From 2f1b1d6d9befa1fff21c79602e1573e820df098b Mon Sep 17 00:00:00 2001 From: Thomas Witkowski <thomas.witkowski@gmx.de> Date: Thu, 17 Dec 2009 14:40:19 +0000 Subject: [PATCH] Added reinit library to AMDiS repository. --- AMDiS/Reinit/Makefile | 44 + AMDiS/Reinit/src/BoundaryElementDist.cc | 59 + AMDiS/Reinit/src/BoundaryElementDist.h | 82 + AMDiS/Reinit/src/BoundaryElementEdgeDist.cc | 55 + AMDiS/Reinit/src/BoundaryElementEdgeDist.h | 37 + .../Reinit/src/BoundaryElementLevelSetDist.cc | 21 + .../Reinit/src/BoundaryElementLevelSetDist.h | 37 + AMDiS/Reinit/src/BoundaryElementNormalDist.cc | 54 + AMDiS/Reinit/src/BoundaryElementNormalDist.h | 47 + AMDiS/Reinit/src/BoundaryElementTopDist.cc | 403 +++++ AMDiS/Reinit/src/BoundaryElementTopDist.h | 83 + AMDiS/Reinit/src/ElementLevelSet.cc | 423 +++++ AMDiS/Reinit/src/ElementLevelSet.h | 497 ++++++ AMDiS/Reinit/src/ElementUpdate.h | 43 + AMDiS/Reinit/src/ElementUpdate_2d.cc | 52 + AMDiS/Reinit/src/ElementUpdate_2d.h | 33 + AMDiS/Reinit/src/ElementUpdate_3d.cc | 609 ++++++++ AMDiS/Reinit/src/ElementUpdate_3d.h | 117 ++ AMDiS/Reinit/src/HL_SignedDist.cc | 375 +++++ AMDiS/Reinit/src/HL_SignedDist.h | 407 +++++ AMDiS/Reinit/src/HL_SignedDistBornemann.h | 916 +++++++++++ AMDiS/Reinit/src/HL_SignedDistLevels.cc | 1360 +++++++++++++++++ AMDiS/Reinit/src/HL_SignedDistLevels.h | 234 +++ AMDiS/Reinit/src/HL_SignedDistTraverse.cc | 275 ++++ AMDiS/Reinit/src/HL_SignedDistTraverse.h | 157 ++ AMDiS/Reinit/src/NormEps.cc | 29 + AMDiS/Reinit/src/NormEps.h | 46 + AMDiS/Reinit/src/VelocityExt.cc | 260 ++++ AMDiS/Reinit/src/VelocityExt.h | 258 ++++ .../src/VelocityExtFromVelocityField.cc | 42 + .../Reinit/src/VelocityExtFromVelocityField.h | 181 +++ 31 files changed, 7236 insertions(+) create mode 100644 AMDiS/Reinit/Makefile create mode 100644 AMDiS/Reinit/src/BoundaryElementDist.cc create mode 100644 AMDiS/Reinit/src/BoundaryElementDist.h create mode 100644 AMDiS/Reinit/src/BoundaryElementEdgeDist.cc create mode 100644 AMDiS/Reinit/src/BoundaryElementEdgeDist.h create mode 100644 AMDiS/Reinit/src/BoundaryElementLevelSetDist.cc create mode 100644 AMDiS/Reinit/src/BoundaryElementLevelSetDist.h create mode 100644 AMDiS/Reinit/src/BoundaryElementNormalDist.cc create mode 100644 AMDiS/Reinit/src/BoundaryElementNormalDist.h create mode 100644 AMDiS/Reinit/src/BoundaryElementTopDist.cc create mode 100644 AMDiS/Reinit/src/BoundaryElementTopDist.h create mode 100644 AMDiS/Reinit/src/ElementLevelSet.cc create mode 100644 AMDiS/Reinit/src/ElementLevelSet.h create mode 100644 AMDiS/Reinit/src/ElementUpdate.h create mode 100644 AMDiS/Reinit/src/ElementUpdate_2d.cc create mode 100644 AMDiS/Reinit/src/ElementUpdate_2d.h create mode 100644 AMDiS/Reinit/src/ElementUpdate_3d.cc create mode 100644 AMDiS/Reinit/src/ElementUpdate_3d.h create mode 100644 AMDiS/Reinit/src/HL_SignedDist.cc create mode 100644 AMDiS/Reinit/src/HL_SignedDist.h create mode 100644 AMDiS/Reinit/src/HL_SignedDistBornemann.h create mode 100644 AMDiS/Reinit/src/HL_SignedDistLevels.cc create mode 100644 AMDiS/Reinit/src/HL_SignedDistLevels.h create mode 100644 AMDiS/Reinit/src/HL_SignedDistTraverse.cc create mode 100644 AMDiS/Reinit/src/HL_SignedDistTraverse.h create mode 100644 AMDiS/Reinit/src/NormEps.cc create mode 100644 AMDiS/Reinit/src/NormEps.h create mode 100644 AMDiS/Reinit/src/VelocityExt.cc create mode 100644 AMDiS/Reinit/src/VelocityExt.h create mode 100644 AMDiS/Reinit/src/VelocityExtFromVelocityField.cc create mode 100644 AMDiS/Reinit/src/VelocityExtFromVelocityField.h diff --git a/AMDiS/Reinit/Makefile b/AMDiS/Reinit/Makefile new file mode 100644 index 00000000..2d71747b --- /dev/null +++ b/AMDiS/Reinit/Makefile @@ -0,0 +1,44 @@ +SHELL = /bin/sh +COMPILE = g++ +DEFS = -DPACKAGE=\"AMDiS\" -DVERSION=\"0.1\" -DHAVE_DLFCN_H=1 +DEBUG = 0 +AMDIS_DIR = ../ + +INCLUDES = -I./src -I$(AMDIS_DIR)/src -I$(AMDIS_DIR)/compositeFEM/src -I$(AMDIS_DIR)/lib/boost_1_34_1 -I$(AMDIS_DIR)/lib/mtl4 + +ifeq ($(strip $(DEBUG)), 0) + CPPFLAGS = -O2 +else + CPPFLAGS = -g -O0 +endif +CPPFLAGS += -ftemplate-depth-30 + +VPATH = .:$(AMDIS_DIR)/Reinit/src + +LIBOFILES = \ +BoundaryElementDist.o \ +BoundaryElementNormalDist.o \ +BoundaryElementLevelSetDist.o \ +BoundaryElementTopDist.o \ +BoundaryElementEdgeDist.o \ +ElementLevelSet.o \ +ElementUpdate_2d.o \ +ElementUpdate_3d.o \ +HL_SignedDist.o \ +HL_SignedDistTraverse.o \ +VelocityExt.o \ +VelocityExtFromVelocityField.o \ +NormEps.o + +all: libreinit.a + +# statische Bibliothek +libreinit.a: $(LIBOFILES) + rm -f lib/libreinit.a + ar cq lib/libreinit.a $(LIBOFILES) + +.cc.o: $*.cc + $(COMPILE) $(DEFS) $(INCLUDES) $(CPPFLAGS) -c -o $*.o $< + +clean: + -rm -rf *.o diff --git a/AMDiS/Reinit/src/BoundaryElementDist.cc b/AMDiS/Reinit/src/BoundaryElementDist.cc new file mode 100644 index 00000000..b3a4adde --- /dev/null +++ b/AMDiS/Reinit/src/BoundaryElementDist.cc @@ -0,0 +1,59 @@ +#include "BoundaryElementDist.h" + +void +BoundaryElementDist::calcNormal( + const FixVec<WorldVector<double>, DIMEN> &vecs, + WorldVector<double> &normalVec) +{ + FUNCNAME("BoundaryElementDist::calcNormal"); + + switch(dim) { + case 2: calcNormal_2d(vecs, normalVec); + break; + case 3: calcNormal_3d(vecs, normalVec); + break; + default: ERROR_EXIT("illegal dimension !\n"); + } +} + +void +BoundaryElementDist::calcNormal_2d( + const FixVec<WorldVector<double>, DIMEN> &vecs, + WorldVector<double> &normalVec) +{ + FUNCNAME("BoundaryElementDist::calcNormal_2d"); + + TEST_EXIT(vecs.size() == dim)("illegal number of world vectors in vecs !\n"); + + double norm2 = 0.0; + double val; + for (int i=0; i<dim; ++i){ + val = vecs[0][i] - vecs[1][i]; + norm2 += val*val; + normalVec[dim-1-i] = val; + } + normalVec[0] *= -1; + double norm = sqrt(norm2); + for(int i=0; i<dim; ++i) { + normalVec[i] = 1/norm * normalVec[i]; + } +} + +void +BoundaryElementDist::calcNormal_3d( + const FixVec<WorldVector<double>, DIMEN> &vecs, + WorldVector<double> &normalVec) +{ + FUNCNAME("BoundaryElementDist::calcNormal_3d"); + + TEST_EXIT(vecs.size() == dim)("illegal number of world vectors in vecs !\n"); + + WorldVector<double> A = vecs[1]-vecs[0]; + WorldVector<double> B = vecs[2]-vecs[0]; + vectorProduct(A, B, normalVec); + + double norm = sqrt(normalVec * normalVec); + for(int i=0; i<dim; ++i) { + normalVec[i] = 1/norm * normalVec[i]; + } +} diff --git a/AMDiS/Reinit/src/BoundaryElementDist.h b/AMDiS/Reinit/src/BoundaryElementDist.h new file mode 100644 index 00000000..5088edfd --- /dev/null +++ b/AMDiS/Reinit/src/BoundaryElementDist.h @@ -0,0 +1,82 @@ +#ifndef BOUNDARYELEMENTDIST_H +#define BOUNDARYELEMENTDIST_H + +#include "ElInfo.h" +#include "FixVec.h" + +#include "ElementLevelSet.h" + +using namespace AMDiS; + +class BoundaryElementDist { + public: + MEMORY_MANAGED(BoundaryElementDist); + + /** + * Constructor. + */ + BoundaryElementDist(ElementLevelSet *elLS_, int dim_) + : dim(dim_), + elLS(elLS_) + { + FUNCNAME("BoundaryElementDist::BoundaryElementDist()"); + + TEST_EXIT(dim == 2 || dim == 3) + ("function only works for dimension 2 !\n"); + }; + + /** + * Virtual destructor. + */ + virtual ~BoundaryElementDist() {}; + + /** + * Calculates distance from the interface for all vertices of a boundary + * element. + * + * Pure virtual: Realizations in + * BoundaryElementLevelSetDist - boundary value initialization + * by level set function + * BoundaryElementTopDist - topological distance + * (distance within element) + * BoundaryElementEdgeDist - distance along edges + * BoundaryElementNormalDist - normal distance to + * intersection plane + */ + virtual int calcDistOnBoundaryElement(ElInfo *elInfo, + FixVec<double, VERTEX> &dVec) = 0; + + protected: + /** + * Calculate the (unit) normal for the plane defined by the world vectors in + * vecs. + */ + void calcNormal(const FixVec<WorldVector<double>, DIMEN> &vecs, + WorldVector<double> &normalVec); + + /** + * Normal calculation: 2-dimensional case. + */ + void calcNormal_2d(const FixVec<WorldVector<double>, DIMEN> &vecs, + WorldVector<double> &normalVec); + + /** + * Normal calculation: 3-dimensional case. + */ + void calcNormal_3d(const FixVec<WorldVector<double>, DIMEN> &vecs, + WorldVector<double> &normalVec); + + protected: + /** + * Dimension. + */ + int dim; + + /** + * Holds level set function and functionalities for intersection point + * calculation. + */ + ElementLevelSet *elLS; +}; + +#endif // BOUNDARYELEMENTDIST_H diff --git a/AMDiS/Reinit/src/BoundaryElementEdgeDist.cc b/AMDiS/Reinit/src/BoundaryElementEdgeDist.cc new file mode 100644 index 00000000..73d76a5d --- /dev/null +++ b/AMDiS/Reinit/src/BoundaryElementEdgeDist.cc @@ -0,0 +1,55 @@ +#include "BoundaryElementEdgeDist.h" + +int +BoundaryElementEdgeDist::calcDistOnBoundaryElement( + ElInfo *elInfo, + FixVec<double, VERTEX> &dVec) +{ + WorldVector<double> vert1, vert2; + int vert1Ind, vert2Ind; + double length; + double val; + + + // Get intersection information. + int elStatus = elLS->createElementLevelSet(elInfo); + if (elStatus != ElementLevelSet::LEVEL_SET_BOUNDARY) + return elStatus; + + VectorOfFixVecs<DimVec<double> > *elIntersecPoints = + elLS->getElIntersecPoints(); + int numIntersecPoints = elLS->getNumElIntersecPoints(); + + // For all vertices: calculate distance to intersection points. + for (int i = 0; i < numIntersecPoints; ++i) { + vert1Ind = -1; + vert2Ind = -1; + length = 0; + + // Get vertices on edge with intersection point. + for (int j=0; j<=dim; ++j) { + if ((*elIntersecPoints)[i][j] > 1.e-15) { + if (vert1Ind == -1) vert1Ind = j; + else { + vert2Ind = j; + break; + } + } + } + + // Get length of edge with intersection point. + vert1 = elInfo->getCoord(vert1Ind); + vert2 = elInfo->getCoord(vert2Ind); + for (int j=0; j<dim; ++j) { + length += (vert1[j] - vert2[j])*(vert1[j]-vert2[j]); + } + length = sqrt(length); + + // Get distance of vert1 and vert2 to intersection point. + val = (*elIntersecPoints)[i][vert2Ind] * length; + dVec[vert1Ind] = val; + dVec[vert2Ind] = length - val; + } + + return elStatus; +} diff --git a/AMDiS/Reinit/src/BoundaryElementEdgeDist.h b/AMDiS/Reinit/src/BoundaryElementEdgeDist.h new file mode 100644 index 00000000..579fa634 --- /dev/null +++ b/AMDiS/Reinit/src/BoundaryElementEdgeDist.h @@ -0,0 +1,37 @@ +#ifndef BOUNDARYELEMENTEDGEDIST_H +#define BOUNDARYELEMENTEDGEDIST_H + +#include "ElInfo.h" +#include "FixVec.h" + +#include "ElementLevelSet.h" + +#include "BoundaryElementDist.h" + +using namespace AMDiS; + +class BoundaryElementEdgeDist : public BoundaryElementDist +{ + public: + MEMORY_MANAGED(BoundaryElementEdgeDist); + + /** + * Constructor. + */ + BoundaryElementEdgeDist(ElementLevelSet *elLS_, + int dim_) + : BoundaryElementDist(elLS_, dim_) + {}; + + /** + * Calculates distance from the interface for all vertices of a boundary + * element. + * Distance is here the distance along edges. + * + * Return value: Status of element elInfo. + */ + int calcDistOnBoundaryElement(ElInfo *elInfo, + FixVec<double, VERTEX> &dVec); +}; + +#endif // BOUNDARYELEMENTEDGEDIST_H diff --git a/AMDiS/Reinit/src/BoundaryElementLevelSetDist.cc b/AMDiS/Reinit/src/BoundaryElementLevelSetDist.cc new file mode 100644 index 00000000..69ad306e --- /dev/null +++ b/AMDiS/Reinit/src/BoundaryElementLevelSetDist.cc @@ -0,0 +1,21 @@ +#include "BoundaryElementLevelSetDist.h" + +int +BoundaryElementLevelSetDist::calcDistOnBoundaryElement( + ElInfo *elInfo, + FixVec<double, VERTEX> &dVec) +{ + // Get intersection information. + int elStatus = elLS->createElementLevelSet(elInfo); + if (elStatus != ElementLevelSet::LEVEL_SET_BOUNDARY) + return elStatus; + + const double *elVertLevelSetVec = elLS->getElVertLevelSetVec(); + + // Set distance to values of level set function in element vertices. + for (int i=0; i<=dim; ++i) { + dVec[i] = fabs(elVertLevelSetVec[i]); + } + + return elStatus; +} diff --git a/AMDiS/Reinit/src/BoundaryElementLevelSetDist.h b/AMDiS/Reinit/src/BoundaryElementLevelSetDist.h new file mode 100644 index 00000000..f639e207 --- /dev/null +++ b/AMDiS/Reinit/src/BoundaryElementLevelSetDist.h @@ -0,0 +1,37 @@ +#ifndef BOUNDARYELEMENTLEVELSETDIST_H +#define BOUNDARYELEMENTLEVELSETDIST_H + +#include "ElInfo.h" +#include "FixVec.h" + +#include "ElementLevelSet.h" + +#include "BoundaryElementDist.h" + +using namespace AMDiS; + +class BoundaryElementLevelSetDist : public BoundaryElementDist +{ + public: + MEMORY_MANAGED(BoundaryElementLevelSetDist); + + /** + * Constructor. + */ + BoundaryElementLevelSetDist(ElementLevelSet *elLS_, int dim_) + : BoundaryElementDist(elLS_, dim_) + {}; + + /** + * Calculates distance from the interface for all vertices of a boundary + * element. + * Distance is here the value of the level set function at boundary + * vertices.. + * + * Return value: Status of element elInfo. + */ + int calcDistOnBoundaryElement(ElInfo *elInfo, + FixVec<double, VERTEX> &dVec); +}; + +#endif // BOUNDARYELEMENTLEVELSETDIST_H diff --git a/AMDiS/Reinit/src/BoundaryElementNormalDist.cc b/AMDiS/Reinit/src/BoundaryElementNormalDist.cc new file mode 100644 index 00000000..c14f5b93 --- /dev/null +++ b/AMDiS/Reinit/src/BoundaryElementNormalDist.cc @@ -0,0 +1,54 @@ +#include "BoundaryElementNormalDist.h" + +int +BoundaryElementNormalDist::calcDistOnBoundaryElement( + ElInfo *elInfo, + FixVec<double, VERTEX> &dVec) +{ + + // Get intersection information. + int elStatus = elLS->createElementLevelSet(elInfo); + if (elStatus != ElementLevelSet::LEVEL_SET_BOUNDARY) + return elStatus; + + VectorOfFixVecs<DimVec<double> > *elIntersecPoints = + elLS->getElIntersecPoints(); + + // Calculate (unit) normal to intersection plane. + FixVec<WorldVector<double>, DIMEN> planeVecs(dim, NO_INIT); + WorldVector<double> normalVec; + for (int i=0; i<dim; ++i) { + elInfo->coordToWorld((*elIntersecPoints)[i], (planeVecs[i])); + } + calcNormal(planeVecs, normalVec); + + // Calculate normal distance for all vertices. + for (int i=0; i<=dim; ++i) { + + dVec[i] = calculateDistLevelSetWithNormal(elInfo, + i, + normalVec, + planeVecs[0]); + } + + return elStatus; +} + +double +BoundaryElementNormalDist::calculateDistLevelSetWithNormal( + ElInfo *elInfo, + int vert, + WorldVector<double> &normalVec, + WorldVector<double> &planeVec) +{ + // Get world coordinates of vertex. + const WorldVector<double> &vertex = elInfo->getCoord(vert); + + // Calculate distance. + double dist = 0.0; + for (int i=0; i<dim; ++i) { + dist += (vertex[i]-planeVec[i]) * normalVec[i]; + } + + return fabs(dist); +} diff --git a/AMDiS/Reinit/src/BoundaryElementNormalDist.h b/AMDiS/Reinit/src/BoundaryElementNormalDist.h new file mode 100644 index 00000000..a74c2725 --- /dev/null +++ b/AMDiS/Reinit/src/BoundaryElementNormalDist.h @@ -0,0 +1,47 @@ +#ifndef BOUNDARYELEMENTNORMALDIST_H +#define BOUNDARYELEMENTNORMALDIST_H + +#include "ElInfo.h" +#include "FixVec.h" + +#include "ElementLevelSet.h" + +#include "BoundaryElementDist.h" + +using namespace AMDiS; + +class BoundaryElementNormalDist : public BoundaryElementDist +{ + public: + MEMORY_MANAGED(BoundaryElementNormalDist); + + /** + * Constructor. + */ + BoundaryElementNormalDist(ElementLevelSet *elLS_, int dim_) + : BoundaryElementDist(elLS_, dim_) + {}; + + /** + * Calculates distance from the interface for all vertices of a boundary + * element. + * Distance is here the normal distance. + * + * Return value: Status of element elInfo. + */ + int calcDistOnBoundaryElement(ElInfo *elInfo, + FixVec<double, VERTEX> &dVec); + + protected: + /** + * Calculates the distance of vertex vert in element elInfo + * from the plane given by the normal vector of the plane normalVec + * and one point lying in the plane planeVec. + */ + double calculateDistLevelSetWithNormal(ElInfo *elInfo, + int vert, + WorldVector<double> &normalVec, + WorldVector<double> &planeVec); +}; + +#endif // BOUNDARYELEMENTNORMALDIST_H diff --git a/AMDiS/Reinit/src/BoundaryElementTopDist.cc b/AMDiS/Reinit/src/BoundaryElementTopDist.cc new file mode 100644 index 00000000..367337fc --- /dev/null +++ b/AMDiS/Reinit/src/BoundaryElementTopDist.cc @@ -0,0 +1,403 @@ +#include "BoundaryElementTopDist.h" + +int +BoundaryElementTopDist::calcDistOnBoundaryElement( + ElInfo *elInfo, + FixVec<double, VERTEX> &dVec) +{ + //Cartesian coordinates of the 3 or 4 vertices of a simplex + FixVec<WorldVector<double>,VERTEX> Vert(dim, NO_INIT); + //normal unit vector in Cartesian coordinates + WorldVector<double> normalVec; + //Cartesian coordinates of dim intersection points + FixVec<WorldVector<double>,DIMEN> planeVecs_DIMEN(dim, NO_INIT); + //Cartesian coordinates of 3 or 4 intersection points (3d) + FixVec<WorldVector<double>,VERTEX> planeVecs(dim, NO_INIT); + //barycentric coordinates of the intersection point + //(straight line - normal) + DimVec<double> SP_Vec(dim, NO_INIT); + //Cartesian coordinates of SP_Vec + WorldVector<double> SP; + + double lambda; + double h_dist = 0.0; + double h_dist2 = 0.0; + double dist = 0.0; + + // for VelocityExt + int edgeUpdateInd = -1; + int sP1NextEdge = -1; + int sP2NextEdge = -1; + double lambdaNextPt = 0.0; + + // Get intersection information. + int elStatus = elLS->createElementLevelSet(elInfo); + if (elStatus != ElementLevelSet::LEVEL_SET_BOUNDARY) + return elStatus; + + //bar. coordinates of the intersection points + VectorOfFixVecs<DimVec<double> > *elIntersecPoints = + elLS->getElIntersecPoints(); + + //Cartesian coordinates of the vertices + for( int i=0; i<=dim; i++) + { + Vert[i] = elInfo->getCoord(i); + } + + //Cartesian coordinates of the intersection point + //attention: in 3d it is possible that there are 4 intersection + //points, but her we save only 3 of them + for(int i=0; i<dim/*ElementLevelSet::getNumElIntersecPoints()*/; i++) + { + elInfo->coordToWorld((*elIntersecPoints)[i], (planeVecs_DIMEN[i])); + } + + //calculating of the normal unit vector + calcNormal(planeVecs_DIMEN, normalVec); + + //2D or 3D + if( dim == 2) + { + //loop over all vertices + for(int i=0; i<=dim; i++) + { + //Cartesian coordinates of the intersection point + //(straight line- normal) + h_dist = 0.0; + for (int j=0; j<dim; ++j) + { + h_dist += (Vert[i][j]-planeVecs_DIMEN[0][j]) * normalVec[j]; + } + SP[0]=Vert[i][0]-h_dist*normalVec[0]; + SP[1]=Vert[i][1]-h_dist*normalVec[1]; + + //barycentric coordinates of the intersection point + elInfo->worldToCoord(SP, &SP_Vec); + + //calculating of the distance + //intersection point inside of the 2d-simplex? + if(SP_Vec[0]>=0 && SP_Vec[1]>=0 && SP_Vec[2]>=0) + { + dist = fabs(h_dist); + dVec[i] = dist; + //save barycentric coordinates of intersection point, + //for calculation of the velocity + if(velExt != NULL) + { + velExt->setBarycentricCoords_2D_boundary(SP_Vec[0], SP_Vec[1], SP_Vec[2], i); + } + } + //dist = min of the distance to the two intersection points + else + { + for (int j=0; j<elLS->getNumElIntersecPoints(); j++) + { + h_dist = 0.0; + for(int k=0; k<dim; k++) + { + h_dist += (Vert[i][k]-planeVecs_DIMEN[j][k])* + (Vert[i][k]-planeVecs_DIMEN[j][k]); + } + if (j == 0) + { + h_dist2 = h_dist; + + // Store index of intersection point which is next + // point on interface. + edgeUpdateInd = j; + } + else if (h_dist < h_dist2) + { + h_dist2 = h_dist; + + // Store index of intersection point which is next + // point on interface. + edgeUpdateInd = j; + } + } + dist = sqrt(h_dist2); + dVec[i] = dist; + //save barycentric coordinates of intersection point, + //for calculation of the velocity + if(velExt != NULL) + { + velExt->setBarycentricCoords_2D_boundary( + (*elIntersecPoints)[edgeUpdateInd][0], + (*elIntersecPoints)[edgeUpdateInd][1], + (*elIntersecPoints)[edgeUpdateInd][2], + i); + } + }//end of the else-part according to "if(!normalDistCalc)" + }//end of the loop over all vertices + }//end of the 2d-case + + else //dim ==3 + { + //Cartesian coordinates of the intersection point + //attention: in 3d it is possible that there are 4 intersection + //points, here we save them all + for(int i=0; i<elLS->getNumElIntersecPoints(); i++) + { + elInfo->coordToWorld((*elIntersecPoints)[i], (planeVecs[i])); + } + + //loop over all 4 vertices + for ( int i=0; i<=dim; i++) + { + h_dist = 0.0; + + //intersection point of the normal with the intersection plane + for ( int j = 0; j<dim; j++) + { + h_dist+=(Vert[i][j]-planeVecs[0][j])*normalVec[j]; + } + for ( int j=0; j<dim; j++) + { + SP[j]=Vert[i][j]-h_dist*normalVec[j]; + } + + //barycentric coordinates of the intersection point + elInfo->worldToCoord(SP, &SP_Vec); + + //intersection point inside of the 3d-simplex + //distance calculated with the unit normal vector of the + //intersection plane + if (SP_Vec[0]>=0 && SP_Vec[1]>=0 && SP_Vec[2]>=0 && SP_Vec[3]>=0) + { + dist = fabs(h_dist); + dVec[i] = dist; + //save barycentric coordinates of intersection point, + //for calculation of the velocity + if(velExt != NULL) + { + velExt->setBarycentricCoords_3D_boundary(SP_Vec[0], SP_Vec[1], SP_Vec[2], SP_Vec[3], i); + } + } + //dist = min of the distances to the cutting straight lines at + //the sides of the simplex + else if(elLS->getNumElIntersecPoints() == 3) + { + dist = 1.e15; + for (int j=0; j<dim; j++) + { + h_dist = calcDistOnIntersecEdge(planeVecs[j], + planeVecs[(j+1)%3], + Vert[i], + lambda); + // dist = (dist < h_dist) ? dist : h_dist; + if(h_dist<dist) + { + dist = h_dist; + if (velExt != NULL) + { + sP1NextEdge = j; + sP2NextEdge = (j+1)%3; + lambdaNextPt = lambda; + } + } + // if (velExt != NULL) { +// sP1NextEdge = j; +// sP2NextEdge = (j+1)%3; +// lambdaNextPt = lambda; + + } + dVec[i] = dist; + //save barycentric coordinates of intersection point, + //for calculation of the velocity + if(velExt != NULL) + { + velExt->calcBarycentricCoords_3D_boundary( + (*elIntersecPoints)[sP1NextEdge], + (*elIntersecPoints)[sP2NextEdge], + lambdaNextPt, + i); + } + } + else if(elLS->getNumElIntersecPoints() == 4) + { + dist = 1.e15; + for (int j=0; j<=1; j++) + { + h_dist = calcDistOnIntersecEdge(planeVecs[j], + planeVecs[(j+2)%3], + Vert[i], + lambda); + // dist = (dist < h_dist) ? dist : h_dist; + +// if (velExt != NULL) { +// sP1NextEdge = j; +// sP2NextEdge = (j+2)%3; +// lambdaNextPt = lambda; +// } + if(h_dist<dist) + { + dist = h_dist; + if (velExt != NULL) + { + sP1NextEdge = j; + sP2NextEdge = (j+2)%3; + lambdaNextPt = lambda; + } + } + } + + h_dist = calcDistOnIntersecEdge(planeVecs[1], + planeVecs[2], + Vert[i], + lambda); + // dist = (dist < h_dist) ? dist : h_dist; + +// if (velExt != NULL) { +// sP1NextEdge = 1; +// sP2NextEdge = 2; +// lambdaNextPt = lambda; +// } + if(h_dist<dist) + { + dist = h_dist; + if (velExt != NULL) + { + sP1NextEdge = 1; + sP2NextEdge = 2; + lambdaNextPt = lambda; + } + } + + h_dist = calcDistOnIntersecEdge(planeVecs[0], + planeVecs[3], + Vert[i], + lambda); + // dist = (dist < h_dist) ? dist : h_dist; + +// if (velExt != NULL) { +// sP1NextEdge = 0; +// sP2NextEdge = 3; +// lambdaNextPt = lambda; +// } + if(h_dist<dist) + { + dist = h_dist; + if (velExt != NULL) + { + sP1NextEdge = 0; + sP2NextEdge = 3; + lambdaNextPt = lambda; + } + } + + dVec[i] = dist; + //save barycentric coordinates of intersection point, + //for calculation of the velocity + if(velExt != NULL) + { + velExt->calcBarycentricCoords_3D_boundary( + (*elIntersecPoints)[sP1NextEdge], + (*elIntersecPoints)[sP2NextEdge], + lambdaNextPt, + i); + } + } + }//end of the loop over all 4 vertices + }//end of the else-part according to "if( dim == 2)" + + return elStatus; +} + +double +BoundaryElementTopDist::calcDistOnIntersecEdge( + const WorldVector<double> &sP1, + const WorldVector<double> &sP2, + const WorldVector<double> &v, + double &lambda) +{ + WorldVector<double> SP_projected; + double dist = 0.0; + + // Calculate projection of v on straight line through sP1 and sP2. + projected_on_a_straight_line(sP1, sP2, v, SP_projected, lambda); + + // Get distance and next point on interface (implicitly: lambda). + cases_for_lambda(v, SP_projected, sP1, sP2, lambda, dist); + + return dist; +} + +double +BoundaryElementTopDist::calc_dist_between_two_points ( + const WorldVector<double> &point1, + const WorldVector<double> &point2) +{ + double h_dist = 0.0; + + for(int i=0; i<dim; i++) + { + h_dist += (point1[i] - point2[i])*(point1[i] - point2[i]); + } + h_dist = sqrt(h_dist); + + return h_dist; +} + +void +BoundaryElementTopDist::cases_for_lambda( + const WorldVector<double> &SP, + const WorldVector<double> &SP_projected, + const WorldVector<double> &point1, + const WorldVector<double> &point2, + double &lambda, + double &dist) +{ + if(0 <= lambda && lambda <= 1) + { + dist = calc_dist_between_two_points(SP, SP_projected); + } + if(lambda < 0.0) + { + lambda = 0; + dist = calc_dist_between_two_points(SP, point1); + } + if(1.0 < lambda) + { + lambda = 1; + dist = calc_dist_between_two_points(SP, point2); + } +} + +void +BoundaryElementTopDist::projected_on_a_straight_line( + const WorldVector<double> &sP1, + const WorldVector<double> &sP2, + const WorldVector<double> &v, + WorldVector<double> &v_p, + double &lambda) + // lambda < 0: v_p---sP1---sP2 + // 0<lambda<1: sP1---v_p---sP2 + // 1 < lambda: sP1---sP2---v_p +{ + lambda = 0.0; + WorldVector<double> sP1_sP2; + WorldVector<double> sP1_v; + double norm_sP1_sP2 = 0.0; + + for (int i=0; i<dim; ++i) { + sP1_sP2[i]=sP2[i]-sP1[i]; + } + for (int i=0; i<dim; ++i) { + sP1_v[i]=v[i]-sP1[i]; + } + for (int i=0; i<dim; ++i) { + norm_sP1_sP2 += sP1_sP2[i]*sP1_sP2[i]; + } + // norm_sP1_sP2 = sqrt(norm_sP1_sP2); + + for (int i=0; i<dim; ++i) { + lambda += sP1_v[i]*sP1_sP2[i]; + } + lambda = lambda / norm_sP1_sP2; + + for (int i=0; i<dim; i++) + { + v_p[i] = sP1[i] + lambda * sP1_sP2[i]; + } +} diff --git a/AMDiS/Reinit/src/BoundaryElementTopDist.h b/AMDiS/Reinit/src/BoundaryElementTopDist.h new file mode 100644 index 00000000..0adfb23b --- /dev/null +++ b/AMDiS/Reinit/src/BoundaryElementTopDist.h @@ -0,0 +1,83 @@ +#ifndef BOUNDARYELEMENTTOPDIST_H +#define BOUNDARYELEMENTTOPDIST_H + +#include "ElInfo.h" +#include "FixVec.h" + +#include "ElementLevelSet.h" + +#include "BoundaryElementDist.h" +#include "VelocityExt.h" + +using namespace AMDiS; + +class BoundaryElementTopDist : public BoundaryElementDist +{ + public: + MEMORY_MANAGED(BoundaryElementTopDist); + + /** + * Constructor. + */ + BoundaryElementTopDist(ElementLevelSet *elLS_, + int dim_, + VelocityExt *velExt_ = NULL) + : BoundaryElementDist(elLS_, dim_), + velExt(velExt_) + {}; + + /** + * Destructor. + */ + ~BoundaryElementTopDist() + {}; + + /** + * Calculates distance from the interface for all vertices of a boundary + * element. + * Distance is here the topological distance. + * + * Return value: Status of element elInfo. + */ + int calcDistOnBoundaryElement(ElInfo *elInfo, + FixVec<double, VERTEX> &dVec); + + protected: + /** + * Calculates distance of vertex v to intersection edge through + * sP1 and sP2 within element. + * lambda implicitly gives the next point on the intersection edge. + */ + double calcDistOnIntersecEdge(const WorldVector<double> &sP1, + const WorldVector<double> &sP2, + const WorldVector<double> &v, + double &lambda); + + //calculates the distance between two points + double calc_dist_between_two_points( + const WorldVector<double> &point1, + const WorldVector<double> &point2); + + void cases_for_lambda(const WorldVector<double> &SP, + const WorldVector<double> &SP_projected, + const WorldVector<double> &point1, + const WorldVector<double> &point2, + double &lambda, + double &dist); + + //calculates the projection of the point "v" onto a straight line + //given by two points "sP1" nad "sP2" + void projected_on_a_straight_line(const WorldVector<double> &sP1, + const WorldVector<double> &sP2, + const WorldVector<double> &v, + WorldVector<double> &v_p, + double &lambda_out ); + + protected: + /** + * Object needed to extrapolate velocity from the interface. + */ + VelocityExt *velExt; + }; + +#endif // BOUNDARYELEMENTTOPDIST_H diff --git a/AMDiS/Reinit/src/ElementLevelSet.cc b/AMDiS/Reinit/src/ElementLevelSet.cc new file mode 100644 index 00000000..5ef6b076 --- /dev/null +++ b/AMDiS/Reinit/src/ElementLevelSet.cc @@ -0,0 +1,423 @@ +#include "ElementLevelSet.h" +#include "ElInfo.h" + +int +ElementLevelSet::createElementLevelSet(const ElInfo *elInfo_, + const bool doCalcIntersecPts_) +{ + Element *el = elInfo_->getElement(); + + if (elInfo == NULL || el != lastEl) { + /** + * Element has changed. New calculation. + */ + + // Set new element. + lastEl = el; + + // Set information for element and reset data. + setElement(elInfo_); + + // Calculate level set function values for each vertex of element. + calculateElementLevelSetVal(); + + // Check whether level set function values are not too small. + checkElementLevelSetVal(); + + // Calculate status of element and element vertices. + calculateElementStatus(); + + // Calculate intersection points with zero level set if necessary. + if (doCalcIntersecPts_ && elStatus == LEVEL_SET_BOUNDARY) { + calculateIntersecPoints(); + + // dim == 3: sort intersection points if necessary + if (dim == 3 && numIntersecPoints == 4) + sortIntersecPoints_4IP3D(); + } + } + +// else { + /** + * LevelSet-Status for element has already been calculated. + */ +// } + + return elStatus; +} + +void +ElementLevelSet::calculateElementLevelSetVal() +{ + DimVec<double> lambda(dim, DEFAULT_VALUE, 0.0); + + for (int i = 0; i <= dim; i++) { + + lambda[i] = 1.0; + lSFct->setElInfo(elInfo); + elVertexLevelSetVec[i] = (*lSFct)((const DimVec<double>) lambda); + lambda[i] = 0.0; + } +} + +int +ElementLevelSet::calculateElementStatus() +{ + for (int i=0; i<=dim; ++i) { + if (elVertexLevelSetVec[i] < 0) { + elVertexStatusVec[i] = LEVEL_SET_INTERIOR; + numElVertexInterior++; + } + else { + elVertexStatusVec[i] = LEVEL_SET_EXTERIOR; + numElVertexExterior++; + } + } + + /** + * Calculate level set status of element. + */ + if (numElVertexInterior == dim+1) { + elStatus = LEVEL_SET_INTERIOR; + return LEVEL_SET_INTERIOR; + } + if (numElVertexExterior == dim+1) { + elStatus = LEVEL_SET_EXTERIOR; + return LEVEL_SET_EXTERIOR; + } + elStatus = LEVEL_SET_BOUNDARY; + return LEVEL_SET_BOUNDARY; +} + +void +ElementLevelSet::calculateIntersecPoints() +{ + //************************************************************************** + // The level set function is linearly approximated by a hyperplane through + // the points of the graph of the level set function in the vertices + // of the element. + // This routine calculates the intersection points of the hyperplane + // with the edges of the element. + //************************************************************************** + DimVec<double> tempPoint(dim); + DimVec<double> zeroVec(dim, DEFAULT_VALUE, 0.0); + int i, j; + + /** + * Get intersection points (in barycentric coordinates). + * + * An edge is intersected if its vertices have level sets with + * different sign. + */ + for (i = 0; i <= dim; i++) { + for (j = i+1; j <= dim; j++) { + + if (elVertexStatusVec[i] * elVertexStatusVec[j] < 0.0) { + + tempPoint = zeroVec; + tempPoint[j] = elVertexLevelSetVec[i] / + (elVertexLevelSetVec[i] - elVertexLevelSetVec[j]); + checkIntersecBary(tempPoint[j]); + tempPoint[i] = 1 - tempPoint[j]; + + (*elIntersecPoints)[numIntersecPoints] = tempPoint; + ++numIntersecPoints; + } + + } // for(j ... + } // for(i ... +} + +int +ElementLevelSet::checkElementLevelSetVal() +{ + int changed = 0; + double abs_grd_val = 0.0; + double abs_min_val = 0.0; + double comp = 0.0; + + for (int i=0; i<dim; ++i) { + comp = elVertexLevelSetVec[i]-elVertexLevelSetVec[dim]; + abs_grd_val += comp*comp; + } + abs_grd_val = sqrt(abs_grd_val); + + abs_min_val = LS_VAL_TOL*abs_grd_val; + abs_min_val = (abs_min_val > LS_VAL_MIN) ? abs_min_val : LS_VAL_MIN; + + for (int i=0; i<=dim; ++i) { + if (fabs(elVertexLevelSetVec[i]) < abs_min_val) { +// elVertexLevelSetVec[i] = abs_min_val; + elVertexLevelSetVec[i] = (elVertexLevelSetVec[i] < 0) ? + -abs_min_val : abs_min_val; + ++changed; + } + } + + return changed; +} + +bool +ElementLevelSet::checkIntersecBary(double &bary) +{ + if (bary < SP_BARY_TOL) { + bary = SP_BARY_TOL; + return true; + } + if (bary > 1-SP_BARY_TOL) { + bary = 1-SP_BARY_TOL; + return true; + } + + return false; +} + +void +ElementLevelSet::sortIntersecPoints_4IP3D() +{ + FUNCNAME("sortIntersecPoints_4IP3D"); + + int indexFace1 = 0; + int indexFace2 = 0; + int indexOpVert = 0; + DimVec<double> tempPoint(dim); + int i,j; + + /** + * Consider the 4 intersection points S0, S1, S2 and S3. If the components + * of S0 indexFace1 and indexFace2 are not zero, i.e. S0 lies in + * the element faces indexFace1 and indexFace2, the intersection + * point with zero components indexFace1 and indexFace2 is + * opposite to S0 in the intersection plane. Move this vertex to the end + * of the intersection point list elIntersecPoints. + */ + + // Get indexFace1 and indexFace2. + for (i = 0; i < numIntersecPoints; i++) { + if (fabs((*elIntersecPoints)[0][i]) > 1.e-15) { + indexFace1 = i; + break; + } + } + for (j = i+1; j < numIntersecPoints; j++) { + if (fabs((*elIntersecPoints)[0][j]) > 1.e-15) { + indexFace2 = j; + break; + } + } + + // Get index of vertex opposite to S0. + for (i = 1; i < numIntersecPoints; i++) { + if (fabs((*elIntersecPoints)[i][indexFace1]) <= 1.e-15 && + fabs((*elIntersecPoints)[i][indexFace2]) <= 1.e-15) { + indexOpVert = i; + break; + } + } + + // Move vertex to the end of \ref elIntersecPoints. + if (indexOpVert != numIntersecPoints-1) { + tempPoint = (*elIntersecPoints)[indexOpVert]; + (*elIntersecPoints)[indexOpVert] = (*elIntersecPoints)[numIntersecPoints-1]; + (*elIntersecPoints)[numIntersecPoints-1] = tempPoint; + } + + return; +} + +void +ElementLevelSet::calcIntersecNormal(WorldVector<double> &normalVec) +{ + FUNCNAME("ElementLevelSet::calcIntersecNormal"); + + switch(dim) { + case 2: calcIntersecNormal_2d(normalVec); + break; + case 3: calcIntersecNormal_3d(normalVec); + break; + default: ERROR_EXIT("illegal dimension !\n"); + } +}; + +void +ElementLevelSet::calcIntersecNormal_2d(WorldVector<double> &normalVec) +{ + FUNCNAME("ElementLevelSet::calcIntersecNormal_2d"); + + TEST_EXIT(numIntersecPoints == 2)("illegal number of intersection points !\n"); + + // ===== Get world coordinates of intersection points. ===== + WorldVector<double> sP1; + WorldVector<double> sP2; + elInfo->coordToWorld((*elIntersecPoints)[0], sP1); + elInfo->coordToWorld((*elIntersecPoints)[1], sP2); + + // ===== Calculate normal vector. ===== + double norm2 = 0.0; + double val; + for (int i=0; i<dim; ++i){ + val = sP1[i] - sP2[i]; + norm2 += val*val; + normalVec[dim-1-i] = val; + } + normalVec[0] *= -1; + double norm = sqrt(norm2); + for(int i=0; i<dim; ++i) { + normalVec[i] = 1/norm * normalVec[i]; + } + + // ===== Set correct orientation (exterior normal vector). ===== + + // Calculate barycenter. + WorldVector<double> baryc; + for (int i=0; i<dim; ++i) { + baryc[i] = 0.5*sP1[i] + 0.5*sP2[i]; + } + double d = sqrt((sP1-sP2)*(sP1-sP2)); + + // Barycenter + factor*normalVec. + double elSize = sqrt(fabs(elInfo->getDet())); + double factor = 0.01*d/elSize; + WorldVector<double> tmpPoint; + int cntr = 0; + DimVec<double> lambda(dim, NO_INIT); + + while (1) { + ++cntr; + + for(int i=0; i<dim; ++i) { + tmpPoint[i] = baryc[i] + factor*normalVec[i]; + } + + elInfo->worldToCoord(tmpPoint, &lambda); + for (int i=0; i<=dim; ++i) { + if (lambda[i] < 0) { + factor *= 0.1; + + if (cntr == 10) { + WARNING("inefficient normal vector calculation !\n"); + } + if (cntr == 100) { + ERROR_EXIT("infinite loop !\n"); + } + + continue; + } + } + + break; + } + + if (ElementLevelSet::calcLevelSetFct(lambda) < 0) { + for (int i=0; i<dim; ++i) { + normalVec[i] *= -1; + } + } +}; + +void +ElementLevelSet::calcIntersecNormal_3d(WorldVector<double> &normalVec) +{ + FUNCNAME("ElementLevelSet::calcIntersecNormal_3d"); + + TEST_EXIT(numIntersecPoints == 3 || numIntersecPoints == 4)("illegal number of intersection points !\n"); + + // ===== Get world coordinates of intersection points. ===== + WorldVector<double> sP1; + WorldVector<double> sP2; + WorldVector<double> sP3; + elInfo->coordToWorld((*elIntersecPoints)[0], sP1); + elInfo->coordToWorld((*elIntersecPoints)[1], sP2); + elInfo->coordToWorld((*elIntersecPoints)[2], sP3); + + // ===== Calculate normal vector. ===== + WorldVector<double> A = sP2-sP1; + WorldVector<double> B = sP3-sP1; + vectorProduct(A, B, normalVec); + + double norm = sqrt(normalVec * normalVec); + for(int i=0; i<dim; ++i) { + normalVec[i] = 1/(norm+1.e-4) * normalVec[i]; + } + + // ===== Set correct orientation (exterior normal vector). ===== + + // Calculate barycenter. + WorldVector<double> baryc; + for (int i=0; i<dim; ++i) { + baryc[i] = 1.0/3*sP1[i] + 1.0/3*sP2[i] + 1.0/3*sP3[i]; + } + double d = sqrt((sP1-sP2)*(sP1-sP2)); + + // Barycenter + factor*normalVec. + double elSize = pow(fabs(elInfo->getDet()), 1.0/3); + double factor = 0.01*d/elSize; + WorldVector<double> tmpPoint; + int cntr = 0; + DimVec<double> lambda(dim, NO_INIT); + + while (1) { + ++cntr; + + for(int i=0; i<dim; ++i) { + tmpPoint[i] = baryc[i] + factor*normalVec[i]; + } + + elInfo->worldToCoord(tmpPoint, &lambda); + for (int i=0; i<=dim; ++i) { + if (lambda[i] < 0) { + factor *= 0.1; + + if (cntr == 10) { + WARNING("inefficient normal vector calculation !\n"); + } + if (cntr == 100) { + ERROR_EXIT("infinite loop !\n"); + } + + continue; + } + } + + break; + } + + if (ElementLevelSet::calcLevelSetFct(lambda) < 0) { + for (int i=0; i<dim; ++i) { + normalVec[i] *= -1; + } + } +}; + +int +ElementLevelSet::getVertexPos(const DimVec<double> barCoords) +{ + double vertex_val; + + for (int i=0; i<=dim; ++i) { + if (barCoords[i] > 1-1.e-15) { + vertex_val = elVertexLevelSetVec[i]; + break; + } + } + + if (vertex_val > 0) { + return LEVEL_SET_EXTERIOR; + } + else { + return LEVEL_SET_INTERIOR; + } +} + +int +ElementLevelSet::getElPos(const DimVec<double> barCoords) +{ + double ls_val = calcLevelSetFct(barCoords); + if (ls_val > 0) { + return LEVEL_SET_EXTERIOR; + } + else { + return LEVEL_SET_INTERIOR; + } +} + diff --git a/AMDiS/Reinit/src/ElementLevelSet.h b/AMDiS/Reinit/src/ElementLevelSet.h new file mode 100644 index 00000000..5bcf7964 --- /dev/null +++ b/AMDiS/Reinit/src/ElementLevelSet.h @@ -0,0 +1,497 @@ +#ifndef AMDIS_ELEMENTLEVELSET_H +#define AMDIS_ELEMENTLEVELSET_H + +#include "ElementFunction.h" +#include "FixVec.h" +// #include "MemoryManager.h" +#include "Parameters.h" + +namespace AMDiS { + class Element; + class ElInfo; + class Mesh; +} + +using namespace AMDiS; +using namespace std; + +// =========================================================================== +// ===== class ElementLevelSet =============================================== +// =========================================================================== +// +// Class Description: +// The class ElementLevelSet contains the functionality for +// - calculating the intersection points resulting from an intersection +// of the boundary (level set zero) with an element, +// - calculating the status of an element, i.e. is the element cut +// by the zero level set or not. +// The calculation of the intersection points is done as follows: +// The level set function is linearly approximated on the element, i.e. its +// graph is approximated by the plane through the level set values of the +// element vertices. We approximate the intersection points by the +// intersection of the plane with the element edges. +// If in 3-dimensional finite element space the intersection produced 4 +// intersection points S0, S1, S2, S3, the intersection points in +// elIntersecPoints are rearranged so that S1 and S2 divides the intersection +// plane in two (dim - 1)-dimensional simplices. +// +// Constants indicating the level set status of element: +// LEVEL_SET_INTERIOR - element is in domain where level set function +// is negative +// LEVEL_SET_BOUNDARY - element is in domain where level set function +// is positive +// LEVEL_SET_EXTERIOR - element is cut by the zero level set +// +// Main routines: +// setElementLevelSet() - Defines the level set function for the +// following calculations. +// createElementLevelSet() - Calculates level set status of element and +// intersection points if needed. +// calculateElementLevelSetVal() - Calculates values of the level set +// function in the element vertices. +// setElement() - Sets elInfo. +// getElementLevelSetStatus() - Returns status of element. +// getElementIntersecPoints() - Returns intersection points. +// getElVertStatusVec() - Returns vector with status information +// for each vertex. +// =========================================================================== +class ElementLevelSet +{ + public: + MEMORY_MANAGED(ElementLevelSet); + + /** + * Constructor. + */ + ElementLevelSet(const char *name_, + ElementFunction<double> *lSFct_, + Mesh *mesh_) + : name(name_), + elInfo(NULL), + lastEl(NULL), + level_set_domain(LEVEL_SET_UNDEFINED), + numIntersecPoints(0), + elStatus(LEVEL_SET_UNDEFINED), + numElVertexInterior(0), + numElVertexBoundary(0), + numElVertexExterior(0), + LS_VAL_TOL(1.e-8), + LS_VAL_MIN(1.e-8), + SP_BARY_TOL(1.e-7) + { + FUNCNAME("ElementLevelSet::ElementLevelSet()"); + + TEST_EXIT(lSFct_ || mesh_) + ("illegal initialization of ElementLevelSet!\n"); + + lSFct = lSFct_; + mesh = mesh_; + dim = mesh->getDim(); + + elIntersecPoints = + NEW VectorOfFixVecs<DimVec<double> >(dim, + MAX_INTERSECTION_POINTS, + NO_INIT); + elVertexStatusVec = new int[dim+1]; + elVertexLevelSetVec = new double[dim+1]; + + int setElementLevelSetTol = 0; + GET_PARAMETER(0, name + "->set ElementLevelSet tolerances", "%d", + &setElementLevelSetTol); + if (setElementLevelSetTol) { + + GET_PARAMETER(0, name + "->LS_VAL_TOL", "%f", &LS_VAL_TOL); + GET_PARAMETER(0, name + "->LS_VAL_MIN", "%f", &LS_VAL_MIN); + GET_PARAMETER(0, name + "->SP_BARY_TOL", "%f", &SP_BARY_TOL); + + TEST_EXIT(LS_VAL_TOL > 0)("illegal LS_VAL_TOL\n"); + TEST_EXIT(LS_VAL_MIN > 0)("illegal LS_VAL_MIN\n"); + TEST_EXIT(SP_BARY_TOL > 0)("illegal SP_BARY_TOL\n"); + } + }; + + /** + * Destructor. + */ + ~ElementLevelSet() + { + if (elVertexStatusVec) + delete [] elVertexStatusVec; + if(elVertexLevelSetVec) + delete [] elVertexLevelSetVec; + if (elIntersecPoints) + DELETE elIntersecPoints; + }; + + /** + * Calculates LevelSet-status of element and its intersection points + * with the zero level set if necessary. + * + * Result: + * LEVEL_SET_BOUNDARY: Element elInfo is intersected by levelSetFct. + * LEVEL_SET_EXTERIOR / LEVEL_SET_INTERIOR: Element lies completely on + * one side of the zero level set. + * + * After proceeding this function, information about the level set + * status is given in: + * elStatus: status of element (LEVEL_SET_BOUNDARY, LEVEL_SET_INTERIOR or + * EXTERIOR) + * elVertexStatusVec: stores status of each vertex of element + * elVertexLevelSetVec: stores level set function value of each vertex of + * element + * numElVertexInterior: number of vertices of element with status + * LEVEL_SET_INTERIOR + * numElVertexExterior: number of vertices of element with status + * LEVEL_SET_EXTERIOR + * numElVertexBoundary: number of vertices of element with status + * LEVEL_SET_BOUNDARY + * elIntersecPoints: stores the intersection points produced by the + * intersection of element with the zero level set + * numIntersecPoints: number of intersection points + */ + int createElementLevelSet(const ElInfo *elInfo_, + const bool doCalcIntersecPts_ = true); + + /** + * Gets value of level set function at point given in + * barycentric coordinates. + */ + inline double calcLevelSetFct(const DimVec<double>& bary) { + return (*lSFct)(bary); + }; + + /** + * Resets level set information on element. + */ + inline void resetElement() { + FUNCNAME("ElementLevelSet::resetElement"); + + numElVertexInterior = 0; + numElVertexBoundary = 0; + numElVertexExterior = 0; + numIntersecPoints = 0; + elStatus = LEVEL_SET_UNDEFINED; + }; + + /** + * Defines current element (elInfo). + */ + inline void setElement(const ElInfo *elInfo_) { + elInfo = elInfo_; + resetElement(); + }; + + /** + * Set level_set_domain. + */ + inline void setLevelSetDomain(int status_) { + + TEST_EXIT(status_ == LEVEL_SET_INTERIOR || + status_ == LEVEL_SET_EXTERIOR || + status_ == LEVEL_SET_BOUNDARY)("illegal level set status !\n"); + level_set_domain = status_; + }; + + /** + * Functions to set tolerances for intersection point calculation. + */ + inline void setLsValTol(double tol) {LS_VAL_TOL = tol;}; + inline void setLsValMin(double min) {LS_VAL_MIN = min;}; + inline void setSpBaryTol(double tol) {SP_BARY_TOL = tol;}; + + /** + * Get level_set_domain. + */ + inline const int& getLevelSetDomain() const { + return level_set_domain; + }; + + /** + * Get LevelSet-Status of element. + */ + inline const int& getElementLevelSetStatus() const { + return elStatus; + }; + + /** + * Get number of vertices which are intersection points. + */ + inline const int& getNumVertIntPoints() const { + FUNCNAME("ElementLevelSet::getNumVertIntPoints"); + TEST_EXIT(numElVertexBoundary == 0)("numElVertexBoundary should be zero!\n"); + return numElVertexBoundary; + }; + + /** + * Get vector elVertexStatusVec. + */ + inline const int *getElVertStatusVec() const { + return elVertexStatusVec; + }; + + /** + * Get i-th component of vector elVertexLevelSetVec. + */ + inline const double getElVertLevelSetVec(const int i) const { + return elVertexLevelSetVec[i]; + }; + + /** + * Get vector elVertexLevelSetVec. + */ + inline const double *getElVertLevelSetVec() const { + return elVertexLevelSetVec; + }; + + /** + * Get levelSetFct. + */ + inline ElementFunction<double> *getLevelSetFct() const { + return lSFct; + }; + + /** + * Get mesh. + */ + inline Mesh *getMesh() const { + return mesh; + }; + + /** + * Get dim. + */ + inline int getDim() const { + return dim; + }; + + /** + * Get the intersection points. + */ + inline VectorOfFixVecs<DimVec<double> > *getElIntersecPoints() const { + return elIntersecPoints; + }; + + /** + * Get number of intersection points. + */ + inline int getNumElIntersecPoints() const { + return numIntersecPoints; + }; + + /** + * Calculate exterior normal to intersection plane. + */ + void calcIntersecNormal(WorldVector<double> &normal); + + /** + * Gets position of point in element with barycentric coordinates + * barCoords, i.e. whether point is in the domain with positive + * (LEVEL_SET_EXTERIOR) or negative (LEVEL_SET_INTERIOR) level set + * function values. Uses level set function, thus element vertices + * may have level set function value zero. + */ + int getElPos(const DimVec<double> barCoords); + + /** + * Gets position of element vertex given in barycentric coordinates, + * i.e. whether element vertex is in the domain with positive + * (LEVEL_SET_EXTERIOR) or negative (LEVEL_SET_INTERIOR) level set + * function values. Uses elVertexLevelSetVec. + */ + int getVertexPos(const DimVec<double> barCoords); + + protected: + /** + * Calculates level set value of each vertex of element. + */ + void calculateElementLevelSetVal(); + + /** + * Calculates the status of an element. + * + * Note: Uses values in elVertexLevelSetVec. + * + * Return value: + * LEVEL_SET_INTERIOR element lies completely inside + * LEVEL_SET_EXTERIOR element lies completely outside + * LEVEL_SET_BOUNDARY element is cut by the zero level set + */ + int calculateElementStatus(); + + /** + * Calculates intersection points of zero level set with element. + * + * Note: Uses elVertexLevelSet. + */ + void calculateIntersecPoints(); + + /** + * Checks whether level set values of element (in elVertexLevelSetVec) + * are below a certain bound and corrects them if this is the case. + * + * Return value: number of values corrected + */ + int checkElementLevelSetVal(); + + /** + * Checks whether barycentric coordinate of intersection point is not + * too small and corrects it if this is the case. + * + * Return value: true - barycentric coordinate has been corrected + * false - barycentric coordinate is ok + */ + bool checkIntersecBary(double &bary); + + /** + * Sort intersection points S0, S1, S2 and S3 in \ref elIntersecPoints in + * such a way that afterwards, a line through S1 and S2 divides the + * intersection plane into two (\ref dim - 1)-dimensional simplices. + */ + void sortIntersecPoints_4IP3D(); + + /** + * Calculate exterior normal to intersection plane for dimension 2. + */ + void calcIntersecNormal_2d(WorldVector<double> &normal); + + /** + * Calculate exterior normal to intersection plane for dimension 3. + */ + void calcIntersecNormal_3d(WorldVector<double> &normal); + + public: + /** + * Constants characterizing element position with respect to zero level set. + */ + static const int LEVEL_SET_INTERIOR = -1; + static const int LEVEL_SET_BOUNDARY = 0; + static const int LEVEL_SET_EXTERIOR = 1; + static const int LEVEL_SET_UNDEFINED = -2; + + protected: + /** + * Name of this object. + */ + std::string name; + + /** + * Level set function. + */ + ElementFunction<double> *lSFct; + + /** + * Mesh. + */ + Mesh *mesh; + + /** + * elInfo of element. + */ + const ElInfo *elInfo; + + /** + * Pointer to last element processed calculations on whithin this class. + */ + Element *lastEl; + + /** + * Indicator which can be used for example for function evaluation + * or integration on subelements. Indicates whether point/subelement ... + * is inside (LEVEL_SET_INTERIOR) or outside (LEVEL_SET_EXTERIOR) the + * zero level set or is cut by the zero level set (LEVEL_SET_BOUNDARY). + */ + int level_set_domain; + + /** + * Dimension of the problem. dim + 1 is the number of vertices + * of element. + */ + int dim; + + /** + * Vector for intersection points produced by the intersection of linearly + * approximated level set function with the edges of element. + */ + VectorOfFixVecs<DimVec<double> > *elIntersecPoints; + + /** + * Number of intersection points. + */ + int numIntersecPoints; + + /** + * LevelSet-Status of element. + */ + int elStatus; + + /** + * Holds for each vertex of element the information about the position + * of the vertex with respect to the zero level set. + */ + int *elVertexStatusVec; + + /** + * Stores for each vertex of element the level set of the vertex. + */ + double *elVertexLevelSetVec; + + /** + * Number of vertices in element with level set status LEVEL_SET_INTERIOR. + */ + int numElVertexInterior; + + /** + * Number of vertices in element with level set status LEVEL_SET_BOUNDARY. + * + * Note: should be zero + */ + int numElVertexBoundary; + + /** + * Number of vertices in element with level set status LEVEL_SET_EXTERIOR. + */ + int numElVertexExterior; + + /** + * Tolerance used in the calculation of the local minimal level set value. + * The local minimal level set value depends on the gradient of the + * level set function. + * Used for the calculation of intersection points. + * + * If intersection points are too close to vertices, they are slightly + * moved. + * IDEA: If d is the distance of an intersection point to vertex v, + * the property + * + * d > LS_VAL_TOL * h + * + * must be satisfied. + * In the implementation this results in + * + * phi(v) > LS_VAL_TOL * h * grad . + */ + double LS_VAL_TOL; + + /** + * Lower bound for level set value on elements cut by the zero level set. + * Used for the calculation of intersection points. + */ + double LS_VAL_MIN; + + /** + * Lower bound for barycentric coordinates of intersection points. + * + * Each component x of the barycentric coordinates of an intersection + * point satisfies + * + * SP_BARY_TOL < x < 1 - SP_BARY_TOL . + */ + double SP_BARY_TOL; + + /* + * Maximum number of intersection points. + */ + static const int MAX_INTERSECTION_POINTS = 4; +}; + +#endif // AMDIS_ELEMENTLEVELSET_H diff --git a/AMDiS/Reinit/src/ElementUpdate.h b/AMDiS/Reinit/src/ElementUpdate.h new file mode 100644 index 00000000..c20fb738 --- /dev/null +++ b/AMDiS/Reinit/src/ElementUpdate.h @@ -0,0 +1,43 @@ +#ifndef ELEMENTUPDATE_H +#define ELEMENTUPDATE_H + +#include "FixVec.h" +// #include "MemoryManager.h" + +#include "VelocityExt.h" + +using namespace AMDiS; + +class ElementUpdate +{ + public: + MEMORY_MANAGED(ElementUpdate); + + /** + * Constructor. + */ + ElementUpdate(VelocityExt *velExt_) + : velExt(velExt_) + {}; + + /** + * Virtual destructor. + */ + virtual ~ElementUpdate() {}; + + /** + * Pure virtual function. + * Calculate Bornemann update on an element. Realization is implemented for + * dimensions 2 and 3. + */ + virtual double calcElementUpdate(const FixVec<WorldVector<double> *, VERTEX> &vert, + FixVec<double, VERTEX> &uhVal) = 0; + + protected: + /** + * Object needed to extrapolate velocity from the interface. + */ + VelocityExt *velExt; +}; + +#endif // ELEMENTUPDATE_H diff --git a/AMDiS/Reinit/src/ElementUpdate_2d.cc b/AMDiS/Reinit/src/ElementUpdate_2d.cc new file mode 100644 index 00000000..92d76aee --- /dev/null +++ b/AMDiS/Reinit/src/ElementUpdate_2d.cc @@ -0,0 +1,52 @@ +#include "ElementUpdate_2d.h" + +double +ElementUpdate_2d::calcElementUpdate( + const FixVec<WorldVector<double> *, VERTEX> &vert, + FixVec<double, VERTEX> &uhVal) +{ + WorldVector<double> xhminusYh = *(vert[2]) - *(vert[0]); + WorldVector<double> zhminusYh = *(vert[1]) - *(vert[0]); + WorldVector<double> xhminusZh = *(vert[2]) - *(vert[1]); + + double norm_zhminusYh = sqrt(zhminusYh * zhminusYh); + double norm_xhminusYh = sqrt(xhminusYh * xhminusYh); + double norm_xhminusZh = sqrt(xhminusZh * xhminusZh); + + double delta = (uhVal[1]-uhVal[0]) / norm_zhminusYh; + + double c_alpha = 0; + double c_beta = 0; + double sP = xhminusYh * zhminusYh; + c_alpha = sP / (norm_xhminusYh * norm_zhminusYh); + sP = xhminusZh * zhminusYh; + c_beta = -sP / (norm_xhminusZh * norm_zhminusYh); + + double update = 0; + if (c_alpha <= delta) { + update = uhVal[0] + norm_xhminusYh; + //save barycentric coordinates for calculation of the velocity + if(velExt != NULL) + { + velExt->setBarycentricCoords_2D(1,0,0); + } + } else if (delta <= -c_beta) { + update = uhVal[1] + norm_xhminusZh; + //save barycentric coordinates for calculation of the velocity + if(velExt != NULL) + { + velExt->setBarycentricCoords_2D(0,1,0); + } + } else { + update = uhVal[0] + + (c_alpha*delta + sqrt((1-c_alpha*c_alpha)*(1-delta*delta))) * + norm_xhminusYh; + //calculate and save barycentric coordinates for calculation of the velocity + if(velExt != NULL) + { + velExt->calcBarycentricCoords_2D(delta, c_alpha, norm_zhminusYh, norm_xhminusYh); + } + } + + return update; +} diff --git a/AMDiS/Reinit/src/ElementUpdate_2d.h b/AMDiS/Reinit/src/ElementUpdate_2d.h new file mode 100644 index 00000000..a5fbbd96 --- /dev/null +++ b/AMDiS/Reinit/src/ElementUpdate_2d.h @@ -0,0 +1,33 @@ +#ifndef ELEMENTUPDATE_2D_H +#define ELEMENTUPDATE_2D_H + +#include "FixVec.h" +// #include "MemoryManager.h" + +#include "ElementUpdate.h" +#include "VelocityExt.h" + +using namespace AMDiS; + +class ElementUpdate_2d : public ElementUpdate +{ + public: + MEMORY_MANAGED(ElementUpdate_2d); + + /** + * Constructor. + */ + ElementUpdate_2d(VelocityExt *velExt_ = NULL) + : ElementUpdate(velExt_) + {}; + + /** + * Realization of ElementUpdate::calcElementUpdate. + * Calculates the Bornemann update for an element. + */ + double calcElementUpdate(const FixVec<WorldVector<double> *, VERTEX> &vert, + FixVec<double, VERTEX> &uhVal); +}; + +#endif // ELEMENTUPDATE_2D_H + diff --git a/AMDiS/Reinit/src/ElementUpdate_3d.cc b/AMDiS/Reinit/src/ElementUpdate_3d.cc new file mode 100644 index 00000000..f21bef58 --- /dev/null +++ b/AMDiS/Reinit/src/ElementUpdate_3d.cc @@ -0,0 +1,609 @@ +#include "ElementUpdate_3d.h" + +double +ElementUpdate_3d::calcElementUpdate( + const FixVec<WorldVector<double> *, VERTEX> &vert_, + FixVec<double, VERTEX> &uhVal) +{ + FUNCNAME("ElementUpdate_3d::calcElementUpdate"); + + int dim = 3; + double update = 0.0; + WorldVector<double> B1; + WorldVector<double> C1; + WorldVector<double> D1; + double uhVal0_orig; // original value of vertex 0 after sort and + // translation of vertices but before + // translation of function values to zero + FixVec<WorldVector<double> *, VERTEX> vert(dim, NO_INIT); + for (int i=0; i<=dim; ++i) { + vert[i] = vert_[i]; + } + + // ===== Sort vertices and translate element to point of origin. ===== + sortAndTranslateElement(vert, uhVal, uhVal0_orig); + + // ===== Rotate element. + // The rotated element is stored in B1, C1, D1 (A = zero vector + // after sort and translation and is fix under rotation). + // Return value: true - rotation exists + // false - rotation does not exist + bool rotationFlag = rotateElement(vert, uhVal, B1, C1, D1); + + // ===== rotation exists ==> calculate projection and update value + // depending on the position of the + // projection point + // rotation does not exist ==> calculate update values on the + // faces of element + + if (rotationFlag) { + + // Calculate projection of B1, C1 and D1 on x-y-plane -> B2, C2, D2. + WorldVector<double> B2; + WorldVector<double> C2; + WorldVector<double> D2; + + B2[0] = B1[0]; B2[1] = B1[1]; B2[2] = 0.0; + C2[0] = C1[0]; C2[1] = C1[1]; C2[2] = 0.0; + D2[0] = D1[0]; D2[1] = D1[1]; D2[2] = 0.0; + + // Calculate position of D2 with respect to A, B2 and C2. + // If D2 lies in the triangle AB2C2, this is the minimizing point + // of the update formula. Else, the minimizing point lies on edges + // of this triangle and the 2-dimensional update formula is applied + // on faces of element to get the minimizing point. + int posFlag = calcPosition(B2, C2, D2); + + WorldVector<double> tmpVec; + switch(posFlag) { + + case IN_ABC: // update value is the distance of D1 to the x-y-plane + update = D1[2]; + break; + + case VERT_A: // minimizing point is vertex A + update = uhVal[0] + sqrt(*(vert[3]) * *(vert[3])); + //set barycentric coordinats for calculation of the velocity + if(velExt != NULL) + { + velExt->setBarycentricCoords_3D(1,0,0,0); + } + break; + + case VERT_B: // minimizing point is vertex B + tmpVec = (*(vert[3])) - (*(vert[1])); + update = uhVal[1] + sqrt(tmpVec * tmpVec); + //set barycentric coordinats for calculation of the velocity + if(velExt != NULL) + { + velExt->setBarycentricCoords_3D(0,1,0,0); + } + break; + + case VERT_C: // minimizing point is vertex C + tmpVec = (*(vert[3])) - (*(vert[2])); + update = uhVal[2] + sqrt(tmpVec * tmpVec); + //set barycentric coordinats for calculation of the velocity + if(velExt != NULL) + { + velExt->setBarycentricCoords_3D(0,0,1,0); + } + break; + + case EDGE_AB: // minimizing point lies on edge AB + update = calcFaceUpdate(vert[0], vert[1], vert[3], + uhVal[0], uhVal[1]); + //set barycentric coordinats for calculation of the velocity + if(velExt != NULL) + { + velExt->copyAndExpandFaceCoords_3D(2,0); + } + break; + + case EDGE_AC: // minimizing point lies on edge AC + update = calcFaceUpdate(vert[0], vert[2], vert[3], + uhVal[0], uhVal[2]); + //set barycentric coordinats for calculation of the velocity + if(velExt != NULL) + { + velExt->copyAndExpandFaceCoords_3D(1,0); + } + break; + + case EDGE_BC: // minimizing point lies on edge BC + update = calcFaceUpdate(vert[1], vert[2], vert[3], + uhVal[1], uhVal[2]); + //set barycentric coordinats for calculation of the velocity + if(velExt != NULL) + { + velExt->copyAndExpandFaceCoords_3D(0,0); + } + break; + + default: ERROR_EXIT("illegal position flag !\n"); + break; + } + + } + else { // rotation does not exist + + // ===== Calculate the 2-dimensional update for D on all faces + // adjacent with D. The update value is the minimum of these + // updates. ===== + double tmp_update; + + update = calcFaceUpdate(vert[0], vert[1], vert[3], + uhVal[0], uhVal[1]); + //set barycentric coordinats for calculation of the velocity + //save index of element face + if(velExt != NULL) + { + velExt->copyAndExpandFaceCoords_3D(2,1); + velExt->setIndexFaceWithShortestDist(1); + } + tmp_update = calcFaceUpdate(vert[0], vert[2], vert[3], + uhVal[0], uhVal[2]); + //set barycentric coordinats for calculation of the velocity + if(velExt != NULL) + { + velExt->copyAndExpandFaceCoords_3D(1,2); + } + if (tmp_update < update) { + update = tmp_update; + //save index of element face, if diatance is shorter + if(velExt != NULL) + { + velExt->setIndexFaceWithShortestDist(2); + } + } + tmp_update = calcFaceUpdate(vert[1], vert[2], vert[3], + uhVal[1], uhVal[2]); + //set barycentric coordinats for calculation of the velocity + if(velExt != NULL) + { + velExt->copyAndExpandFaceCoords_3D(0,3); + } + if (tmp_update < update) { + update = tmp_update; + //save index of element face, if distance is shorter + if(velExt != NULL) + { + velExt->setIndexFaceWithShortestDist(3); + } + } + } + + // ===== Correct initial translation of function values to zero. ===== + update += uhVal0_orig; + + return update; +} + +void +ElementUpdate_3d::sortAndTranslateElement( + FixVec<WorldVector<double> *, VERTEX> &vert, + FixVec<double, VERTEX> &uhVal, + double &uhVal0_orig) +{ + WorldVector<double> *tmpVec; + double tmpVal; + + // ===== Sort vertices. ===== + if (uhVal[0] > uhVal[1]) { + + if (uhVal[1] > uhVal[2]) { + + tmpVec = vert[0]; + vert[0] = vert[2]; + vert[2] = tmpVec; + + tmpVal = uhVal[0]; + uhVal[0] = uhVal[2]; + uhVal[2] = tmpVal; + //save permutation of vertices + if(velExt != NULL) + { + velExt->swapVertices(0,2); + } + } + else if (uhVal[0] > uhVal[2]) { + + tmpVec = vert[0]; + vert[0] = vert[1]; + vert[1] = vert[2]; + vert[2] = tmpVec; + + tmpVal = uhVal[0]; + uhVal[0] = uhVal[1]; + uhVal[1] = uhVal[2]; + uhVal[2] = tmpVal; + //save permutation of vertices + if(velExt != NULL) + { + velExt->swapVertices(0,1); + velExt->swapVertices(2,1); + } + } + else { + + tmpVec = vert[0]; + vert[0] = vert[1]; + vert[1] = tmpVec; + + tmpVal = uhVal[0]; + uhVal[0] = uhVal[1]; + uhVal[1] = tmpVal; + //save permutation of vertices + if(velExt != NULL) + { + velExt->swapVertices(0,1); + } + } + } + else if (uhVal[1] > uhVal[2]) { + + if (uhVal[0] > uhVal[2]) { + + tmpVec = vert[0]; + vert[0] = vert[2]; + vert[2] = vert[1]; + vert[1] = tmpVec; + + tmpVal = uhVal[0]; + uhVal[0] = uhVal[2]; + uhVal[2] = uhVal[1]; + uhVal[1] = tmpVal; + //save permutation of vertices + if(velExt != NULL) + { + velExt->swapVertices(0,2); + velExt->swapVertices(1,2); + } + } + else { + + tmpVec = vert[1]; + vert[1] = vert[2]; + vert[2] = tmpVec; + + tmpVal = uhVal[1]; + uhVal[1] = uhVal[2]; + uhVal[2] = tmpVal; + //save permutation of vertices + if(velExt != NULL) + { + velExt->swapVertices(1,2); + } + } + } + + // ===== Translation: A is moved to point of origin. ===== + *(vert[1]) -= *(vert[0]); + *(vert[2]) -= *(vert[0]); + *(vert[3]) -= *(vert[0]); + *(vert[0]) = 0.0; + + // ===== Adapt \ref uhVal. ===== + uhVal[1] -= uhVal[0]; + uhVal[2] -= uhVal[0]; + uhVal0_orig = uhVal[0]; + uhVal[0] = 0.0; +} + +bool +ElementUpdate_3d::rotateElement( + const FixVec<WorldVector<double> *, VERTEX> &vert, + const FixVec<double, VERTEX> &uhVal, + WorldVector<double> &B1, + WorldVector<double> &C1, + WorldVector<double> &D1) +{ + int orient = 1; // orientation of AB, AC and AD + WorldVector<double> B = *(vert[1]); + WorldVector<double> C = *(vert[2]); + WorldVector<double> D = *(vert[3]); + WorldVector<double> N; // unit normal for ABC + // (orientation of AB, AC and N is 1) + WorldVector<double> P; // projection of D on ABC + WorldVector<double> unit_B; // normalized AB + double norm_B; // norm of vector AB + double norm_C; // norm of vector AC + double norm_P; // norm of vector AP + double dD; // (signed) distance of D to ABC + double lambda, nue; // scalars + WorldVector<double> N1; // unit normal for A1B1C1 + WorldVector<double> unit_B1; // normalized B1 + double dB1 = uhVal[1]; // distance of B1 to x-y-plane + double dC1 = uhVal[2]; // distance of C1 to x-y-plane + WorldVector<double> E_21; // vector of rotated coordinate system + int dim = 3; + WorldVector<double> tmpVec; + double tmp; + + + // ===== Calculate orientation of ABCD. ===== + + // Get unit normal for ABC. + tmpVec[0] = B[1]*C[2] - B[2]*C[1]; + tmpVec[1] = B[2]*C[0] - B[0]*C[2]; + tmpVec[2] = B[0]*C[1] - B[1]*C[0]; + tmp = sqrt(tmpVec * tmpVec); + for (int i=0; i<dim; ++i) { N[i] = tmpVec[i] / tmp; } + + // Calculate distance of D to ABC. + dD = D * N; + + // Orientation. + orient = (dD < 0) ? -1 : 1; + + + // ===== Calculate B1. + // We construct B1 in x-z-plane with distance dB1 to + // x-y-plane. ===== + + norm_B = sqrt(B * B); + + tmp = norm_B*norm_B - dB1*dB1; + if (tmp < 1.e-15) { + return false; // rotation is not possible + } + B1[0] = sqrt(tmp); + B1[1] = 0.0; + B1[2] = dB1; + + + // ===== Calculate C1. + // If (E_1, E_2, E_3) is a coordinate system with + // AC = lambda*E_1 + nue*E_2, then for the rotated coordinate + // system (E_11, E_21, E_31) we have + // A1C1 = lambda*E_11 + nue*E_21. + // + // The coordinate system (E_1, E_2, E_3) does not need to + // be calculated, but we assume + // --> E_1 = unit_B, + // --> nue > 0. ===== + + // Calculate lambda and nue. + for (int i=0; i<dim; ++i) { unit_B[i] = B[i] / norm_B; } + norm_C = sqrt(C * C); + + lambda = C * unit_B; // corresponds to norm(AC)*cos(AC,AB) + nue = sqrt(norm_C*norm_C - lambda*lambda); + // corresponds to norm(AC)*sin(AC,AB) + + // Calculate E_11 (= unit_B1). + for (int i=0; i<dim; ++i) { unit_B1[i] = B1[i] / norm_B; } + + // Calculate E_21. + E_21[2] = (dC1 - lambda*unit_B1[2])/nue; + // A1C1 = lambda*E_11 + nue*E_21 and C1[2] = dC1 + + E_21[0] = -unit_B1[2]*E_21[2]/unit_B1[0]; + // E_11*E_21 = 0 and unit_B[1]=0 + + tmp = 1 - E_21[0]*E_21[0] - E_21[2]*E_21[2]; + if (tmp < 1.e-15) { + return false; // rotation is not possible + } + E_21[1] = orient * sqrt(tmp); // norm(E_21) = 1 and + // in further construction: D1 + // above x-y-plane + + // Calculate C1. + C1[0] = lambda*unit_B1[0] + nue*E_21[0]; + C1[1] = lambda*unit_B1[1] + nue*E_21[1]; + C1[2] = lambda*unit_B1[2] + nue*E_21[2]; + + + // ===== Calculate D1. + // If we have AP = lambda*E_1 + nue*E_2 for the projection P of + // D on ABC , then D1 = lambda*E_11 + nue*E_21 + dD*N1. ===== + + // Calculate P. + P[0] = D[0] - dD*N[0]; + P[1] = D[1] - dD*N[1]; + P[2] = D[2] - dD*N[2]; + + // Calculate lambda and nue. + norm_P = sqrt(P * P); + lambda = P * unit_B; // corresponds to norm(AP)*cos(AP,AB) + nue = sqrt(norm_P*norm_P - lambda*lambda); + // corresponds to norm(AP)*sin(AP,AB) + // Fix problem for angle(E_2,P) > Pi/2: + // project P onto E_2-axes (-> tmpVec), + // if angle(tmpVec,AC) > Pi/2 the scalar nue has negative sign. + tmpVec = P - unit_B*lambda; + if (tmpVec * C < 0) { nue *= -1; } + + // Calculate N1. + tmpVec[0] = B1[1]*C1[2] - B1[2]*C1[1]; + tmpVec[1] = B1[2]*C1[0] - B1[0]*C1[2]; + tmpVec[2] = B1[0]*C1[1] - B1[1]*C1[0]; + tmp = sqrt(tmpVec * tmpVec); + for (int i=0; i<dim; ++i) { N1[i] = tmpVec[i] / tmp; } + + // Calculate D1. + D1[0] = lambda*unit_B1[0] + nue*E_21[0] + dD*N1[0]; + D1[1] = lambda*unit_B1[1] + nue*E_21[1] + dD*N1[1]; + D1[2] = lambda*unit_B1[2] + nue*E_21[2] + dD*N1[2]; + +// // Check projection of triangle A1B1C1 (-> triangle A2B2C2) to x-y-plane. +// // Rotation is said to be not possible if +// // -> angles are too small: | cos(A2B2,A2C2) | < 1-1.e-3 +// // -> area of A2B2C2 is too small: +// // | det(A2B2 A2C2) | > max(1.e-10, 0.01*norm_B*norm_B) +// double abs_det_B2C2 = fabs(B1[0]*C1[1]-B1[1]*C1[0]); +// double limit = (0.01*norm_B*norm_B < 1.e-10) ? +// 1.e-10 : 0.01*norm_B*norm_B; +// if (abs_det_B2C2 < limit) +// return false; + +// double norm_AB2 = sqrt(B1[0]*B1[0]+B1[1]*B1[1]); +// double norm_AC2 = sqrt(C1[0]*C1[0]+C1[1]*C1[1]); +// double cos_B2AC2 = (B1[0]*C1[0]+B1[1]*C1[1]) / (norm_AB2*norm_AC2); +// if (fabs(cos_B2AC2) > 0.999) +// return false; + + return true; +} + +const int +ElementUpdate_3d::calcPosition(const WorldVector<double> &B2, + const WorldVector<double> &C2, + const WorldVector<double> &D2) +{ + FUNCNAME("ElementUpdate_3d::calcPosition"); + + double l_A, l_B2, l_C2; + double tmp_B2, tmp_C2; + double norm_AB2 = sqrt(B2 * B2); + double norm_AC2 = sqrt(C2 * C2); + double sP_AB2AC2 = B2 * C2; + double cos_B2AC2 = sP_AB2AC2 / (norm_AB2*norm_AC2); + int posFlag = -1; + + // ===== Calculate barycentric coordinates of D2 with respect to + // triangle AB2C2. ===== + if (fabs(cos_B2AC2) < 1.e-15) { + double sP_AB2AD2 = B2 * D2; + double sP_AC2AD2 = C2 * D2; + + tmp_B2 = (sP_AB2AD2 < 0) ? -D2[0] : D2[0]; + tmp_C2 = (sP_AC2AD2 < 0) ? -D2[1] : D2[1]; + + if (C2[1] < 0) + tmp_C2 *= -1; + } + else { + double sin_B2AC2 = sqrt(1-cos_B2AC2*cos_B2AC2); + + if (C2[1] < 0) + sin_B2AC2 *= -1; + + tmp_C2 = D2[1]/sin_B2AC2; + tmp_B2 = D2[0] - D2[1]*cos_B2AC2/sin_B2AC2; + } + + l_B2 = tmp_B2 / norm_AB2; + l_C2 = tmp_C2 / norm_AC2; + +// // for test purposes: barycentric coordinates with Cramer's rule +// double det_B2C2 = B2[0]*C2[1]-B2[1]*C2[0]; + +// TEST_EXIT(fabs(det_B2C2) > 1.e-15)("illegal projection triangle !\n"); + +// double det_D2C2 = D2[0]*C2[1]-D2[1]*C2[0]; +// double det_B2D2 = B2[0]*D2[1]-B2[1]*D2[0]; + +// double l_B2_Cramer = 1.0*det_D2C2/det_B2C2; +// double l_C2_Cramer = 1.0*det_B2D2/det_B2C2; + +// // TEST_EXIT(fabs(l_B2-l_B2_Cramer) < 1.e-8 && +// // fabs(l_C2-l_C2_Cramer) < 1.e-8) +// TEST_EXIT(fabs(l_B2*l_B2_Cramer) >= 0 && +// fabs(l_C2*l_C2_Cramer) >= 0) +// ("problems in barycentric coordinates of projection point !\n"); +// // end: for test purposes + + /* // Corrections. */ + /* if (fabs(l_B2) < 1.e-15) l_B2 = 0.0; */ + /* if (fabs(1-l_B2) < 1.e-15) l_B2 = 1.0; */ + /* if (fabs(l_C2) < 1.e-15) l_C2 = 0.0; */ + /* if (fabs(1-l_C2) < 1.e-15) l_C2 = 1.0; */ + + l_A = 1-l_B2-l_C2; + + //save barycentric coordinates for calculation of the velocity + if(velExt != NULL) + { + velExt->setBarycentricCoords_3D(l_A,l_B2,l_C2,0); + } + + // ===== Determine position of D2. ===== + if (l_A < 0) { + if (l_B2 < 0) { + if (l_C2 < 0) { + ERROR_EXIT("calculation error: sum of barycentric coordinates is equal to 1 !\n"); + } + else { + posFlag = VERT_C; + } + } + else if (l_C2 < 0) { + posFlag = VERT_B; + } + else { // EDGE_BC + posFlag = EDGE_BC; + /* if (l_B2 > 0) { */ + /* posFlag = (l_C2 > 0) ? EDGE_BC : VERT_B; */ + /* } */ + /* else { */ + /* if (l_C2 > 0) { */ + /* posFlag = VERT_C; */ + /* } */ + /* else { */ + /* ERROR_EXIT("no barycentric coordinates !\n"); */ + /* } */ + /* } */ + } + } + else if (l_B2 < 0) { + if (l_C2 < 0) { + posFlag = VERT_A; + } + else { // EDGE_AC + posFlag = EDGE_AC; + /* if (l_A > 0) { */ + /* posFlag = (l_C2 > 0) ? EDGE_AC : VERT_A; */ + /* } */ + /* else { */ + /* if (l_C2 > 0) { */ + /* posFlag = VERT_C; */ + /* } */ + /* else { */ + /* ERROR_EXIT("no barycentric coordinates !\n"); */ + /* } */ + /* } */ + } + } + else if (l_C2 < 0) { // EDGE_AB + posFlag = EDGE_AB; + /* if (l_A > 0) { */ + /* posFlag = (l_B2 > 0) ? EDGE_AB : VERT_A; */ + /* } */ + /* else { */ + /* if (l_B2 > 0) { */ + /* posFlag = VERT_B; */ + /* } */ + /* else { */ + /* ERROR_EXIT("no barycentric coordinates !\n"); */ + /* } */ + /* } */ + } + else { + posFlag = IN_ABC; + } + + return posFlag; +} + +double +ElementUpdate_3d::calcFaceUpdate(WorldVector<double> *A2d, + WorldVector<double> *B2d, + WorldVector<double> *C2d, + double &uhValA2d, + double &uhValB2d) +{ + int dim = A2d->getSize(); + FixVec<WorldVector<double> *, VERTEX> vert2d(dim, NO_INIT); + FixVec<double, VERTEX> uhVal2d(dim, NO_INIT); + + vert2d[0] = A2d; + vert2d[1] = B2d; + vert2d[2] = C2d; + + uhVal2d[0] = uhValA2d; + uhVal2d[1] = uhValB2d; + + return elUpdate2d->calcElementUpdate(vert2d, uhVal2d); +} diff --git a/AMDiS/Reinit/src/ElementUpdate_3d.h b/AMDiS/Reinit/src/ElementUpdate_3d.h new file mode 100644 index 00000000..1801dd73 --- /dev/null +++ b/AMDiS/Reinit/src/ElementUpdate_3d.h @@ -0,0 +1,117 @@ +#ifndef ELEMENTUPDATE_3D_H +#define ELEMENTUPDATE_3D_H + +#include "FixVec.h" +// #include "MemoryManager.h" + +#include "ElementUpdate.h" +#include "ElementUpdate_2d.h" +#include "VelocityExt.h" + +using namespace AMDiS; + +class ElementUpdate_3d : public ElementUpdate +{ + public: + MEMORY_MANAGED(ElementUpdate_3d); + + /** + * Constructor. + */ + ElementUpdate_3d(VelocityExt *velExt_ = NULL) + : ElementUpdate(velExt_) + { + elUpdate2d = NEW ElementUpdate_2d(velExt_); + }; + + /** + * Destructor. + */ + ~ElementUpdate_3d() + { + DELETE elUpdate2d; + }; + + /** + * Realization of ElementUpdate::calcElementUpdate. + * Calculates the Bornemann update for an element. The update is + * calculated for the last vertex of \ref vert, denoted by xh. + */ + double calcElementUpdate(const FixVec<WorldVector<double> *, VERTEX> &vert_, + FixVec<double, VERTEX> &uhVal); + + protected: + /** + * Sorts vertices of the face opposite to xh and translates the element + * to the point of origin. + * + * Denote A the vertex \ref vert[0], B the vertex \ref vert[1], ... + * after the sort, and uhVal(A), uhVal(B), ... the corresponding function + * values. + * Then, after the sort, uhVal(A) <= uhVal(B) <= uhVal(C). + * Finally, translation of element moves A to zero, uhVal(A) is set to + * zero, uhVal(B), uhVal(C) correspondingly. + */ + void sortAndTranslateElement(FixVec<WorldVector<double> *, VERTEX> &vert, + FixVec<double, VERTEX> &uhVal, + double &uhVal0_orig); + + /** + * Calculates rotation of element. + * + * Denote A1, B1, ... the vertices of element after rotation. + * Then distance of B1 to x-y-plane is uhVal(B) and + * distance of C1 to x-y-plane is uhVal(C). + * + * Return value: true - rotation exists + * false - rotation does not exist + * + * Assumptions: --> A == zero vector (then AB == B, ...) + * --> uhVal(A) == 0 + */ + bool rotateElement(const FixVec<WorldVector<double> *, VERTEX> &vert, + const FixVec<double, VERTEX> &uhVal, + WorldVector<double> &B1, + WorldVector<double> &C1, + WorldVector<double> &D1); + + /** + * Determines position of D2 with respect to the triangle AB2C2. + * A is the point of origin. + * + * Note: Limited to triangles with angles not greater than Pi/2 + * (acute triangles). + */ + const int calcPosition(const WorldVector<double> &B2, + const WorldVector<double> &C2, + const WorldVector<double> &D2); + + /** + * Calculate 2-dimensional Bornemann update for face of element. The + * update is calculated for vertex with coordinates \ref *C2d. + */ + double calcFaceUpdate(WorldVector<double> *A2d, + WorldVector<double> *B2d, + WorldVector<double> *C2d, + double &uhValA2d, + double &uhValB2d); + + protected: + /** + * Used for Bornemann update on faces of element. + */ + ElementUpdate_2d *elUpdate2d; + + /** + * Flags to decribe position of D2 with respect to AB2C2. + */ + static const int IN_ABC = 0; + static const int VERT_A = 1; + static const int VERT_B = 2; + static const int VERT_C = 3; + static const int EDGE_AB = 4; + static const int EDGE_AC = 5; + static const int EDGE_BC = 6; +}; + +#endif // ELEMENTUPDATE_3D_H diff --git a/AMDiS/Reinit/src/HL_SignedDist.cc b/AMDiS/Reinit/src/HL_SignedDist.cc new file mode 100644 index 00000000..a81ae35a --- /dev/null +++ b/AMDiS/Reinit/src/HL_SignedDist.cc @@ -0,0 +1,375 @@ +#include "HL_SignedDist.h" + +const Flag HL_SignedDist::VEL_EXT = 0X01L; +const Flag HL_SignedDist::VEL_EXT_FROM_VEL_FIELD = 0X02L; + +void +HL_SignedDist::calcSignedDistFct(AdaptInfo *adaptInfo_, + const DOFVector<double> *lS_DOF_, + DOFVector<double> *sD_DOF_, + ElementFunction<double> *elFct) +{ + adaptInfo = adaptInfo_; + + if (elFct == NULL) { + TEST_EXIT(lS_DOF_)("illegal level set function !\n"); + TEST_EXIT(lS_DOF_->getFESpace() == sD_DOF_->getFESpace())("DOF vectors do not have the same FE space!\n"); + } + TEST_EXIT(sD_DOF_)("illegal DOF vector for signed distance function !\n"); + TEST_EXIT(sD_DOF_->getFESpace()->getBasisFcts()->getDegree() == 1)("does it work for non-linear finite elements ?\n"); + + lS_DOF = lS_DOF_; + sD_DOF = sD_DOF_; + feSpace = sD_DOF->getFESpace(); + + // ===== Initialization. ===== + initialize(elFct); + + // ===== Print level set function. ===== + if (lS_DOF) + printLevelSetFct(); + + // ===== Create DOF vector to mark boundary vertices. ===== + if (bound_DOF) + DELETE bound_DOF; + bound_DOF = NEW DOFVector<double>(feSpace, "bound_DOF"); + bound_DOF->set(0.0); + + // ===== Boundary vertex and boundary value initialization. ===== + initializeBoundary(); + + // ===== Print boundary initialization. ===== + printBoundInitFct(); + + // ===== Calculate distance function. ===== + HL_updateIteration(); + + // ===== Transformation to signed distance function. ===== + if (elFct == NULL) + setSign(); + + // ===== Print calculated signed distance function. ===== + printSignedDistFct(); +} + +void +HL_SignedDist::calcSignedDistFct(AdaptInfo *adaptInfo_, + DOFVector<double> *lS_DOF_) +{ + TEST_EXIT(lS_DOF_)("illegal level set function lS_DOF_ !\n"); + + sD_DOF = NEW DOFVector<double>(lS_DOF_->getFESpace(), "sD_DOF"); + + calcSignedDistFct(adaptInfo_, lS_DOF_, sD_DOF, NULL); + + // lS_DOF_->copy(*sD_DOF); + *lS_DOF_ = *sD_DOF; + + DELETE sD_DOF; +} + +void +HL_SignedDist::calcVelocityExt(AdaptInfo *adaptInfo_, + DOFVector<double> *origVel_DOF_, + DOFVector<double> *vel_DOF_, + const DOFVector<double> *lS_DOF_, + DOFVector<double> *sD_DOF_, + bool calcSDFct, + ElementFunction<double> *elFct) +{ + TEST_EXIT(velExtType.isSet(VEL_EXT))("illegal velocity extension type !\n"); + TEST_EXIT(velExt)("velExt not defined !\n"); + + velExt->setVelocity(origVel_DOF_, vel_DOF_); + + velExt->printOrigVelDOF(adaptInfo_); + + if (calcSDFct || sD_DOF_ != NULL) { + calcSignedDistFct(adaptInfo_, lS_DOF_, sD_DOF_, elFct); + } + else { + + TEST_EXIT(vel_DOF_)("illegal level set function lS_DOF_ !\n"); + + sD_DOF = NEW DOFVector<double>(vel_DOF_->getFESpace(), "sD_DOF"); + + calcSignedDistFct(adaptInfo_, lS_DOF_, sD_DOF, elFct); + + DELETE sD_DOF; + } + + velExt->printVelDOF(adaptInfo_); +} + +void +HL_SignedDist::calcVelocityExt(AdaptInfo *adaptInfo_, + DOFVector<double> *vel_DOF_, + DOFVector<double> *lS_DOF_, + bool calcSDFct, + ElementFunction<double> *elFct) +{ + TEST_EXIT(velExtType.isSet(VEL_EXT))("illegal velocity extension type !\n"); + TEST_EXIT(velExt)("velExt not defined !\n"); + TEST_EXIT(vel_DOF_)("velocity vector vel_DOF_ not defined !\n"); + + if (calcSDFct) + TEST_EXIT(lS_DOF_)("illegal level set function lS_DOF_ !\n"); + + DOFVector<double> *newVel_DOF_ = + NEW DOFVector<double>(vel_DOF_->getFESpace(), "vel_DOF_"); + + velExt->setVelocity(vel_DOF_, newVel_DOF_); + + velExt->printOrigVelDOF(adaptInfo_); + + if (calcSDFct && elFct == NULL) + calcSignedDistFct(adaptInfo_, lS_DOF_); + else { + + sD_DOF = NEW DOFVector<double>(vel_DOF_->getFESpace(), "sD_DOF"); + + calcSignedDistFct(adaptInfo_, lS_DOF_, sD_DOF, elFct); + + if (calcSDFct) + lS_DOF_->copy(*sD_DOF); + + DELETE sD_DOF; + } + + vel_DOF_->copy(*newVel_DOF_); + + velExt->printVelDOF(adaptInfo_); + + DELETE newVel_DOF_; +} + +void +HL_SignedDist::calcVelocityExt( + AdaptInfo *adaptInfo_, + std::vector<DOFVector<double> *> origVel_DOF_, + std::vector<DOFVector<double> *> vel_DOF_, + const DOFVector<double> *lS_DOF_, + DOFVector<double> *sD_DOF_, + bool calcSDFct, + ElementFunction<double> *elFct) +{ + TEST_EXIT(velExtType.isSet(VEL_EXT))("illegal velocity extension type !\n"); + TEST_EXIT(velExt)("velExt not defined !\n"); + + velExt->setVelocity(origVel_DOF_, vel_DOF_); + + velExt->printOrigVelDOF(adaptInfo_); + + if (calcSDFct || sD_DOF_ != NULL) { + calcSignedDistFct(adaptInfo_, lS_DOF_, sD_DOF_, elFct); + } + else { + + TEST_EXIT(vel_DOF_[0])("illegal level set function lS_DOF_ !\n"); + + sD_DOF = NEW DOFVector<double>(vel_DOF_[0]->getFESpace(), "sD_DOF"); + + calcSignedDistFct(adaptInfo_, lS_DOF_, sD_DOF, elFct); + + DELETE sD_DOF; + } + + velExt->printVelDOF(adaptInfo_); +} + +void +HL_SignedDist::calcVelocityExt(AdaptInfo *adaptInfo_, + std::vector<DOFVector<double> *> vel_DOF_, + DOFVector<double> *lS_DOF_, + bool calcSDFct, + ElementFunction<double> *elFct) +{ + TEST_EXIT(velExtType.isSet(VEL_EXT))("illegal velocity extension type !\n"); + TEST_EXIT(velExt)("velExt not defined !\n"); + + int nVelDOFs = vel_DOF_.size(); + + if (calcSDFct) + TEST_EXIT(lS_DOF_)("illegal level set function lS_DOF_ !\n"); + + std::vector<DOFVector<double> *> newVel_DOF_(nVelDOFs); + for (int nV=0; nV<nVelDOFs; ++nV) { + + TEST_EXIT(vel_DOF_[nV])("velocity vector vel_DOF_ not defined !\n"); + + newVel_DOF_[nV] = + NEW DOFVector<double>((vel_DOF_[nV])->getFESpace(), "vel_DOF_"); + } + + velExt->setVelocity(vel_DOF_, newVel_DOF_); + + velExt->printOrigVelDOF(adaptInfo_); + + if (calcSDFct && elFct == NULL) + calcSignedDistFct(adaptInfo_, lS_DOF_); + else { + + sD_DOF = NEW DOFVector<double>(vel_DOF_[0]->getFESpace(), "sD_DOF"); + + calcSignedDistFct(adaptInfo_, lS_DOF_, sD_DOF, elFct); + + if (calcSDFct) + lS_DOF_->copy(*sD_DOF); + + DELETE sD_DOF; + } + + for (int nV=0; nV<nVelDOFs; ++nV) + (vel_DOF_[nV])->copy(*(newVel_DOF_[nV])); + + velExt->printVelDOF(adaptInfo_); + + for (int nV=0; nV<nVelDOFs; ++nV) + DELETE newVel_DOF_[nV]; +} + +void +HL_SignedDist::calcVelocityExtFromVelocityField( + AdaptInfo *adaptInfo_, + std::vector<DOFVector<double> *> &velField_, + DOFVector<double> *vel_DOF_, + const DOFVector<double> *lS_DOF_, + DOFVector<double> *sD_DOF_, + bool calcSDFct, + ElementFunction<double> *elFct) +{ + TEST_EXIT(velExtType.isSet(VEL_EXT_FROM_VEL_FIELD)) + ("illegal velocity extension type !\n"); + TEST_EXIT(velExt)("velExt not defined !\n"); + TEST_EXIT(elFct == NULL)("not implemented yet for elFct != NULL !\n"); + + ((VelocityExtFromVelocityField *)(velExt))->setVelocityField(velField_, lS_DOF_, vel_DOF_); + + if (calcSDFct) { + calcSignedDistFct(adaptInfo_, lS_DOF_, sD_DOF_, elFct); + } + else { + + TEST_EXIT(vel_DOF_)("illegal velocity vector vel_DOF_ !\n"); + + sD_DOF = NEW DOFVector<double>(vel_DOF_->getFESpace(), "sD_DOF"); + + calcSignedDistFct(adaptInfo_, lS_DOF_, sD_DOF, elFct); + + DELETE sD_DOF; + } + + velExt->printVelDOF(adaptInfo_); +} + +void +HL_SignedDist::calcVelocityExtFromVelocityField( + AdaptInfo *adaptInfo_, + std::vector<DOFVector<double> *> &velField_, + DOFVector<double> *vel_DOF_, + DOFVector<double> *lS_DOF_, + bool calcSDFct, + ElementFunction<double> *elFct) +{ + TEST_EXIT(velExtType.isSet(VEL_EXT_FROM_VEL_FIELD)) + ("illegal velocity extension type !\n"); + TEST_EXIT(velExt)("velExt not defined !\n"); + TEST_EXIT(elFct == NULL)("not implemented yet for elFct != NULL !\n"); + + if (calcSDFct) + TEST_EXIT(lS_DOF_)("illegal level set function lS_DOF_ !\n"); + + ((VelocityExtFromVelocityField *)(velExt))->setVelocityField(velField_, lS_DOF_, vel_DOF_); + + if (calcSDFct && elFct == NULL) { + calcSignedDistFct(adaptInfo_, lS_DOF_); + } + else { + + TEST_EXIT(vel_DOF_)("illegal velocity vector vel_DOF_ !\n"); + + sD_DOF = NEW DOFVector<double>(vel_DOF_->getFESpace(), "sD_DOF"); + + calcSignedDistFct(adaptInfo_, lS_DOF_, sD_DOF, elFct); + + if (calcSDFct) + lS_DOF_->copy(*sD_DOF); + + DELETE sD_DOF; + } + + velExt->printVelDOF(adaptInfo_); +} + +void +HL_SignedDist::initialize(ElementFunction<double> *elFct) +{ + if (elUpdate) + DELETE elUpdate; + if (bndElDist) + DELETE bndElDist; + + if (elLS) + DELETE elLS; + if (phi) + DELETE phi; + + // ===== Create ElementLevelSet. ===== + if (elFct == NULL) { + phi = NEW ElementFunctionDOFVec<double>(lS_DOF); + elLS = NEW ElementLevelSet("ElementLevelSet", phi, feSpace->getMesh()); + } + else { + elLS = NEW ElementLevelSet("ElementLevelSet", elFct, feSpace->getMesh()); + } + + + // ===== Define boundary initialization strategy. ===== + int boundInitFlag; + GET_PARAMETER(0, name + "->boundary initialization", "%d", + &boundInitFlag); + switch(boundInitFlag) { + case 0: bndElDist = NEW BoundaryElementLevelSetDist(elLS, dim); + break; + case 1: bndElDist = NEW BoundaryElementTopDist(elLS, dim, velExt); + break; + case 2: bndElDist = NEW BoundaryElementEdgeDist(elLS, dim); + break; + case 3: bndElDist = NEW BoundaryElementNormalDist(elLS, dim); + break; + default: ERROR_EXIT("illegal boundary initialization !\n"); + break; + } + + // ===== Create elUpdate. ===== + TEST_EXIT(velExt == NULL || boundInitFlag == 1) + ("velocity extension only works with topological boundary element initialization method !\n"); + + switch(dim) { + case 2: elUpdate = NEW ElementUpdate_2d(velExt); + break; + case 3: elUpdate = NEW ElementUpdate_3d(velExt); + break; + default: ERROR_EXIT("illegal dimension !\n"); + break; + } +} + +void +HL_SignedDist::setSign() +{ + DOFVector<double>::Iterator it_sD(const_cast<DOFVector<double> *>(sD_DOF), + USED_DOFS); + DOFVector<double>::Iterator it_lS(const_cast<DOFVector<double> *>(lS_DOF), + USED_DOFS); + + for(it_sD.reset(), it_lS.reset(); + !it_sD.end(); + ++it_sD, ++it_lS) { + + // Vertex lies inside the zero level set ? + if ((*it_lS) < 0) { + (*it_sD) *= -1; + } + } +} diff --git a/AMDiS/Reinit/src/HL_SignedDist.h b/AMDiS/Reinit/src/HL_SignedDist.h new file mode 100644 index 00000000..0853c6f4 --- /dev/null +++ b/AMDiS/Reinit/src/HL_SignedDist.h @@ -0,0 +1,407 @@ +#ifndef HL_SIGNEDDIST +#define HL_SIGNEDDIST + +#include "Global.h" +#include "AdaptInfo.h" +#include "DOFVector.h" +#include "ElementFunction.h" +#include "FileWriter.h" +#include "FixVec.h" +#include "Flag.h" +// #include "MemoryManager.h" +#include "Parameters.h" + +#include "ElementLevelSet.h" + +#include "BoundaryElementDist.h" +#include "BoundaryElementLevelSetDist.h" +#include "BoundaryElementTopDist.h" +#include "BoundaryElementEdgeDist.h" +#include "BoundaryElementNormalDist.h" +#include "ElementUpdate.h" +#include "ElementUpdate_2d.h" +#include "ElementUpdate_3d.h" +#include "VelocityExt.h" +#include "VelocityExtFromVelocityField.h" + +using namespace AMDiS; + +////////////////////////////////////////////////////////////////////////////// +// +// class HL_SignedDist: +// -------------------- +// Holds functionality for +// - calculation of signed distance function for a level set function +// (calcSignedDistFct()) +// - extension of velocity from an interface on complete mesh in direction +// normal to the interface, where the interface is given implicitly +// by a level set function +// (calcVelocityExt()) +// +////////////////////////////////////////////////////////////////////////////// +class HL_SignedDist +{ + public: + MEMORY_MANAGED(HL_SignedDist); + + /** + * Constructor. + */ + HL_SignedDist(const char *name_, + int dim_, + bool doVelocityExt = false, + Flag velExtType_ = VEL_EXT) + : name(name_), + adaptInfo(NULL), + dim(dim_), + lS_DOF(NULL), + sD_DOF(NULL), + bound_DOF(NULL), + feSpace(NULL), + elUpdate(NULL), + bndElDist(NULL), + elLS(NULL), + phi(NULL), + velExt(NULL), + velExtType(velExtType_) + { + FUNCNAME("HL_SignedDist::HL_SignedDist"); + + TEST_EXIT(dim == 2 || dim == 3)("only works for dimension 2 and 3 !\n"); + + // ===== Read parameters from init file. ===== + GET_PARAMETER(0, name + "->infinity value", "%f", &inftyValue); + + TEST_EXIT(inftyValue > 1000)("illegal infinity value !\n"); + + // ===== Create functionality for velocity extension. ===== + if (doVelocityExt) { + if (velExtType.isSet(VEL_EXT)) + velExt = NEW VelocityExt(dim); + else + velExt = NEW VelocityExtFromVelocityField(dim); + } + }; + + /** + * Virtual destructor. + */ + virtual ~HL_SignedDist() + { + if (elUpdate) + DELETE elUpdate; + if (bndElDist) + DELETE bndElDist; + + if (elLS) + DELETE elLS; + if (phi) + DELETE phi; + + if (bound_DOF) + DELETE bound_DOF; + + DELETE velExt; + }; + + /** + * Calculates the signed distance function for the interface given + * implicitly by the zero level set of lS_DOF_. The result + * is stored in sD_DOF_. + * + * Alternative to level set function as DOF vector: + * If elFct != NULL, this ElementFunction is used as level set function. + * In this case: only calculation of distance function (positive sign) ! + */ + void calcSignedDistFct(AdaptInfo *adaptInfo_, + const DOFVector<double> *lS_DOF_, + DOFVector<double> *sD_DOF_, + ElementFunction<double> *elFct = NULL); + + /** + * Calculates the signed distance function for the interface given + * implicitly by the zero level set of lS_DOF_. The result + * is stored in lS_DOF_. + */ + void calcSignedDistFct(AdaptInfo *adaptInfo_, + DOFVector<double> *lS_DOF_); + + /** + * Calculates the extension of a velocity origVel_DOF_ from the interface + * on the complete mesh in direction normal to the interface. The interface + * is given implicitly as the zero level set of lS_DOF_. The result + * is stored in vel_DOF_. If calcSDFct is true, the signed distance function + * which is calculated during the extension of the velocity anyway is + * stored in sD_DOF_. + * + * Alternative to level set function as DOF vector: + * If elFct != NULL, this ElementFunction is used as level set function. + * In this case: only calculation of distance function (positive sign) ! + */ + void calcVelocityExt(AdaptInfo *adaptInfo_, + DOFVector<double> *origVel_DOF_, + DOFVector<double> *vel_DOF_, + const DOFVector<double> *lS_DOF_, + DOFVector<double> *sD_DOF_, + bool calcSDFct, + ElementFunction<double> *elFct = NULL); + + /** + * Calculates the extension of a velocity vel_DOF_ from the interface + * on the complete mesh in direction normal to the interface. The interface + * is given implicitly as the zero level set of lS_DOF_. The result + * is stored in origVel_DOF_. If calcSDFct is true, the signed distance + * function, which is calculated during the extension of the velocity + * anyway, is stored in lS_DOF_. + * + * Alternative to level set function as DOF vector: + * If elFct != NULL, this ElementFunction is used as level set function. + * In this case: only calculation of distance function (positive sign) ! + */ + void calcVelocityExt(AdaptInfo *adaptInfo_, + DOFVector<double> *vel_DOF_, + DOFVector<double> *lS_DOF_, + bool calcSDFct, + ElementFunction<double> *elFct = NULL); + + /** + * Calculates the extension of the velocity vectors in origVel_DOF_ + * from the interface on the complete mesh in direction normal to the + * interface. The interface is given implicitly as the zero level set of + * lS_DOF_. The result is stored in vel_DOF_. + * If calcSDFct is true, the signed distance function, + * which is calculated during the extension of the velocity anyway, is + * stored in sD_DOF_. + * + * Alternative to level set function as DOF vector: + * If elFct != NULL, this ElementFunction is used as level set function. + * In this case: only calculation of distance function (positive sign) ! + */ + void calcVelocityExt(AdaptInfo *adaptInfo_, + std::vector<DOFVector<double> *> origVel_DOF_, + std::vector<DOFVector<double> *> vel_DOF_, + const DOFVector<double> *lS_DOF_, + DOFVector<double> *sD_DOF_, + bool calcSDFct, + ElementFunction<double> *elFct = NULL); + + /** + * Calculates the extension of the velocity vectors in vel_DOF_ + * from the interface on the complete mesh in direction normal to the + * interface. The interface is given implicitly as the zero level set + * of lS_DOF_. The result is stored in vel_DOF_. + * If calcSDFct is true, the signed distance function, which is calculated + * during the extension of the velocity anyway, is stored in lS_DOF_. + * + * Alternative to level set function as DOF vector: + * If elFct != NULL, this ElementFunction is used as level set function. + * In this case: only calculation of distance function (positive sign) ! + */ + void calcVelocityExt(AdaptInfo *adaptInfo_, + std::vector<DOFVector<double> *> vel_DOF_, + DOFVector<double> *lS_DOF_, + bool calcSDFct, + ElementFunction<double> *elFct = NULL); + + /** + * Calculates the normal velocity for the velocity field velField_ and its + * extension from the interface on the complete mesh in direction normal + * to the interface. The interface is given implicitly as the + * zero level set of lS_DOF_. The result is stored in vel_DOF_. + * If calcSDFct is true, the signed distance function + * which is calculated during the extension of the velocity anyway is + * stored in sD_DOF_. + * + * Alternative to level set function as DOF vector: + * If elFct != NULL, this ElementFunction is used as level set function. + * In this case: only calculation of distance function (positive sign) ! + */ + void calcVelocityExtFromVelocityField( + AdaptInfo *adaptInfo_, + std::vector<DOFVector<double> *> &velField_, + DOFVector<double> *vel_DOF_, + const DOFVector<double> *lS_DOF_, + DOFVector<double> *sD_DOF_, + bool calcSDFct, + ElementFunction<double> *elFct = NULL); + + /** + * Calculates the normal velocity for the velocity field velField_ and its + * extension from the interface on the complete mesh in direction normal + * to the interface. The interface is given implicitly as the + * zero level set of lS_DOF_. The result is stored in vel_DOF_. + * If calcSDFct is true, the signed distance function + * which is calculated during the extension of the velocity anyway is + * stored in lS_DOF_. + * + * Alternative to level set function as DOF vector: + * If elFct != NULL, this ElementFunction is used as level set function. + * In this case: only calculation of distance function (positive sign) ! + */ + void calcVelocityExtFromVelocityField( + AdaptInfo *adaptInfo_, + std::vector<DOFVector<double> *> &velField_, + DOFVector<double> *vel_DOF_, + DOFVector<double> *lS_DOF_, + bool calcSDFct, + ElementFunction<double> *elFct = NULL); + + /** + * Print initial function: level set function defining the interface. + */ + void printLevelSetFct() + { + FileWriter *fileWriter = NEW FileWriter( + "SignedDist->level set fct output", + feSpace->getMesh(), + const_cast<DOFVector<double> *>(lS_DOF)); + fileWriter->writeFiles(adaptInfo, false); + + DELETE fileWriter; + }; + + /** + * Print signed distance function. + */ + void printSignedDistFct() + { + FileWriter *fileWriter = NEW FileWriter( + "SignedDist->result output", + feSpace->getMesh(), + sD_DOF); + fileWriter->writeFiles(adaptInfo, false); + + DELETE fileWriter; + }; + + protected: + /** + * Initialization. + */ + virtual void initialize(ElementFunction<double> *elFct = NULL); + + /** + * Initializes the boundary: calculation of the distance of boundary + * vertices to the interface. + * Interface is given by lS_DOF and result is stored in + * sD_DOF. + */ + virtual void initializeBoundary() = 0; + + /** + * Calculates the distance function and stores result in sD_DOF. + * Requirement: The boundary values are already set in sD_DOF. + */ + virtual void HL_updateIteration() = 0; + + /** + * Transforms the distance function into a signed distance function. + * The sign is given by the level set function lS_DOF. The + * signed distance function is stored in sD_DOF. + */ + void setSign(); + + /** + * Print boundary initialization (initial function for Hopf-Lax iteration). + */ + void printBoundInitFct() + { + FileWriter *fileWriter = NEW FileWriter( + "SignedDist->boundary initialization output", + feSpace->getMesh(), + sD_DOF); + fileWriter->writeFiles(adaptInfo, false); + + DELETE fileWriter; + }; + + public: + /** + * Flags to distinguish velocity extension types. + */ + static const Flag VEL_EXT; + static const Flag VEL_EXT_FROM_VEL_FIELD; + + protected: + /** + * Name of this instantiation of HL_SignedDist. + */ + std::string name; + + /** + * AdaptInfo. + */ + AdaptInfo *adaptInfo; + + /** + * Dimension. + */ + int dim; + + /** + * Level set function giving implicitely (as zero level set) the + * interface for which the signed distance function is calculated. + */ + const DOFVector<double> *lS_DOF; + + /** + * DOF vector for the calculated signed distance function. + * Also used during calculation. + */ + DOFVector<double> *sD_DOF; + + /** + * Marker for boundary vertices: + * 0 - vertex is no boundary vertex + * 1 - vertex is boundary vertex + */ + DOFVector<double> *bound_DOF; + + /** + * Finite element space. + */ + const FiniteElemSpace *feSpace; + + /** + * Initialization value "inifinity" for non-boundary vertices. + */ + double inftyValue; + + /** + * Pointer to ElementUpdate. Used for Hopf-Lax element update. + */ + ElementUpdate *elUpdate; + + /** + * Used for boundary vertex initialization: calculation of the distance + * to the interface for all vertices of a boundary element. + */ + BoundaryElementDist *bndElDist; + + /** + * Holds level set function and functionalities for intersection point + * calculation. + */ + ElementLevelSet *elLS; + + /* + * Level set function which implicitely gives the interface as its + * zero level set. + * This representation is needed for the use of class ElementLevelSet. + */ + ElementFunction<double> *phi; + + /** + * Object needed to extrapolate velocity from the interface. + */ + VelocityExt *velExt; + + /** + * Type of velocity extension method. Possible types: + * VEL_EXT - object of class VelocityExt + * VEL_EXT_FROM_VEL_FIELD - object of class VelocityExtFromVelocityField + */ + Flag velExtType; +}; + +#endif // HL_SIGNEDDIST diff --git a/AMDiS/Reinit/src/HL_SignedDistBornemann.h b/AMDiS/Reinit/src/HL_SignedDistBornemann.h new file mode 100644 index 00000000..648e97a7 --- /dev/null +++ b/AMDiS/Reinit/src/HL_SignedDistBornemann.h @@ -0,0 +1,916 @@ +#ifndef HL_SIGNEDDISTBORNEMANN +#define HL_SIGNEDDISTBORNEMANN + +#include "ElInfo.h" +#include "FixVec.h" +// #include "MemoryManager.h" +#include "Traverse.h" +#include <queue> +#include <time.h> + +#include "ElementLevelSet.h" + +#include "BoundaryElementDist.h" +/* #include "BoundaryElementTopDist.h" */ +/* #include "BoundaryElementEdgeDist.h" */ +/* #include "BoundaryElementNormalDist.h" */ +#include "ElementUpdate.h" +#include "ElementUpdate_2d.h" +#include "ElementUpdate_3d.h" +#include "HL_SignedDist.h" + +#include "SMIAdapter.h" +#include "smi.h" + +using namespace AMDiS; + +typedef struct +{ + int ElNum; + int VertNum; +} Vert_Struct; + +class HL_SignedDistBornemann : public HL_SignedDist +{ + public: + MEMORY_MANAGED(HL_SignedDistBornemann); + + /** + * Constructor. + */ + HL_SignedDistBornemann(const char *name_,int dim_) + : HL_SignedDist(name_, dim_), + smiAdapter(NULL) + { + FUNCNAME("HL_SignedDistBornemann::HL_SignedDistBornemann"); + + // ===== Read parameters from init file. ===== + GET_PARAMETER(0,name + "->tolerance", "%f", &tol); + GET_PARAMETER(0,name + "->count_how_often_saved_in_list", "%d", &count_in_list); + GET_PARAMETER(0,name + "->save_in_list->the ..th", "%d", &print_in_list); + + TEST_EXIT(tol > 0)("illegal tolerance !\n"); + }; + + protected: + /** + * Initializes the boundary: calculation of the distance of boundary + * vertices to the interface. + * Interface is given by \ref lS_DOF and result is stored in + * \ref sD_DOF. + */ + void initializeBoundary() + { + FUNCNAME("HL_SignedDistBornemann::initializeBoundary()"); + + TraverseStack stack; + FixVec<double, VERTEX> distVec(dim, NO_INIT); + int elStatus; + const int *elVertStatusVec; + int numIntersecPoints; + int NumVertIntPoints; + int ElNum; + clock_t time1; + clock_t time2; + double TIME; + + //=== transvering Mesh to SMI and add quantities + time1 = clock(); + Mesh_to_SMI_and_quantity (); + time2 = clock(); + TIME = TIME_USED(time1, time2); + + cout <<"Zeit zum Transformieren nach SMI: "<<TIME<<" sec.\n"; + + // ===== All non-boundary vertices are initialized with "infinity". ===== + sD_DOF->set(inftyValue); + + // ===== Traverse mesh and initialize boundary elements. ===== + const int nBasFcts = feSpace->getBasisFcts()->getNumber(); + DegreeOfFreedom *locInd = GET_MEMORY(DegreeOfFreedom, nBasFcts); + + ElInfo *elInfo = stack.traverseFirst(feSpace->getMesh(), + -1, + Mesh::CALL_LEAF_EL | + Mesh::FILL_BOUND | + Mesh::FILL_COORDS); + while(elInfo) { + + // Get local indices of vertices. + feSpace->getBasisFcts()->getLocalIndices( + const_cast<Element *>(elInfo->getElement()), + const_cast<DOFAdmin *>(feSpace->getAdmin()), + locInd); + + // Get element status. + elStatus = ElementLevelSet::createElementLevelSet(elInfo); + + //Get some information for creating the first list + + elVertStatusVec = ElementLevelSet::getElVertStatusVec(); + numIntersecPoints = ElementLevelSet::getNumElIntersecPoints(); + + //Beginn creating the first list + + NumVertIntPoints = ElementLevelSet::getNumVertIntPoints(); + ElNum = elInfo->getElement()->getIndex(); + + createLists( elStatus, elVertStatusVec, numIntersecPoints, ElNum, NumVertIntPoints, locInd); + + //end creating two lists + + // Is element cut by the interface ? + if (elStatus == ElementLevelSet::LEVEL_SET_BOUNDARY) { + + // Reset element distance vector. + for (int i=0; i<=dim; ++i) { + distVec[i] = inftyValue; + } + + // Mark all vertices as boundary vertices. + for (int i=0; i<=dim; ++i) { + (*bound_DOF)[locInd[i]] = 1.0; + } + + + + // Calculate distance for all vertices. + if (bndElDist->calcDistOnBoundaryElement(elInfo, distVec) != + ElementLevelSet::LEVEL_SET_BOUNDARY) { + ERROR_EXIT("error in distance calculation !\n"); + } + else { + + // If distance is smaller, correct to new distance. + for (int i=0; i<=dim; ++i) { + if ((*sD_DOF)[locInd[i]] > distVec[i]) { + (*sD_DOF)[locInd[i]] = distVec[i]; + } + } + } + } // end of: elStatus == ElementLevelSet::LEVEL_SET_BOUNDARY + + else if (ElementLevelSet::getNumVertIntPoints() != 0){ + // Interface cuts element only in vertices. + elVertStatusVec = ElementLevelSet::getElVertStatusVec(); + + for (int i=0; i<=dim; ++i) { + if (elVertStatusVec[i] == ElementLevelSet::LEVEL_SET_BOUNDARY) { + (*bound_DOF)[locInd[i]] = 1.0; + (*sD_DOF)[locInd[i]] = 0.0; + } + } + } + + elInfo = stack.traverseNext(elInfo); + } // end of: mesh traverse + + FREE_MEMORY(locInd, DegreeOfFreedom, nBasFcts); + + return; + }; + + /** + * Calculates the distance function and stores result in sD_DOF. + * Requirement: The boundary values are already set in \ref sD_DOF. + */ + void HL_updateIteration() + { + int numNodes; + int *nodeIndices; + int max_q3 = 0; + int max_q4 = 0; + int sum_q3 = 0; + int sum_q4 = 0; + clock_t time1; + clock_t time2; + double TIME; + + SMI_Get_all_nodes(1,1,const_cast<DegreeOfFreedom*>(&numNodes),&nodeIndices); + int *values_q3 = new int [numNodes]; + int *values_q4 = new int [numNodes]; + + GET_PARAMETER(0,"SignedDist->count updates", "%d", &count_updates); + + time1 = clock(); + traverseListElement(); + time2 = clock(); + TIME = TIME_USED(time1, time2); + + cout<<"Zeit zum durchlaufen der ersten Liste: "<<TIME<<" sec.\n\n"; + + time1 = clock(); + traversingListELVert ( sD_DOF ); + time2 = clock(); + TIME = TIME_USED(time1,time2); + + cout<<"Zeit zum Durchlaufen der zweiten Liste: "<<TIME<<" sec.\n\n"; + + std::string smiOutFile; + GET_PARAMETER(0, "SignedDist->count updates->output->filename", &smiOutFile); + cout << "count updates Ausgabe-Datei: " << smiOutFile.c_str() << "\n\n"; + + ofstream out (smiOutFile.c_str()); + + SMI_Get_quantity_values(1,1,3,SMI_TYPE_INT,1,numNodes,nodeIndices,values_q3); + SMI_Get_quantity_values(1,1,4,SMI_TYPE_INT,1,numNodes,nodeIndices,values_q4); + + for (int i=0; i<numNodes; i++) + { + out<<nodeIndices[i]<<" "<<values_q3[i]<<" "<<values_q4[i]<<"\n"; + + if(max_q3 < values_q3[i]) + { + max_q3 = values_q3[i]; + } + if(max_q4 < values_q4[i]) + { + max_q4 = values_q4[i]; + } + sum_q3 = sum_q3 + values_q3[i]; + sum_q4 = sum_q4 + values_q4[i]; + } + + out<<"\n\n maximale Anzahl an versuchten Updates auf einem Knoten: "<<max_q3<<"\n maximale Anzahl an durchgefuehrten Updates auf einem Knoten: "<<max_q4<<"\n"; + out<<"\n Summe aller versuchten Updates: "<<sum_q3<<"\n Summe aller durchgefuehrten updates: "<<sum_q4<<"\n"; + + out<<"Anzahl an Knoten: "<<numNodes<<"\n"; + + out.close(); + + + + + SMI_End_write_transaction(1,1); + + return; + }; + + /** + *function for transvering Mesh to SMi an Adding the quantities + **/ + + void Mesh_to_SMI_and_quantity () + { + if(!smiAdapter) + { + smiAdapter = NEW SMIAdapter(1,1,const_cast<FiniteElemSpace*>(feSpace),1,-1); + } + + // cout << "\n\n\tSMI-Adapter angelegt !\n\n"; + + //====== transfer Mesh to SMI ====================== + + smiAdapter->addNeighbourInfo(); + + // cout << "\n\n\tNachbarschafts-Infos in SMI ergaenzt !\n\n"; + + smiAdapter-> transferMeshToSMI(); + + // cout << "\n\n\tGitter nach SMI geschrieben !\n\n"; + + SMI_Begin_write_transaction(1,1); + + int nul=0; + //which pair of element and node is saved in list + SMI_Add_quantity(1, 1, 1, SMI_LOC_ELEM, SMI_TYPE_INT,dim+1, &nul); + //which node is a boundary-node + SMI_Add_quantity(1,1,2,SMI_LOC_NODE, SMI_TYPE_INT,1,&nul); + //saves the number of tried updates + SMI_Add_quantity(1,1,3,SMI_LOC_NODE,SMI_TYPE_INT,1,&nul); + //saves the number of updates + SMI_Add_quantity(1,1,4,SMI_LOC_NODE,SMI_TYPE_INT,1,&nul); + //how often a node is saved in the second list + SMI_Add_quantity(1,1,5,SMI_LOC_NODE,SMI_TYPE_INT,1,&nul); + + // cout << "\n\n\tQuantities in SMI ergaenzt !\n\n"; + } + + //Begin fuction for creating two lists + //* + + void createLists(const int elStatus, + const int *elVertStatusVec, + const int numIntersecPoints, + const int ElNum, + const int NumVertIntPoints, + const DegreeOfFreedom *locInd) + { + Vert_Struct vertStruct; + int *sv = new int [dim+1]; + int value=0; + int value_q5 = 0; + int * nodeIndices; + /* int *nodes = new int [dim+1]; */ + + if (elStatus == ElementLevelSet::LEVEL_SET_BOUNDARY) + { + List_Element.push( ElNum ); + + //saving which nodes are boundary-nodes + for (int i=0; i<=dim; i++) + { + sv[i] = 1; + } + SMI_Get_elems(1,1,1,const_cast<DegreeOfFreedom*>(&ElNum),NULL,&nodeIndices,NULL,NULL); + SMI_Set_quantity_values(1,1,2,SMI_TYPE_INT,1,3,nodeIndices,sv); + } + //if the elemet isn't a boundary-element, but the interface cuts the FE in two nodes + else if (NumVertIntPoints == dim) + { + for (int i=0; i<=dim; i++) + { + if (elVertStatusVec[i] == ElementLevelSet::LEVEL_SET_BOUNDARY && elVertStatusVec[(i+1)%3] ==ElementLevelSet::LEVEL_SET_BOUNDARY) + { + value = 1; + SMI_Get_elems(1,1,1,const_cast<DegreeOfFreedom*>(&ElNum),NULL,&nodeIndices,NULL,NULL); + SMI_Set_quantity_values(1,1,2,SMI_TYPE_INT,1,1,const_cast<DegreeOfFreedom*>(&nodeIndices[i]),&value); + SMI_Set_quantity_values(1,1,2,SMI_TYPE_INT,1,1,const_cast<DegreeOfFreedom*>(&nodeIndices[(i+1)%3]),&value); + + //saving which node of this element will be included into the second list + //part 1 + for (int j=0; j<=dim; j++) //ACHTUNG: aus < ein <= gemacht + { + sv[j] = 0; + } + sv[(i+2)%3] = 1; + + //include pair into the second list + vertStruct.ElNum = ElNum ; + vertStruct.VertNum = locInd[(i+2)%3]; + List_El_Vert.push( vertStruct ); + + //saving which node of this element will be included into the second list + //part 2 + SMI_Set_quantity_values(1,1,1,SMI_TYPE_INT,dim+1,1,const_cast<DegreeOfFreedom*>(&ElNum),sv); + + //counts how often a node is saved in the second list + if(count_in_list == 1) + { + SMI_Get_quantity_values(1,1,5,SMI_TYPE_INT,1,1,const_cast<DegreeOfFreedom*>(&vertStruct.VertNum),&value_q5); + value_q5 = value_q5 + 1; + SMI_Set_quantity_values(1,1,5,SMI_TYPE_INT,1,1,const_cast<DegreeOfFreedom*>(&vertStruct.VertNum),&value_q5); + } + } + } + } + else + { + //saving that none of the nodes of this element is saved in the second list + for (int i=0; i<=dim; i++) + { + sv[i] = 0; + } + SMI_Set_quantity_values(1,1,1,SMI_TYPE_INT,dim+1,1,const_cast<DegreeOfFreedom*>(&ElNum),sv); + } + delete [] sv; + }; + +//End function for creating two lists +// + +//function for traversing the list "List_Element" +// + + void traverseListElement() + { + Vert_Struct vertStruct; + + int Element; + int *neighbour=new int[dim+1]; + int *oppVertices=new int[dim+1]; + int *values=new int[dim*(dim+1)]; + int *value = new int [dim+1]; + int value_q2; + int value_q5; + int *nodeIndices; + + while (List_Element.size() != 0) + { + Element = List_Element.front(); + smiAdapter->getNeighbourInfo(Element, neighbour, oppVertices); + + for ( int i=0; i<=dim; i++) + { + SMI_Get_elems(1,1,1,&neighbour[i],NULL,&nodeIndices, NULL,NULL); + SMI_Get_quantity_values(1,1,1,SMI_TYPE_INT,dim+1,1,&neighbour[i],value); + SMI_Get_quantity_values(1,1,2,SMI_TYPE_INT,1,1,&nodeIndices[oppVertices[i]],&value_q2); + if (value[oppVertices[i]] == 0 && value_q2 == 0) + { + vertStruct.ElNum = neighbour[i] ; + vertStruct.VertNum = nodeIndices[oppVertices[i]] ; + List_El_Vert.push( vertStruct ); + value[oppVertices[i]] = 1; + + //counts how often a node is saved in the second list + if(count_in_list == 1) + { + SMI_Get_quantity_values(1,1,5,SMI_TYPE_INT,1,1,const_cast<DegreeOfFreedom*>(&vertStruct.VertNum),&value_q5); + value_q5 = value_q5 + 1; + SMI_Set_quantity_values(1,1,5,SMI_TYPE_INT,1,1,const_cast<DegreeOfFreedom*>(&vertStruct.VertNum),&value_q5); + } + } + SMI_Set_quantity_values(1,1,1,SMI_TYPE_INT,dim+1,1,&neighbour[i],value); + } + List_Element.pop(); + } + delete [] neighbour; + delete [] oppVertices; + delete [] values; + delete [] value; + }; + + //end of the function for traversing the list "List_Element" + // + + + /* + *gets the neighbour according to the node "VertNum_in" an two of its nodes + *returns "false" if the called neighbour exists and "true" if not + */ + + bool getNextNeighbour (const int ElNum_in, const int Vert_Up_in, const int VertNum_in, int &ElNum_out, int &VertNum_1_out, int &VertNum_2_out) + { + int *neighbour = new int[dim+1]; + int *oppVertices = new int[dim+1]; + int *nodeIndicesOfElem; + int locVertNum; + + smiAdapter->getNeighbourInfo(ElNum_in, neighbour,oppVertices); + + //which local node is the node "VertNum_in"? + SMI_Get_elems(1,1,1,const_cast<DegreeOfFreedom*>(&(ElNum_in)),NULL,&nodeIndicesOfElem, NULL, NULL); + for (int i=0; i<=dim; i++) + { + if(nodeIndicesOfElem[i] == VertNum_in) + { + locVertNum = i; + } + } + + ElNum_out = neighbour [locVertNum]; + + + + SMI_Get_elems(1,1,1,const_cast<DegreeOfFreedom*>(&(ElNum_out)),NULL,&nodeIndicesOfElem, NULL, NULL); + VertNum_1_out = nodeIndicesOfElem [oppVertices[locVertNum]]; + for (int i=0; i<=dim; i++) + { + if (nodeIndicesOfElem[i] != Vert_Up_in && nodeIndicesOfElem[i] != VertNum_1_out) + { + VertNum_2_out = nodeIndicesOfElem[i]; + } + } + + delete [] neighbour; + delete [] oppVertices; + + if (ElNum_out == -1) + { + return true; + } + + return false; + + } + + + /* + * checking whetherthe element "ElNum_in" has to be included into the second list + *if yes it will be included + */ + + void includeIntoList (int ElNum_in, int VertNum_1_in, int VertNum_2_in) + { + Vert_Struct vertStruct_0; + Vert_Struct vertStruct_1; + + int *nodeIndices; + int *valuesINT = new int[dim+1]; + int *locVert = new int[dim]; + int value_q2; + int value_q5; + + if(ElNum_in != -1) + { + + SMI_Get_quantity_values(1,1,1,SMI_TYPE_INT,dim+1,1,const_cast<DegreeOfFreedom*>(&ElNum_in),valuesINT); + + //which locla node is the node VerNum_1_in, which one is the node VertNum_2_in? + SMI_Get_elems (1, 1, 1, &ElNum_in, NULL, &nodeIndices, NULL, NULL); + for (int i=0; i<=dim; i++) + { + if(nodeIndices[i] == VertNum_1_in) + { + locVert[0] = i; + } + if(nodeIndices[i] == VertNum_2_in) + { + locVert[1] = i; + } + } + + //if the pair of element and node isn't saved in the second List an if it isn't a boundary-node include into second list + SMI_Get_quantity_values(1,1,2,SMI_TYPE_INT,1,1,&VertNum_1_in, &value_q2); + if(valuesINT[locVert[0]] == 0 && value_q2 == 0) + { + vertStruct_0.ElNum = ElNum_in; + vertStruct_0.VertNum = VertNum_1_in; + List_El_Vert.push( vertStruct_0 ); + + valuesINT[locVert[0]] = 1; + SMI_Set_quantity_values(1,1,1,SMI_TYPE_INT,dim+1,1,&ElNum_in,&valuesINT); + + //counts how often a node is saved in the second list + if(count_in_list == 1) + { + SMI_Get_quantity_values(1,1,5,SMI_TYPE_INT,1,1,const_cast<DegreeOfFreedom*>(&vertStruct_0.VertNum),&value_q5); + value_q5 = value_q5 + 1; + SMI_Set_quantity_values(1,1,5,SMI_TYPE_INT,1,1,const_cast<DegreeOfFreedom*>(&vertStruct_0.VertNum),&value_q5); + } + } + + //if the pair of element and node isn't saved in the second List an if it isn't a boundary-node include into second list + SMI_Get_quantity_values(1,1,2,SMI_TYPE_INT,1,1,&VertNum_2_in, &value_q2); + if(valuesINT[locVert[1]] == 0 && value_q2 == 0) + { + vertStruct_1.ElNum = ElNum_in; + vertStruct_1.VertNum = VertNum_2_in; + List_El_Vert.push( vertStruct_1 ); + + valuesINT[locVert[1]] = 1; + SMI_Set_quantity_values(1,1,1,SMI_TYPE_INT,dim+1,1,&ElNum_in,&valuesINT); + + //counts how often a node is saved in the second list + if(count_in_list == 1) + { + SMI_Get_quantity_values(1,1,5,SMI_TYPE_INT,1,1,const_cast<DegreeOfFreedom*>(&vertStruct_1.VertNum),&value_q5); + value_q5 = value_q5 + 1; + SMI_Set_quantity_values(1,1,5,SMI_TYPE_INT,1,1,const_cast<DegreeOfFreedom*>(&vertStruct_1.VertNum),&value_q5); + } + } + } + + delete [] valuesINT; + delete [] locVert; + } + + + /** + *function needed in the function "traversingListELVert" + **/ + int getNext_node_l_r (int elem_l_r_in, int node_l_r_in, const int Vert) + { + int *nodeIndicesOfElem; + + SMI_Get_elems(1,1,1,const_cast<DegreeOfFreedom*>(&elem_l_r_in),NULL,&nodeIndicesOfElem, NULL, NULL); + for (int i=0; i<=dim; i++) + { + if(nodeIndicesOfElem[i] != Vert && nodeIndicesOfElem[i] != node_l_r_in) + { + return nodeIndicesOfElem[i]; + } + } + } + + //Beginn function for traversing the list "List_El_Vert" + // + + void traversingListELVert ( DOFVector<double> *boundVal_DOF ) + { + Vert_Struct vertStruct_0; + Vert_Struct vertStruct_1; + + Vert_Struct El_Vert; + + int Vert; + + + + //int * new_neighbour_l = new int [dim+1]; + //int *new_neighbour_r = new int [dim+1]; + // int *oppVertices_l = new int[dim+1]; + //int *oppVertices_r = new int[dim+1]; + + int locVert; + int value_q3; + int value_q4; + int value_q5; + int counter = 0; + int *nodeIndices; + double *coords = new double [(dim+1)*dim]; + int *valuesINT=new int[dim+1]; + double update; + int value_q2; + int counter_list = 0; + FixVec<WorldVector<double> *, VERTEX> coordsOfNodes(dim); + for ( int i=0; i<=dim; i++) + { + coordsOfNodes[i] = new WorldVector<double>; + } + FixVec<double,VERTEX> boundVal(dim,NO_INIT); + WorldVector<double> helpVec; + + + + while (List_El_Vert.size() != 0) + { + El_Vert = List_El_Vert.front(); + Vert = El_Vert.VertNum; + + SMI_Get_elems (1, 1, 1, &(El_Vert.ElNum), NULL, &(nodeIndices), NULL, NULL); + SMI_Get_nodes (1, 1, 3, dim, nodeIndices, coords); + + counter = 0; + for (int i=0; i<=dim; i++) + { + if (nodeIndices[i] == El_Vert.VertNum) + { + (*(coordsOfNodes[dim]))[0]=coords[i*2]; + (*(coordsOfNodes[dim]))[1]=coords[i*2+1]; + boundVal[dim] = (*boundVal_DOF)[nodeIndices[i]]; + locVert = i; + } + else + { + (*(coordsOfNodes[counter]))[0]=coords[i*2]; + (*(coordsOfNodes[counter]))[1]=coords[i*2+1]; + boundVal[counter] = (*boundVal_DOF)[nodeIndices[i]]; + counter = counter+1; + } + } + + update = elUpdate->calcElementUpdate( coordsOfNodes, boundVal ); + + if(count_updates == 1) + { + SMI_Get_quantity_values(1,1,3,SMI_TYPE_INT,1,1,&nodeIndices[locVert],&value_q3); + value_q3 = value_q3 + 1; + SMI_Set_quantity_values(1,1,3,SMI_TYPE_INT,1,1,const_cast<DegreeOfFreedom*>(&nodeIndices[locVert]),&value_q3); + } + + if (update < (*boundVal_DOF)[El_Vert.VertNum] && ((*boundVal_DOF)[El_Vert.VertNum]-update) > tol) + { + (*boundVal_DOF)[El_Vert.VertNum] = update; + + if(count_updates == 1) + { + SMI_Get_quantity_values(1,1,4,SMI_TYPE_INT,1,1,&nodeIndices[locVert],&value_q4); + value_q4 = value_q4 + 1; + SMI_Set_quantity_values(1,1,4,SMI_TYPE_INT,1,1,const_cast<DegreeOfFreedom*>(&nodeIndices[locVert]),&value_q4); + } + search_and_include_comb(El_Vert.ElNum, Vert, nodeIndices); + } + + SMI_Get_quantity_values(1,1,1,SMI_TYPE_INT,dim+1,1,&El_Vert.ElNum, valuesINT); + List_El_Vert.pop(); + valuesINT[locVert] = 0; + SMI_Set_quantity_values(1,1,1,SMI_TYPE_INT,dim+1,1,&El_Vert.ElNum, valuesINT); + + //counts how often a node is saved in the second list + if(count_in_list == 1) + { + SMI_Get_quantity_values(1,1,5,SMI_TYPE_INT,1,1,const_cast<DegreeOfFreedom*>(& El_Vert.VertNum),&value_q5); + value_q5 = value_q5 - 1; + SMI_Set_quantity_values(1,1,5,SMI_TYPE_INT,dim+1,1,const_cast<DegreeOfFreedom*>(& El_Vert.VertNum),&value_q5); + } + + if(count_in_list == 1) + { + counter_list++; + if(counter_list % print_in_list == 0) + { + print_quantity_5(counter_list); + } + } + } + +// delete [] new_neighbour_l; +// delete [] new_neighbour_r; +// delete [] oppVertices_l; +// delete [] oppVertices_r; + delete [] coords; + delete [] valuesINT; + for ( int i=0; i<Global::getGeo(VERTEX,dim); i++) + { + delete coordsOfNodes[i]; + } + }; + + //End of the function for traversing the list "List_El_Vert" + // + + void search_and_include_comb(int ElNum, int Vert, int *nodeIndices) + { + bool stop_l = false; + bool stop_r = false; + int neighbour_l; + int neighbour_r; + int Vert_1_l; + int Vert_2_l; + int Vert_1_r; + int Vert_2_r; + int locVert; + int counter; + int elem_l; + int elem_r; + int node_l; + int node_r; + + //here the process of including elements/nodes into the second list + stop_l = false; + stop_r = false; + + elem_l = ElNum; + if (elem_l == -1) + { + stop_l = true; + } + elem_r = ElNum; + if (elem_r == -1) + { + stop_r = true; + } + + counter = 0; + for (int i=0; i<=dim; i++) + { + if(nodeIndices[i] != Vert && counter == 1) + { + node_r = nodeIndices[i]; + counter = counter + 1; + } + if(nodeIndices[i] != Vert && counter == 0) + { + node_l = nodeIndices[i]; + counter = counter + 1; + } + + if(nodeIndices[i] == Vert) + { + locVert = i; + } + } + + while (!stop_l || !stop_r) + { + //get next neighbour + if (!stop_l) + { + stop_l = getNextNeighbour (elem_l, Vert, node_l, neighbour_l, Vert_1_l, Vert_2_l); + } + if(!stop_r) + { + stop_r = getNextNeighbour (elem_r, Vert, node_r, neighbour_r, Vert_1_r, Vert_2_r); + } + + if(neighbour_l == elem_r) + { + break; + } + + //indclude into the second list (only if possible) + if (!stop_l) + { + includeIntoList (neighbour_l, Vert_1_l, Vert_2_l); + if(neighbour_l == neighbour_r) + { + break; + } + //"elem_l", "node_l", "elem_r", "node_r" have to be set on the next elements + node_l = getNext_node_l_r(elem_l, node_l,Vert); + elem_l = neighbour_l; + } + if (!stop_r && neighbour_l != neighbour_r) + { + includeIntoList (neighbour_r, Vert_1_r, Vert_2_r); + //"elem_l", "node_l", "elem_r", "node_r" have to be set on the next elements + node_r = getNext_node_l_r(elem_r, node_r, Vert); + elem_r = neighbour_r; + } + } + } + + //================================== + void print_quantity_5 (int cntr) + { + int numNodes; + int*nodeIndices; + double *coords = new double[dim]; + SMI_Get_all_nodes(1,1,const_cast<DegreeOfFreedom*>(&numNodes),&nodeIndices); + int *values_q5 = new int [numNodes]; + + std::string q5_OutFile_0; + std::string q5_OutFile_1; + std::string q5_OutFile_2; + std::string q5_OutFile_3; + std::string q5_OutFile_4; + + GET_PARAMETER(0, "SignedDist->count saving->output->filename_0", &q5_OutFile_0); + GET_PARAMETER(0, "SignedDist->count saving->output->filename_1", &q5_OutFile_1); + GET_PARAMETER(0, "SignedDist->count saving->output->filename_2", &q5_OutFile_2); + GET_PARAMETER(0, "SignedDist->count saving->output->filename_3", &q5_OutFile_3); + GET_PARAMETER(0, "SignedDist->count saving->output->filename_4", &q5_OutFile_4); + + + char cntrStr[20]; + sprintf(cntrStr, "%d", cntr); + q5_OutFile_0 += cntrStr; + q5_OutFile_1 += cntrStr; + q5_OutFile_2 += cntrStr; + q5_OutFile_3 += cntrStr; + q5_OutFile_4 += cntrStr; + + cout << "count saving Ausgabe-Datei_0: " << q5_OutFile_0.c_str() << "\n\n"; + cout << "count saving Ausgabe-Datei_1: " << q5_OutFile_1.c_str() << "\n\n"; + cout << "count saving Ausgabe-Datei_2: " << q5_OutFile_2.c_str() << "\n\n"; + cout << "count saving Ausgabe-Datei_3: " << q5_OutFile_3.c_str() << "\n\n"; + cout << "count saving Ausgabe-Datei_4: " << q5_OutFile_4.c_str() << "\n\n"; + + ofstream out_0 (q5_OutFile_0.c_str()); + ofstream out_1 (q5_OutFile_1.c_str()); + ofstream out_2 (q5_OutFile_2.c_str()); + ofstream out_3 (q5_OutFile_3.c_str()); + ofstream out_4 (q5_OutFile_4.c_str()); + + SMI_Get_quantity_values(1,1,5,SMI_TYPE_INT,1,numNodes,nodeIndices,values_q5); + + for (int i=0; i<numNodes; i++) + { + + SMI_Get_nodes (1,1,1,dim,const_cast<DegreeOfFreedom*>(&nodeIndices[i]),coords); + + if(values_q5[i] == 0) + { + out_0<<coords[0]<<" "<<coords[1]<<"\n"; + } + if(values_q5[i] == 1) + { + out_1<<coords[0]<<" "<<coords[1]<<"\n"; + } + if(values_q5[i] == 2) + { + out_2<<coords[0]<<" "<<coords[1]<<"\n"; + } + if(values_q5[i] == 3) + { + out_3<<coords[0]<<" "<<coords[1]<<"\n"; + } + if(values_q5[i] >= 4) + { + out_4<<coords[0]<<" "<<coords[1]<<"\n"; + } + + + } + + out_0.close(); + out_1.close(); + out_2.close(); + out_3.close(); + out_4.close(); + + delete [] coords; + delete [] values_q5; + } + //==================================== + + protected: + /** + * Tolerance for Hopf-Lax update iteration loop. + */ + double tol; + + /** + *is needed for transfering the mesh to SMI + */ + SMIAdapter *smiAdapter; + + /** + * in this list boundary-elements are saved; + * is needed for creating the list "List_El_Vert" + */ + queue<int> List_Element; + + /** + *in this list structs filled with element-number and vertex-number are saved; + *is needed for traversing the mesh efficiently + */ + queue<Vert_Struct> List_El_Vert; + + /** + *0 ->do not count updates + *1 ->count updates + **/ + int count_updates; + + /** + *1 -> it will be count how often a node is saved in the second list + *0 ->it will not be count + **/ + int count_in_list; + + int print_in_list; +}; + +#endif // HL_SIGNEDDISTBORNEMANN diff --git a/AMDiS/Reinit/src/HL_SignedDistLevels.cc b/AMDiS/Reinit/src/HL_SignedDistLevels.cc new file mode 100644 index 00000000..4400e22d --- /dev/null +++ b/AMDiS/Reinit/src/HL_SignedDistLevels.cc @@ -0,0 +1,1360 @@ +#include "HL_SignedDistLevels.h" + +#include "VelocityExtFromVelocityField.h" + +void +HL_SignedDistLevels::initializeBoundary() +{ + FUNCNAME("HL_SignedDistLevels::initializeBoundary()"); + + TraverseStack stack; + FixVec<double, VERTEX> distVec(dim, NO_INIT); + int elStatus; + const int *elVertStatusVec; + int NumVertIntPoints; + int ElNum; + clock_t time1; + clock_t time2; + double TIME; + + //=== transvering Mesh to SMI and add quantities + time1 = clock(); + Mesh_to_SMI_and_quantity(); + time2 = clock(); + TIME = TIME_USED(time1, time2); + + cout <<"Zeit zum Transformieren nach SMI: "<<TIME<<" sec.\n"; + + // ===== All non-boundary vertices are initialized with "infinity". ===== + sD_DOF->set(inftyValue); + + // ===== Traverse mesh and initialize boundary elements. ===== + const int nBasFcts = feSpace->getBasisFcts()->getNumber(); + DegreeOfFreedom *locInd = GET_MEMORY(DegreeOfFreedom, nBasFcts); + + ElInfo *elInfo; + if (velExt && velExtType.isSet(VEL_EXT_FROM_VEL_FIELD)) { + elInfo = stack.traverseFirst(feSpace->getMesh(), + -1, + Mesh::CALL_LEAF_EL | + Mesh::FILL_BOUND | + Mesh::FILL_COORDS | + Mesh::FILL_GRD_LAMBDA); + } + else { + elInfo = stack.traverseFirst(feSpace->getMesh(), + -1, + Mesh::CALL_LEAF_EL | + Mesh::FILL_BOUND | + Mesh::FILL_COORDS); + } + while(elInfo) { + + // Set elInfo in case velocity extension from velocity field is used. + if (velExt && velExtType.isSet(VEL_EXT_FROM_VEL_FIELD)) { + ((VelocityExtFromVelocityField *)velExt)->setElInfo(elInfo); + } + + // Get local indices of vertices. + feSpace->getBasisFcts()->getLocalIndices( + const_cast<Element *>(elInfo->getElement()), + const_cast<DOFAdmin *>(feSpace->getAdmin()), + locInd); + + // Get element status. + elStatus = elLS->createElementLevelSet(elInfo); + + //Get some information for creating the first list + + elVertStatusVec = elLS->getElVertStatusVec(); + + //Beginn creating the first list + + NumVertIntPoints = elLS->getNumVertIntPoints(); + ElNum = elInfo->getElement()->getIndex(); + + createFirstList( elStatus, elVertStatusVec, ElNum, NumVertIntPoints); + + //end creating the first list + + // Is element cut by the interface ? + if (elStatus == ElementLevelSet::LEVEL_SET_BOUNDARY) { + + // Reset element distance vector. + for (int i=0; i<=dim; ++i) { + distVec[i] = inftyValue; + } + + // Mark all vertices as boundary vertices. + for (int i=0; i<=dim; ++i) { + (*bound_DOF)[locInd[i]] = 1.0; + } + + // Calculate distance for all vertices. + if (bndElDist->calcDistOnBoundaryElement(elInfo, distVec) != + ElementLevelSet::LEVEL_SET_BOUNDARY) { + ERROR_EXIT("error in distance calculation !\n"); + } + else { + + // If distance is smaller, correct to new distance. + for (int i=0; i<=dim; ++i) { + if ((*sD_DOF)[locInd[i]] > distVec[i]) { + (*sD_DOF)[locInd[i]] = distVec[i]; + //If distance is corrected, calculate new velocity. + if(velExt != NULL) + { + velExt->calcVelocityBoundary(locInd, i); + } + } + } + } + } // end of: elStatus == ElementLevelSet::LEVEL_SET_BOUNDARY + + else if (elLS->getNumVertIntPoints() != 0){ +// // Interface cuts element only in vertices. +// elVertStatusVec = elLS->getElVertStatusVec(); + +// for (int i=0; i<=dim; ++i) { +// if (elVertStatusVec[i] == ElementLevelSet::LEVEL_SET_BOUNDARY) { +// (*bound_DOF)[locInd[i]] = 1.0; +// (*sD_DOF)[locInd[i]] = 0.0; +// } +// } + + ERROR_EXIT("intersection point is element vertex. should never happen !\n"); + } + + elInfo = stack.traverseNext(elInfo); + } // end of: mesh traverse + + FREE_MEMORY(locInd, DegreeOfFreedom, nBasFcts); + + return; +} + +void +HL_SignedDistLevels::Mesh_to_SMI_and_quantity() +{ + if(!smiAdapter) + { + smiAdapter = NEW SMIAdapter(1, 1, + const_cast<FiniteElemSpace*>(feSpace), + 1, -1); + } + + // cout << "\n\n\tSMI-Adapter angelegt !\n\n"; + + //====== transfer Mesh to SMI ====================== + + smiAdapter->addNeighbourInfo(); + + // cout << "\n\n\tNachbarschafts-Infos in SMI ergaenzt !\n\n"; + + smiAdapter-> transferMeshToSMI(); + + // cout << "\n\n\tGitter nach SMI geschrieben !\n\n"; + + int smiError = SMI_Begin_write_transaction(1,1); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Begin_write_transaction() failed with error %d\n", smiError); + + int nul = 0; + int *null = new int [dim+1]; + for (int i=0; i<=dim; i++) + { + null[i] = nul; + } + + //which pair of element and node is saved in list + smiError = + SMI_Add_quantity(1, 1, 1, SMI_LOC_ELEM, SMI_TYPE_INT, dim+1, null); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Add_quantity() failed with error %d\n", smiError); + + //which node is a boundary-node + smiError = SMI_Add_quantity(1, 1, 2, SMI_LOC_NODE, SMI_TYPE_INT, 1, &nul); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Add_quantity() failed with error %d\n", smiError); + + //saves the number of tried updates + smiError = SMI_Add_quantity(1, 1, 3, SMI_LOC_NODE, SMI_TYPE_INT, 1, &nul); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Add_quantity() failed with error %d\n", smiError); + + //saves the number of updates + smiError = SMI_Add_quantity(1, 1, 4, SMI_LOC_NODE, SMI_TYPE_INT, 1, &nul); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Add_quantity() failed with error %d\n", smiError); + + //how often a node is saved in the second list + smiError = SMI_Add_quantity(1, 1, 5, SMI_LOC_NODE, SMI_TYPE_INT, 1, &nul); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Add_quantity() failed with error %d\n", smiError); + + //saves the level of an element + smiError = SMI_Add_quantity(1, 1, 6, SMI_LOC_ELEM, SMI_TYPE_INT, 1, + &inftyValue); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Add_quantity() failed with error %d\n", smiError); + + // cout << "\n\n\tQuantities in SMI ergaenzt !\n\n"; + + delete [] null; +} + +void +HL_SignedDistLevels::createFirstList(const int elStatus, + const int *elVertStatusVec, + int ElNum, + const int NumVertIntPoints) +{ + int *sv = new int[dim+1]; + int *nodeIndices; + int nul = 0; + int smiError; + + if (elStatus == ElementLevelSet::LEVEL_SET_BOUNDARY) + { + List_Element.push(ElNum); + + smiError = + SMI_Set_quantity_values(1, 1, 6, SMI_TYPE_INT, 1, 1, &ElNum, &nul); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Set_quantity_values() failed with error %d\n", smiError); + + //saving which nodes are boundary-nodes + for (int i=0; i<=dim; i++) + { + sv[i] = 1; + } + + smiError = + SMI_Get_elems(1, 1, 1, const_cast<DegreeOfFreedom*>(&ElNum), + NULL, &nodeIndices, NULL, NULL); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_elems() failed with error %d\n", smiError); + + smiError = + SMI_Set_quantity_values(1, 1, 2, SMI_TYPE_INT, 1, 3, nodeIndices, sv); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Set_quantity_values() failed with error %d\n", smiError); + } + //if the elemet isn't a boundary-element, but the interface cuts the FE in two nodes +// else if (NumVertIntPoints == dim) +// { +// List_Element.push( ElNum ); + +// smiError = +// SMI_Set_quantity_values(1, 1, 6, SMI_TYPE_INT, 1, 1, &ElNum, &nul); +// TEST_EXIT(smiError == SMI_OK) +// ("SMI_Set_quantity_values() failed with error %d\n", smiError); + +// //saving which nodes are boundary-nodes +// for (int i=0; i<=dim; i++) +// { +// if(elVertStatusVec[i] == ElementLevelSet::LEVEL_SET_BOUNDARY) +// { +// sv[i] = 1; +// } +// else +// { +// sv[i] = 0; +// } + +// smiError = +// SMI_Get_elems(1, 1, 1, const_cast<DegreeOfFreedom*>(&ElNum), +// NULL, &nodeIndices, NULL, NULL); +// TEST_EXIT(smiError == SMI_OK) +// ("SMI_Get_elems() failed with error %d\n", smiError); + +// smiError = +// SMI_Set_quantity_values(1, 1, 2, SMI_TYPE_INT, 1, 3, +// nodeIndices, sv); +// TEST_EXIT(smiError == SMI_OK) +// ("SMI_Set_quantity_values() failed with error %d\n", smiError); +// } +// } + + delete [] sv; +} + +void +HL_SignedDistLevels::HL_updateIteration() +{ + int numNodes; + int *nodeIndices; + int max_q3 = 0; + int max_q4 = 0; + int sum_q3 = 0; + int sum_q4 = 0; + clock_t time1; + clock_t time2; + double TIME; + int control; + + int smiError = + SMI_Get_all_nodes(1, 1, const_cast<DegreeOfFreedom*>(&numNodes), + &nodeIndices); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_all_nodes() failed with error %d\n", smiError); + + int *values_q3 = new int [numNodes]; + int *values_q4 = new int [numNodes]; + + GET_PARAMETER(0,"SignedDist->count updates", "%d", &count_updates); + + time1 = clock(); + control = traverseListElement(); + time2 = clock(); + TIME = TIME_USED(time1, time2); + + cout<<"Zeit zum durchlaufen der ersten (Elementen-) Liste: "<<TIME<<" sec.\n\n"; + if(control == 1) + { + createLevels (); + } + + ///////////////////////////////// + + + //print chosen level in a file + if (print_level == 1) + { + DOFVector<double> *level_DOF = NEW DOFVector<double>(sD_DOF->getFESpace(), + "level_DOF"); + + int numElems; + int *elemIndices; + int *NodeIndices; + + smiError = SMI_Get_all_elems(1, 1, &numElems, &elemIndices); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_all_elems() failed with error %d\n", smiError); + + int *value_q6 = new int [numElems]; + + smiError = + SMI_Get_quantity_values(1, 1, 6, SMI_TYPE_INT, 1, numElems, + elemIndices, value_q6); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", smiError); + + for(int i=0; i<numElems; i++) + { + smiError = + SMI_Get_elems(1, 1, 1, &elemIndices[i], NULL, &NodeIndices, + NULL, NULL); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_elems() failed with error %d\n", smiError); + + for(int j=0; j<=dim; j++) + { + (*level_DOF)[NodeIndices[j]] = -1; + } + } + for(int i=0; i<numElems; i++) + { + smiError = + SMI_Get_elems(1, 1, 1, &elemIndices[i], NULL, &NodeIndices, + NULL, NULL); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_elems() failed with error %d\n", smiError); + + if (value_q6[i] == chosen_level) + { + for(int j=0; j<dim+1; j++) + { + (*level_DOF)[NodeIndices[j]] = 0; + } + } + } + + FileWriter *levelFileWriter = + NEW FileWriter("level->output", + level_DOF->getFESpace()->getMesh(), + level_DOF); + levelFileWriter->writeFiles (adaptInfo, false); + + DELETE levelFileWriter; + } + + //end of the part for printing chosen levels + + + time1 = clock(); + traversingListLevel_ ( sD_DOF ); + time2 = clock(); + TIME = TIME_USED(time1,time2); + + cout<<"Zeit zum Durchlaufen der zweiten Liste (Liste von Listen): "<<TIME<<" sec.\n\n"; + + std::string smiOutFile; + GET_PARAMETER(0, "SignedDist->count updates->output->filename", &smiOutFile); + cout << "count updates Ausgabe-Datei: " << smiOutFile.c_str() << "\n\n"; + + ofstream out (smiOutFile.c_str()); + + smiError = + SMI_Get_quantity_values(1, 1, 3, SMI_TYPE_INT, 1, numNodes, nodeIndices, + values_q3); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", smiError); + + smiError = + SMI_Get_quantity_values(1, 1, 4, SMI_TYPE_INT, 1, numNodes, nodeIndices, + values_q4); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", smiError); + + for (int i=0; i<numNodes; i++) + { + out<<nodeIndices[i]<<" "<<values_q3[i]<<" "<<values_q4[i]<<"\n"; + + if(max_q3 < values_q3[i]) + { + max_q3 = values_q3[i]; + } + if(max_q4 < values_q4[i]) + { + max_q4 = values_q4[i]; + } + sum_q3 = sum_q3 + values_q3[i]; + sum_q4 = sum_q4 + values_q4[i]; + } + + out<<"\n\n maximale Anzahl an versuchten Updates auf einem Knoten: "<<max_q3<<"\n maximale Anzahl an durchgefuehrten Updates auf einem Knoten: "<<max_q4<<"\n"; + out<<"\n Summe aller versuchten Updates: "<<sum_q3<<"\n Summe aller durchgefuehrten updates: "<<sum_q4<<"\n"; + + out<<"Anzahl an Knoten: "<<numNodes<<"\n"; + + out.close(); + + smiError = SMI_End_write_transaction(1, 1); + TEST_EXIT(smiError == SMI_OK) + ("SMI_End_write_transaction() failed with error %d\n", smiError); + + return; +} + +int +HL_SignedDistLevels::traverseListElement() +{ + int Element; + + bool neighboursExist; + bool neighbourInNewListSet = false; + + while (List_Element.size() != 0) + { + Element = List_Element.front(); + + neighboursExist = collectNeighbours_setLevels (Element, 0, &neighbourInNewListSet); + + List_Element.pop(); + } + + //within the function "collectNeighbours_setLevels" the new pairs are saved in the list "level" + //this list will be one entry of the list "Level_" + if (neighbourInNewListSet) + { + Level_.push_back (Level); + } + + while (Level.size() != 0) + { + Level.pop(); + } + if (!neighbourInNewListSet) + { + return 0; + } + else + { + return 1; + } + +} + +void +HL_SignedDistLevels::createLevels () +{ + bool neighbourExists = true; + bool stop = false; + Vert_Struct vertStruct; + int i = 0; + bool elementInNextListSet = true; + int value_q2; + int smiError; + + while(elementInNextListSet) + { + stop = false; + neighbourExists = false; + elementInNextListSet = false; + + while(Level_[i].size() != 0) + { + vertStruct = Level_[i].front(); + + neighbourExists = collectNeighbours_setLevels (vertStruct.ElNum, i+1, &elementInNextListSet); + + smiError = + SMI_Get_quantity_values(1, 1, 2, SMI_TYPE_INT, 1, 1, + &vertStruct.VertNum, &value_q2); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", smiError); + + if(value_q2 == 0) + { + helpLevel.push (vertStruct); + } + Level_[i].pop(); + } + + Level_[i] = helpLevel; + while (helpLevel.size() != 0) + { + helpLevel.pop(); + } + + if(elementInNextListSet) + { + Level_.push_back (Level); + } + + while (Level.size() != 0) + { + Level.pop(); + } + i++; + } +} + +bool +HL_SignedDistLevels::collectNeighbours_setLevels (const int Element, + const int currentIndex, + bool *elementInNewListSet) +{ + Vert_Struct vertStruct; + + int *neighbour=new int[dim+1]; + int *oppVertices=new int[dim+1]; + int *value = new int [dim+1]; + int saved_level; + int value_q5; + int *nodeIndices; + int *nodeIndicesOfElem; + int smiError; + + bool neighbourExists = false; + + smiAdapter->getNeighbourInfo(Element, neighbour, oppVertices); + + for ( int i=0; i<=dim; i++) + { + //if this neighbour exists it will be saved in a list according to it's level + if(neighbour[i] != -1) + { + neighbourExists = true; + + //calling old level and saving new level if necessary + smiError = + SMI_Get_quantity_values(1, 1, 6, SMI_TYPE_INT, 1, 1, + &neighbour[i], &saved_level); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", smiError); + + if(saved_level > currentIndex) + { + saved_level = currentIndex+1; + + smiError = + SMI_Set_quantity_values (1, 1, 6, SMI_TYPE_INT, 1, 1, + &neighbour[i], &saved_level); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Set_quantity_values() failed with error %d\n", + smiError); + + smiError = + SMI_Get_elems(1, 1, 1, &neighbour[i], NULL, &nodeIndices, + NULL,NULL); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_elems() failed with error %d\n", + smiError); + + smiError = + SMI_Get_quantity_values(1, 1, 1, SMI_TYPE_INT, dim+1, 1, + &neighbour[i], value); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", + smiError); + + if (value[oppVertices[i]] == 0) + { + vertStruct.ElNum = neighbour[i] ; + vertStruct.VertNum = oppVertices[i]; + Level.push( vertStruct ); + value[oppVertices[i]] = 1; + (*elementInNewListSet) = true; + + //counts how often a node is saved in the list of lists + if(count_in_list == 1) + { + smiError = + SMI_Get_elems(1, 1, 1, + const_cast<DegreeOfFreedom*>(&(vertStruct.ElNum)), + NULL, &nodeIndicesOfElem, NULL, NULL); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_elems() failed with error %d\n", smiError); + + smiError = + SMI_Get_quantity_values(1, 1, 5, SMI_TYPE_INT, 1, 1, + const_cast<DegreeOfFreedom*>(& nodeIndicesOfElem[vertStruct.VertNum]), + &value_q5); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", + smiError); + + value_q5 = value_q5 + 1; + + smiError = + SMI_Set_quantity_values(1, 1, 5, SMI_TYPE_INT, 1, 1, + const_cast<DegreeOfFreedom*>(& nodeIndicesOfElem[vertStruct.VertNum]), + &value_q5); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Set_quantity_values() failed with error %d\n", + smiError); + } + } + //save which pairs of elements and nodes is saved in a list + smiError = + SMI_Set_quantity_values(1, 1, 1, SMI_TYPE_INT, dim+1, 1, +// &neighbour[i], value); + neighbour+i, value); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Set_quantity_values() failed with error %d\n", + smiError); + } + } + } + + delete [] neighbour; + delete [] oppVertices; + delete [] value; + + return neighbourExists; + + +} + +void +HL_SignedDistLevels::traversingListLevel_ ( DOFVector<double> *boundVal_DOF ) +{ + bool Continue = true; + + Vert_Struct El_Vert; + + int Vert; + + int locVert; + int value_q3; + int value_q4; + int value_q5; + int counter = 0; + int *nodeIndices; + int *nodeIndicesOfElem; + double *coords = new double [(dim+1)*dim]; + int *valuesINT=new int[dim+1]; + double update; + int counter_list = 0; + int counter_lists_of_lists = 0; + FixVec<WorldVector<double> *, VERTEX> coordsOfNodes(dim); + for ( int i=0; i<=dim; i++) + { + coordsOfNodes[i] = new WorldVector<double>; + } + FixVec<double,VERTEX> boundVal(dim,NO_INIT); + WorldVector<double> helpVec; + int smiError; + + //for repeating the traverse of the list "Level_" + while (Continue == true) + { + Continue = false; + + //for traversing of the list "Level_" + for (int j=0; j < (signed int) Level_.size();j++) + { + //for traversing the entries of the List "Level_" + + while (Level_[j].size() != 0) + { + El_Vert = Level_[j].front(); + Vert = El_Vert.VertNum; + + smiError = + SMI_Get_elems (1, 1, 1, &(El_Vert.ElNum), NULL, + &(nodeIndices), NULL, NULL); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_elems() failed with error %d\n", smiError); + + smiError = + SMI_Get_nodes (1, 1, 3, dim, nodeIndices, coords); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_nodes() failed with error %d\n", smiError); + + //sorting of the nodes for calculating the update + counter = 0; + for (int i=0; i<=dim; i++) + { + if (i == El_Vert.VertNum) + { + (*(coordsOfNodes[dim]))[0]=coords[i*2]; + (*(coordsOfNodes[dim]))[1]=coords[i*2+1]; + boundVal[dim] = (*boundVal_DOF)[nodeIndices[i]]; + locVert = i; + } + else + { + (*(coordsOfNodes[counter]))[0]=coords[i*2]; + (*(coordsOfNodes[counter]))[1]=coords[i*2+1]; + boundVal[counter] = (*boundVal_DOF)[nodeIndices[i]]; + counter = counter+1; + } + } + + //save permutation of vertexes for calculation of the velocity + if(velExt != NULL) + { + velExt->setPermutation(locVert, 0); + } + update = elUpdate->calcElementUpdate( coordsOfNodes, boundVal ); + + //for counting tried updates + if(count_updates == 1) + { + smiError = + SMI_Get_quantity_values(1, 1, 3, SMI_TYPE_INT, 1, 1, + &nodeIndices[locVert], &value_q3); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", + smiError); + + value_q3 = value_q3 + 1; + + smiError = + SMI_Set_quantity_values(1, 1, 3, SMI_TYPE_INT, 1, 1, + const_cast<DegreeOfFreedom*>(&nodeIndices[locVert]), + &value_q3); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Set_quantity_values() failed with error %d\n", + smiError); + } + + //checking whether the calculated update will be set as new distance + if (update < (*boundVal_DOF)[nodeIndices[locVert]] && ((*boundVal_DOF)[nodeIndices[locVert]]-update) > tol) + { + (*boundVal_DOF)[nodeIndices[locVert]] = update; + //If distance is corrected, calculate new velocity. + if(velExt != NULL) + { + velExt->calcVelocity(nodeIndices, locVert); + } + + //for counting successful updates + if(count_updates == 1) + { + smiError = + SMI_Get_quantity_values(1, 1, 4, SMI_TYPE_INT, 1, 1, + &nodeIndices[locVert], + &value_q4); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", + smiError); + + value_q4 = value_q4 + 1; + + smiError = + SMI_Set_quantity_values(1, 1, 4, SMI_TYPE_INT, 1, 1, + const_cast<DegreeOfFreedom*>(&nodeIndices[locVert]), + &value_q4); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Set_quantity_values() failed with error %d\n", + smiError); + } + //?? + Continue = search_and_include_comb(El_Vert.ElNum, + Vert, nodeIndices, j); + } + + smiError = + SMI_Get_quantity_values(1, 1, 1, SMI_TYPE_INT, dim+1, 1, + &El_Vert.ElNum, valuesINT); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", + smiError); + + Level_[j].pop(); + valuesINT[locVert] = 0; + + smiError = + SMI_Set_quantity_values(1, 1, 1, SMI_TYPE_INT, dim+1, 1, + &El_Vert.ElNum, valuesINT); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Set_quantity_values() failed with error %d\n", + smiError); + + //counts how often a node is saved in the list of lists + if(count_in_list == 1) + { + smiError = + SMI_Get_elems(1, 1, 1, + const_cast<DegreeOfFreedom*>(&(El_Vert.ElNum)), + NULL, &nodeIndicesOfElem, NULL, NULL); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_elems() failed with error %d\n", smiError); + + smiError = + SMI_Get_quantity_values(1, 1, 5, SMI_TYPE_INT, 1, 1, + const_cast<DegreeOfFreedom*>(& nodeIndicesOfElem[El_Vert.VertNum]), + &value_q5); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", + smiError); + + value_q5 = value_q5 - 1; + + smiError = + SMI_Set_quantity_values(1, 1, 5, SMI_TYPE_INT, 1, 1, + const_cast<DegreeOfFreedom*>(& nodeIndicesOfElem[El_Vert.VertNum]), + &value_q5); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Set_quantity_values() failed with error %d\n", + smiError); + } + + //for printing which node is how often saved in a list after a special number of tried updates + if(count_in_list == 1) + { + counter_list++; + if(counter_list % print_in_list == 0) + { + print_quantity_5(counter_list); + } + } + } + } + //for printing which node is how often saved in a list at the end of the ..th traverse of the list "Level_" + if(count_in_list == 1) + { + counter_lists_of_lists++; + if(counter_lists_of_lists == print_in_list_2) + { + print_quantity_5(counter_lists_of_lists); + } + } + + } + + delete [] coords; + delete [] valuesINT; + for ( int i=0; i<Global::getGeo(VERTEX,dim); i++) + { + delete coordsOfNodes[i]; + } +} + +bool +HL_SignedDistLevels::search_and_include_comb(int ElNum, + int Vert, + int *nodeIndices, + const int Index) +{ + bool stop_l = false; + bool stop_r = false; + bool Continue = false; + bool continue_out = false; + int neighbour_l; + int neighbour_r; + int Vert_1_l; + int Vert_2_l; + int Vert_1_r; + int Vert_2_r; + int counter; + int elem_l; + int elem_r; + int node_l; + int node_r; + int VertGlobal; + int *nodeIndicesOfElem; + + int smiError = + SMI_Get_elems(1, 1, 1, const_cast<DegreeOfFreedom*>(&(ElNum)), NULL, + &nodeIndicesOfElem, NULL, NULL); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_elems() failed with error %d\n", smiError); + + VertGlobal = nodeIndicesOfElem[Vert]; + + //here the process of including elements/nodes into the second list + stop_l = false; + stop_r = false; + + elem_l = ElNum; + if (elem_l == -1) + { + stop_l = true; + } + elem_r = ElNum; + if (elem_r == -1) + { + stop_r = true; + } + + counter = 0; + for (int i=0; i<=dim; i++) + { + if(i != Vert && counter == 1) + { + node_r = i; + counter = counter + 1; + } + if(i != Vert && counter == 0) + { + node_l = i; + counter = counter + 1; + } + + } + + while (!stop_l || !stop_r) + { + //get next neighbour + if (!stop_l) + { + stop_l = getNextNeighbour (elem_l, VertGlobal, node_l, neighbour_l, Vert_1_l, Vert_2_l); + } + if(!stop_r) + { + stop_r = getNextNeighbour (elem_r, VertGlobal, node_r, neighbour_r, Vert_1_r, Vert_2_r); + } + + if(neighbour_l == elem_r) + { + break; + } + + //indclude into the second list (only if possible) + if (!stop_l) + { + Continue = includeIntoList (neighbour_l, Vert_1_l, Vert_2_l, Index); + if(Continue == true) + { + continue_out = Continue; + } + if(neighbour_l == neighbour_r) + { + break; + } + //"elem_l", "node_l", "elem_r", "node_r" have to be set on the next elements + node_l = getNext_node_l_r(elem_l,neighbour_l, node_l,VertGlobal); + elem_l = neighbour_l; + + } + if (!stop_r && neighbour_l != neighbour_r) + { + Continue = includeIntoList (neighbour_r, Vert_1_r, Vert_2_r, Index); + if(Continue == true) + { + continue_out = Continue; + } + //"elem_l", "node_l", "elem_r", "node_r" have to be set on the next elements + node_r = getNext_node_l_r(elem_r,neighbour_r, node_r, VertGlobal); + elem_r = neighbour_r; + } + } + return continue_out; +} + +bool +HL_SignedDistLevels::includeIntoList (int ElNum_in, + int VertNum_1_in, + int VertNum_2_in, + const int Index) +{ + Vert_Struct vertStruct_0; + Vert_Struct vertStruct_1; + + int *nodeIndices; + int *valuesINT = new int[dim+1]; + int *locVert = new int[dim]; + int value_q2; + int value_q5; + int value_q6; + int smiError; + + bool Continue = false; + + if(ElNum_in != -1) + { + smiError = + SMI_Get_elems(1, 1, 1, &ElNum_in, NULL, &nodeIndices, NULL, NULL); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_elems() failed with error %d\n", smiError); + + smiError = + SMI_Get_quantity_values(1, 1, 1, SMI_TYPE_INT, dim+1, 1, + const_cast<DegreeOfFreedom*>(&ElNum_in), + valuesINT); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", smiError); + + //if the pair of element and node isn't saved in any List and if it isn't a boundary-node include into adapting list + smiError = SMI_Get_quantity_values(1, 1, 2, SMI_TYPE_INT, 1, 1, + &nodeIndices[VertNum_1_in], + &value_q2); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", smiError); + + if(valuesINT[VertNum_1_in] == 0 && value_q2 == 0) + { + vertStruct_0.ElNum = ElNum_in; + vertStruct_0.VertNum = VertNum_1_in; + + smiError = + SMI_Get_quantity_values (1, 1, 6, SMI_TYPE_INT, 1, 1, &ElNum_in, + &value_q6); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", smiError); + + Level_[value_q6-1].push( vertStruct_0 ); + + //counts how often a node is saved in the list of lists + if(count_in_list == 1) + { + smiError = + SMI_Get_quantity_values(1, 1, 5, SMI_TYPE_INT, 1, 1, + const_cast<DegreeOfFreedom*>(& nodeIndices[vertStruct_0.VertNum]), + &value_q5); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", + smiError); + + value_q5 = value_q5 + 1; + + smiError = + SMI_Set_quantity_values(1, 1, 5, SMI_TYPE_INT, 1, 1, + const_cast<DegreeOfFreedom*>(& nodeIndices[vertStruct_0.VertNum]), + &value_q5); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Set_quantity_values() failed with error %d\n", + smiError); + } + + if(value_q6-1 < Index) + { + Continue = true; + } + + valuesINT[VertNum_1_in] = 1; + + smiError = + SMI_Set_quantity_values(1, 1, 1, SMI_TYPE_INT, dim+1, 1, +// &ElNum_in, &valuesINT); + &ElNum_in, valuesINT); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Set_quantity_values() failed with error %d\n", smiError); + } + + smiError = + SMI_Get_quantity_values(1, 1, 2, SMI_TYPE_INT, 1, 1, + &nodeIndices[VertNum_2_in], &value_q2); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", smiError); + + if(valuesINT[VertNum_2_in] == 0 && value_q2 == 0) + { + vertStruct_1.ElNum = ElNum_in; + vertStruct_1.VertNum = VertNum_2_in; + + smiError = + SMI_Get_quantity_values(1, 1, 6, SMI_TYPE_INT, 1, 1, &ElNum_in, + &value_q6); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", smiError); + + Level_[value_q6-1].push( vertStruct_1 ); + + //counts how often a node is saved in the list of lists + if(count_in_list == 1) + { + smiError = + SMI_Get_quantity_values(1, 1, 5, SMI_TYPE_INT, 1, 1, + const_cast<DegreeOfFreedom*>(& nodeIndices[vertStruct_1.VertNum]), + &value_q5); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", + smiError); + + value_q5 = value_q5 + 1; + + smiError = + SMI_Set_quantity_values(1, 1, 5, SMI_TYPE_INT, 1, 1, + const_cast<DegreeOfFreedom*>(& nodeIndices[vertStruct_1.VertNum]), + &value_q5); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Set_quantity_values() failed with error %d\n", + smiError); + } + + if(value_q6-1 < Index) + { + Continue = true; + } + + valuesINT[VertNum_2_in] = 1; + + smiError = + SMI_Set_quantity_values(1, 1, 1, SMI_TYPE_INT, dim+1, 1, + &ElNum_in, + //&valuesINT); + valuesINT); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Set_quantity_values() failed with error %d\n", smiError); + } + } + + delete [] valuesINT; + delete [] locVert; + + return Continue; +} + +bool +HL_SignedDistLevels::getNextNeighbour (const int ElNum_in, + const int Vert_Up_in, + const int VertNum_in, + int &ElNum_out, + int &VertNum_1_out, + int &VertNum_2_out) +{ + int *neighbour = new int[dim+1]; + int *oppVertices = new int[dim+1]; + int *nodeIndicesOfElem; + int smiError; + + smiAdapter->getNeighbourInfo(ElNum_in, neighbour,oppVertices); + + ElNum_out = neighbour [VertNum_in]; + + if(ElNum_out != -1) + { + smiError = + SMI_Get_elems(1, 1, 1, const_cast<DegreeOfFreedom*>(&(ElNum_out)), + NULL, &nodeIndicesOfElem, NULL, NULL); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_elems() failed with error %d\n", smiError); + + VertNum_1_out = oppVertices[VertNum_in]; + for (int i=0; i<=dim; i++) + { + if (nodeIndicesOfElem[i] != Vert_Up_in && i != VertNum_1_out) + { + VertNum_2_out = i; + } + } + } + + delete [] neighbour; + delete [] oppVertices; + + if (ElNum_out == -1) + { + return true; + } + + return false; + +} + +int +HL_SignedDistLevels::getNext_node_l_r (int elem_l_r_in, + int neighbour_l_r_in, + int node_l_r_in, + const int Vert) +{ + FUNCNAME("getNext_node_l_r()"); + + int *nodeIndicesOfElem; + int *nodeIndicesOfNeighbour = new int[dim+1]; + int globalNextNode_l_r_out; + + int smiError = + SMI_Get_elems(1, 1, 1, const_cast<DegreeOfFreedom*>(&neighbour_l_r_in), + NULL, &nodeIndicesOfElem, NULL, NULL); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_elems() failed with error %d\n", smiError); + + for(int i=0; i<=dim; i++) + { + nodeIndicesOfNeighbour[i] = nodeIndicesOfElem[i]; + } + + smiError = + SMI_Get_elems(1, 1, 1, const_cast<DegreeOfFreedom*>(&elem_l_r_in), + NULL, &nodeIndicesOfElem, NULL, NULL); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_elems() failed with error %d\n", smiError); + + for (int i=0; i<=dim; i++) + { + if(nodeIndicesOfElem[i] != Vert && i != node_l_r_in) + { + globalNextNode_l_r_out = nodeIndicesOfElem[i]; + } + } + for (int i=0; i<=dim; i++) + { + if(nodeIndicesOfNeighbour[i] == globalNextNode_l_r_out) + { + return i; + } + } + + ERROR_EXIT("should never be reached !\n"); + return 0; +} + +void +HL_SignedDistLevels::print_quantity_5 (int cntr) +{ + int numNodes; + int*nodeIndices; + double *coords = new double[dim]; + + int smiError = + SMI_Get_all_nodes(1, 1, const_cast<DegreeOfFreedom*>(&numNodes), + &nodeIndices); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_alls() failed with error %d\n", smiError); + + int *values_q5 = new int [numNodes]; + + std::string q5_OutFile_0; + std::string q5_OutFile_1; + std::string q5_OutFile_2; + std::string q5_OutFile_3; + std::string q5_OutFile_4; + + GET_PARAMETER(0, "SignedDist->count saving->output->filename_0", &q5_OutFile_0); + GET_PARAMETER(0, "SignedDist->count saving->output->filename_1", &q5_OutFile_1); + GET_PARAMETER(0, "SignedDist->count saving->output->filename_2", &q5_OutFile_2); + GET_PARAMETER(0, "SignedDist->count saving->output->filename_3", &q5_OutFile_3); + GET_PARAMETER(0, "SignedDist->count saving->output->filename_4", &q5_OutFile_4); + + + char cntrStr[20]; + sprintf(cntrStr, "%d", cntr); + q5_OutFile_0 += cntrStr; + q5_OutFile_1 += cntrStr; + q5_OutFile_2 += cntrStr; + q5_OutFile_3 += cntrStr; + q5_OutFile_4 += cntrStr; + + cout << "count saving Ausgabe-Datei_0: " << q5_OutFile_0.c_str() << "\n\n"; + cout << "count saving Ausgabe-Datei_1: " << q5_OutFile_1.c_str() << "\n\n"; + cout << "count saving Ausgabe-Datei_2: " << q5_OutFile_2.c_str() << "\n\n"; + cout << "count saving Ausgabe-Datei_3: " << q5_OutFile_3.c_str() << "\n\n"; + cout << "count saving Ausgabe-Datei_4: " << q5_OutFile_4.c_str() << "\n\n"; + + ofstream out_0 (q5_OutFile_0.c_str()); + ofstream out_1 (q5_OutFile_1.c_str()); + ofstream out_2 (q5_OutFile_2.c_str()); + ofstream out_3 (q5_OutFile_3.c_str()); + ofstream out_4 (q5_OutFile_4.c_str()); + + smiError = + SMI_Get_quantity_values(1, 1, 5, SMI_TYPE_INT, 1, numNodes, nodeIndices, + values_q5); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", smiError); + + for (int i=0; i<numNodes; i++) + { + smiError = + SMI_Get_nodes (1, 1, 1, dim, + const_cast<DegreeOfFreedom*>(&nodeIndices[i]), + coords); + + if(values_q5[i] == 0) + { + out_0<<coords[0]<<" "<<coords[1]<<"\n"; + } + if(values_q5[i] == 1) + { + out_1<<coords[0]<<" "<<coords[1]<<"\n"; + } + if(values_q5[i] == 2) + { + out_2<<coords[0]<<" "<<coords[1]<<"\n"; + } + if(values_q5[i] == 3) + { + out_3<<coords[0]<<" "<<coords[1]<<"\n"; + } + if(values_q5[i] >= 4) + { + out_4<<coords[0]<<" "<<coords[1]<<"\n"; + } + + + } + + out_0.close(); + out_1.close(); + out_2.close(); + out_3.close(); + out_4.close(); + + delete [] coords; + delete [] values_q5; +} + +void +HL_SignedDistLevels::print_quantity_6 () +{ + std::string smiOutFile2; + GET_PARAMETER(0, "SignedDist->print levels->filename2", &smiOutFile2); + cout << "count levels Ausgabe-Datei: " << smiOutFile2.c_str() << "\n\n"; + + ofstream out2 (smiOutFile2.c_str()); + + int numElems; + int *elemIndices; + + int smiError = SMI_Get_all_elems(1, 1, &numElems, &elemIndices); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_all_elems() failed with error %d\n", smiError); + + int *value_q6 = new int [numElems]; + + smiError = + SMI_Get_quantity_values(1, 1, 6, SMI_TYPE_INT, 1, numElems, elemIndices, + value_q6); + TEST_EXIT(smiError == SMI_OK) + ("SMI_Get_quantity_values() failed with error %d\n", smiError); + + int cl=0; + for (int i=0; i<numElems; i++) + { + out2<<elemIndices[i]<<" "<<value_q6[i]<<"\n"; + + if(value_q6[i] == 100000) + { + cl=cl +1; + } + } + + out2.close(); +} diff --git a/AMDiS/Reinit/src/HL_SignedDistLevels.h b/AMDiS/Reinit/src/HL_SignedDistLevels.h new file mode 100644 index 00000000..aa02a31d --- /dev/null +++ b/AMDiS/Reinit/src/HL_SignedDistLevels.h @@ -0,0 +1,234 @@ +#ifndef HL_SIGNEDDISTLEVELS +#define HL_SIGNEDDISTLEVELS + +#include "ElInfo.h" +#include "FixVec.h" +// #include "MemoryManager.h" +#include "Traverse.h" +#include <queue> +#include <vector> +#include <time.h> + +#include "ElementLevelSet.h" + +#include "BoundaryElementDist.h" +#include "ElementUpdate.h" +#include "ElementUpdate_2d.h" +#include "ElementUpdate_3d.h" +#include "HL_SignedDist.h" +#include "VelocityExt.h" + +#include "SMIAdapter.h" +#include "smi.h" + +using namespace AMDiS; + +typedef struct +{ + int ElNum; + int VertNum; +} Vert_Struct; + +class HL_SignedDistLevels : public HL_SignedDist +{ + public: + MEMORY_MANAGED(HL_SignedDistLevels); + + /** + * Constructor. + */ + HL_SignedDistLevels(const char *name_, + int dim_, + bool doVelocityExt = false, + Flag velExtType_ = VEL_EXT) + : HL_SignedDist(name_, dim_, doVelocityExt, velExtType_), + smiAdapter(NULL) + { + FUNCNAME("HL_SignedDistLevels::HL_SignedDistLevels"); + + // ===== Read parameters from init file. ===== + GET_PARAMETER(0,name + "->tolerance", "%f", &tol); + GET_PARAMETER(0,name + "->count_how_often_saved_in_list", "%d", &count_in_list); + GET_PARAMETER(0,name + "->save_in_list->the ..th", "%d", &print_in_list); + GET_PARAMETER(0,name + "->save_in_list->after the ..th traversing of the list", "%d", &print_in_list_2); + GET_PARAMETER(0,name + "->print_level", "%d", &chosen_level); + GET_PARAMETER(0,name + "->print_level_yes_no", "%d", &print_level); + + TEST_EXIT(tol > 0)("illegal tolerance !\n"); + }; + + protected: + /** + * Initializes the boundary: calculation of the distance of boundary + * vertices to the interface. + * Interface is given by \ref lS_DOF and result is stored in + * \ref sD_DOF. + */ + void initializeBoundary(); + + /** + * function for transvering Mesh to SMi an Adding the quantities + **/ + void Mesh_to_SMI_and_quantity (); + + /** + * function for creating the first list, in which elementnumber of + * boundary-elements are saved + */ + void createFirstList(const int elStatus, + const int *elVertStatusVec, + int ElNum, + const int NumVertIntPoints); + + /** + * Calculates the distance function and stores result in sD_DOF. + * Requirement: The boundary values are already set in \ref sD_DOF. + */ + void HL_updateIteration(); + + /** + * function for traversing the list "List_Element" + * returns 1 if min one element is set in the new list + * returns 0 if no element is set in the new list + */ + int traverseListElement(); + + /** + * function for creating all levels higher than 1 an saving pairs of + * elements and node in the right list + **/ + void createLevels (); + + /** + * function collects the next neighbours, creates an according list + * and saves the pair in it + * returns true if one or more neighbours exist and false if not + **/ + bool collectNeighbours_setLevels (const int Element, + const int currentIndex, + bool *elementInNewListSet); + + /** + * function for traversing the list of list, named "Level_" + **/ + void traversingListLevel_ ( DOFVector<double> *boundVal_DOF ); + + /** + * calls the next neighbours and puts them into the right list + * returns true if an element had to be saved in an lower level + * than the current index + * this means the loop over all lists Level_[i] has to be repaeated again + * "Vert" is a local node + **/ + bool search_and_include_comb(int ElNum, + int Vert, + int *nodeIndices, + const int Index); + + /** + * checking whether the element "ElNum_in" has to be included into + * the second list + * if yes it will be included + * returns true if the level of the element is smaler than he current index + * returns false if the level is greater thean the current index + * "Vert_1_in" and "Vert_2_in" are localvertizes + */ + bool includeIntoList (int ElNum_in, + int VertNum_1_in, + int VertNum_2_in, + const int Index); + + /** + * gets the neighbour according to the node "VertNum_in" and two of + * its nodes (in local koordinates) + * returns "false" if the called neighbour exists and "true" if not + * Vert_Up_in is given in global coordinates, the other points are + * given in local coordinates + */ + bool getNextNeighbour (const int ElNum_in, + const int Vert_Up_in, + const int VertNum_in, + int &ElNum_out, + int &VertNum_1_out, + int &VertNum_2_out); + + /** + * function needed in the function "traversingListELVert" + **/ + int getNext_node_l_r (int elem_l_r_in, + int neighbour_l_r_in, + int node_l_r_in, + const int Vert); + + //================================== + void print_quantity_5 (int cntr); + + /** + * function for printinq the quantity 6 + * attention: we need at least read_transaction in smi for calling + * this function + **/ + void print_quantity_6 (); + //==================================== + + protected: + /** + * Tolerance for Hopf-Lax update iteration loop. + */ + double tol; + + /** + * is needed for transfering the mesh to SMI + */ + SMIAdapter *smiAdapter; + + /** + * in this list boundary-elements are saved; + * is needed for creating the list "List_El_Vert" + */ + queue<int> List_Element; + + /** + * in this list structs filled with element-number and vertex-number + * are saved; + * is needed for traversing the mesh efficiently + */ + queue<Vert_Struct> Level; + + queue<Vert_Struct> helpLevel; + + queue<Vert_Struct> List_El_Vert; //Listen noch einmal kontrollieren! + + /** + * in this vector the lists of different levels are saved + **/ + vector<queue<Vert_Struct> > Level_; + + /** + * 0 ->do not count updates + * 1 ->count updates + **/ + int count_updates; + + /** + * 1 -> it will be count how often a node is saved in the second list + * 0 ->it will not be count + **/ + int count_in_list; + + int print_in_list; + int print_in_list_2; + + /** + * level which will be printed in a file + **/ + int chosen_level; + + /** + * 1->a special level will be printed in a file + * 0->no level is printed in a file + **/ + int print_level; +}; + +#endif // HL_SIGNEDDISTLEVELS diff --git a/AMDiS/Reinit/src/HL_SignedDistTraverse.cc b/AMDiS/Reinit/src/HL_SignedDistTraverse.cc new file mode 100644 index 00000000..534db935 --- /dev/null +++ b/AMDiS/Reinit/src/HL_SignedDistTraverse.cc @@ -0,0 +1,275 @@ +#include "HL_SignedDistTraverse.h" + +#include "VelocityExtFromVelocityField.h" + +void +HL_SignedDistTraverse::initializeBoundary() +{ + FUNCNAME("HL_SignedDistTraverse::initializeBoundary()"); + + // ===== All non-boundary vertices are initialized with "infinity". ===== + sD_DOF->set(inftyValue); + + // ===== Traverse mesh and initialize boundary elements. ===== + TraverseStack stack; + FixVec<double, VERTEX> distVec(dim, NO_INIT); + int elStatus; + + const int nBasFcts = feSpace->getBasisFcts()->getNumber(); + DegreeOfFreedom *locInd = GET_MEMORY(DegreeOfFreedom, nBasFcts); + + ElInfo *elInfo; + if (velExt && velExtType.isSet(VEL_EXT_FROM_VEL_FIELD)) { + elInfo = stack.traverseFirst(feSpace->getMesh(), + -1, + Mesh::CALL_LEAF_EL | + Mesh::FILL_BOUND | + Mesh::FILL_COORDS | + Mesh::FILL_GRD_LAMBDA); + } + else { + elInfo = stack.traverseFirst(feSpace->getMesh(), + -1, + Mesh::CALL_LEAF_EL | + Mesh::FILL_BOUND | + Mesh::FILL_COORDS); + } + while(elInfo) { + + // Set elInfo in case velocity extension from velocity field is used. + if (velExt && velExtType.isSet(VEL_EXT_FROM_VEL_FIELD)) { + ((VelocityExtFromVelocityField *)velExt)->setElInfo(elInfo); + } + + // Get local indices of vertices. + feSpace->getBasisFcts()->getLocalIndices( + const_cast<Element *>(elInfo->getElement()), + const_cast<DOFAdmin *>(feSpace->getAdmin()), + locInd); + + // Get element status. + elStatus = elLS->createElementLevelSet(elInfo); + + // Is element cut by the interface ? + if (elStatus == ElementLevelSet::LEVEL_SET_BOUNDARY) { + + // Reset element distance vector. + for (int i=0; i<=dim; ++i) { + distVec[i] = inftyValue; + } + + // Mark all vertices as boundary vertices. + for (int i=0; i<=dim; ++i) { + (*bound_DOF)[locInd[i]] = 1.0; + } + + // Calculate distance for all vertices. + if (bndElDist->calcDistOnBoundaryElement(elInfo, distVec) != + ElementLevelSet::LEVEL_SET_BOUNDARY) { + ERROR_EXIT("error in distance calculation !\n"); + } + else { + + // If distance is smaller, correct to new distance. + for (int i=0; i<=dim; ++i) { + + // --> for test purposes: + if (distVec[i] > 1000) { + cout << "\nElement: " << elInfo->getElement()->getIndex() << ", Knoten: " << i << " , keine Randwertinitialisierung !\n"; + } + // --> end: for test purposes + + if ((*sD_DOF)[locInd[i]] > distVec[i]) { + (*sD_DOF)[locInd[i]] = distVec[i]; + //If Distance is corrected, calculate new velocity. + if(velExt != NULL) + { + velExt->calcVelocityBoundary(locInd, i); + } + } + } + } + } // end of: elStatus == ElementLevelSet::LEVEL_SET_BOUNDARY + + elInfo = stack.traverseNext(elInfo); + } // end of: mesh traverse + + FREE_MEMORY(locInd, DegreeOfFreedom, nBasFcts); + + return; +} + +void +HL_SignedDistTraverse::HL_updateIteration() +{ + // ===== Create DOF vector for the last iteration step. ===== + if (sDOld_DOF) + DELETE sDOld_DOF; + sDOld_DOF = NEW DOFVector<double>(feSpace, "sDOld_DOF"); + sDOld_DOF->copy(const_cast<DOFVector<double> &>(*sD_DOF)); + + // ===== Gauss-Seidel or Jacobi iteration ? ===== + if (GaussSeidelFlag) { + update_DOF = sD_DOF; + } + else { + update_DOF = sDOld_DOF; + } + + // ===== Iteration loop: proceed until tolerance is reached. ===== + TraverseStack stack; + ElInfo *elInfo; + tol_reached = false; + int itCntr = 0; + while (!tol_reached && itCntr != maxIt) { + + ++itCntr; + tol_reached = true; + + // ===== Traverse mesh: perform Hopf-Lax element update on + // each element. ===== + elInfo = stack.traverseFirst(feSpace->getMesh(), -1, + Mesh::CALL_LEAF_EL | + Mesh::FILL_BOUND | + Mesh::FILL_COORDS); + while(elInfo) { + HL_elementUpdate(elInfo); + + elInfo = stack.traverseNext(elInfo); + } + + // ===== Is tolerance reached ? ===== + tol_reached = checkTol(); + + sDOld_DOF->copy(const_cast<DOFVector<double> &>(*sD_DOF)); + } + + cout << "\n\nCalculation of signed distance function via mesh traverse iteration:\n"; + if (GaussSeidelFlag) { + cout << "\tGauss-Seidel iteration\n"; + } + else { + cout << "\tJacobi iteration\n"; + } + cout << "\tnumber of iterations needed: " << itCntr << "\n\n"; + + return; +} + +void +HL_SignedDistTraverse::HL_elementUpdate(ElInfo *elInfo) +{ + FUNCNAME("HL_SignedDistTraverse::HL_elementUpdate()"); + + double update; + + // ===== Get global indices of vertices of element. ===== + const int nBasFcts = feSpace->getBasisFcts()->getNumber(); + DegreeOfFreedom *locInd = GET_MEMORY(DegreeOfFreedom, nBasFcts); + + feSpace->getBasisFcts()->getLocalIndices( + const_cast<Element *>(elInfo->getElement()), + const_cast<DOFAdmin *>(feSpace->getAdmin()), + locInd); + + // ===== Hopf-Lax element update for each vertex of element. ===== + for (int i=0; i<=dim; ++i) { + + // ===== Calculate update for non-boundary vertex. ===== + if ((*bound_DOF)[locInd[i]] < 1.e-15) { + //save permutation of vertexes for calculation of the velocity + if(velExt != NULL) + { + velExt->setPermutation(i, 1); + } + update = calcElementUpdate(elInfo, i, locInd); + // ---> for test purposes: count number of calculated updates + ++calcUpdate_Cntr; + // ---> end: for test purposes + + // Calculates minimum of all element updates on elements + // containing vertex i. + if (update < (*sD_DOF)[locInd[i]]) { + (*sD_DOF)[locInd[i]] = update; + ///If Distance is corrected, calculate new velocity. + if(velExt != NULL) + { + velExt->calcVelocity(locInd, i); + } + // ---> for test purposes: count number of calculated updates + ++setUpdate_Cntr; + // ---> end: for test purposes + } + } + } + + FREE_MEMORY(locInd, DegreeOfFreedom, nBasFcts); +} + +double +HL_SignedDistTraverse::calcElementUpdate(ElInfo *elInfo, + int nXh, + const DegreeOfFreedom *locInd) +{ + double update; + FixVec<WorldVector<double> *, VERTEX> elVert(dim, NO_INIT); + FixVec<double, VERTEX> uhVal(dim, NO_INIT); + + // ===== Get local indices of element vertices (except xh). ===== + int nYh, nZh, nWh; + + nYh = (nXh + 1) % (dim+1); + nZh = (nXh + 2) % (dim+1); + if (dim == 3) nWh = (nXh + 3) % (dim+1); + + // ===== Get world coordinates of vertices of element and their values + // of uh. + // The coordinates of the vertex the update is calculated for + // are stored at the end of the vector elVert. ===== + switch (dim) { + case 2: elVert[0] = &(elInfo->getCoord(nYh)); + elVert[1] = &(elInfo->getCoord(nZh)); + elVert[2] = &(elInfo->getCoord(nXh)); + + uhVal[0] = (*update_DOF)[locInd[nYh]]; + uhVal[1] = (*update_DOF)[locInd[nZh]]; + uhVal[2] = (*update_DOF)[locInd[nXh]]; + + break; + case 3: elVert[0] = &(elInfo->getCoord(nYh)); + elVert[1] = &(elInfo->getCoord(nZh)); + elVert[2] = &(elInfo->getCoord(nWh)); + elVert[3] = &(elInfo->getCoord(nXh)); + + uhVal[0] = (*update_DOF)[locInd[nYh]]; + uhVal[1] = (*update_DOF)[locInd[nZh]]; + uhVal[2] = (*update_DOF)[locInd[nWh]]; + uhVal[3] = (*update_DOF)[locInd[nXh]]; + + break; + default: ERROR_EXIT("illegal dimension !\n"); + break; + } + + // ===== Calculate Hopf-Lax element update for vertex. ===== + update = elUpdate->calcElementUpdate(elVert, uhVal); + + return update; +} + +bool +HL_SignedDistTraverse::checkTol() +{ + DOFVector<double>::Iterator it_sD(sD_DOF, USED_DOFS); + DOFVector<double>::Iterator it_sDOld(sDOld_DOF, USED_DOFS); + + for(it_sD.reset(), it_sDOld.reset(); + !it_sD.end(); + ++it_sD, ++it_sDOld) { + if ((*it_sDOld)-(*it_sD) > tol || (*it_sDOld)-(*it_sD) < 0) { + return false; + } + } + + return true; +} diff --git a/AMDiS/Reinit/src/HL_SignedDistTraverse.h b/AMDiS/Reinit/src/HL_SignedDistTraverse.h new file mode 100644 index 00000000..2f41d015 --- /dev/null +++ b/AMDiS/Reinit/src/HL_SignedDistTraverse.h @@ -0,0 +1,157 @@ +#ifndef HL_SIGNEDDISTTRAVERSE +#define HL_SIGNEDDISTTRAVERSE + +#include "ElInfo.h" +#include "FixVec.h" +//#include "MemoryManager.h" +#include "Traverse.h" + +#include "ElementLevelSet.h" + +#include "BoundaryElementDist.h" +#include "ElementUpdate.h" +#include "ElementUpdate_2d.h" +#include "ElementUpdate_3d.h" +#include "HL_SignedDist.h" +#include "VelocityExt.h" + +using namespace AMDiS; + +class HL_SignedDistTraverse : public HL_SignedDist +{ + public: + MEMORY_MANAGED(HL_SignedDistTraverse); + + /** + * Constructor. + */ + HL_SignedDistTraverse(const char *name_, + int dim_, + bool doVelocityExt = false, + Flag velExtType_ = VEL_EXT) + : HL_SignedDist(name_, dim_, doVelocityExt, velExtType_), + sDOld_DOF(NULL), + update_DOF(NULL), + tol_reached(false) + { + FUNCNAME("HL_SignedDistTraverse::HL_SignedDistTraverse"); + + // ===== Read parameters from init file. ===== + GET_PARAMETER(0, name + "->tolerance", "%f", &tol); + GET_PARAMETER(0, name + "->maximal number of iteration steps", + "%d", &maxIt); + GET_PARAMETER(0, name + "->Gauss-Seidel iteration", "%d", + &GaussSeidelFlag); + + TEST_EXIT(tol > 0)("illegal tolerance !\n"); + + // ---> for test purposes: initialization of counter variables + calcUpdate_Cntr = 0; + setUpdate_Cntr = 0; + // ---> end: for test purposes + }; + + /** + * Destructor. + */ + ~HL_SignedDistTraverse() + { + if (sDOld_DOF) + DELETE sDOld_DOF; + + // ---> for test purposes: print result of update counting + printUpdateCntr(); + // ---> end: for test purposes + }; + + protected: + /** + * Initializes the boundary: calculation of the distance of boundary + * vertices to the interface. + * Interface is given by lS_DOF and result is stored in + * sD_DOF. + */ + void initializeBoundary(); + + /** + * Calculates the distance function and stores result in sD_DOF. + * Requirement: The boundary values are already set in sD_DOF. + */ + void HL_updateIteration(); + + /** + * Hopf-Lax element update on element elInfo. + */ + void HL_elementUpdate(ElInfo *elInfo); + + /** + * Calculate the update for the vertex xh of element elInfo. + */ + double calcElementUpdate(ElInfo *elInfo, + int nXh, + const DegreeOfFreedom *locInd); + + /** + * In iteration loop: checks whether tolerance is reached. + * true - tolerance is reached + * false - tolerance is not reached + */ + bool checkTol(); + + // ---> for test purposes: print result of update counting + void printUpdateCntr() + { + cout << "\n"; + cout << "\tUpdate statistic: \n"; + cout << "\t-----------------\n"; + cout << "\tcalculated updates: " << calcUpdate_Cntr << "\n"; + cout << "\tset updates: " << setUpdate_Cntr << "\n"; + cout << "\n"; + }; + // ---> end: for test purposes + + protected: + /** + * DOF vector for the last iteration step. + * Used during Jacobi iteration and to check whether tolerance is reached. + */ + DOFVector<double> *sDOld_DOF; + + /** + * Pointer to the DOF vector holding the values of the last iteration + * step. + * Gauss-Seidel iteration - update_DOF == sD_DOF + * Jacobi iteration - update_DOF == sDOld_DOF + */ + DOFVector<double> *update_DOF; + + /** + * Tolerance for Hopf-Lax update iteration loop. + */ + double tol; + + /** + * Flag showing whether tolerance tol is reached. + */ + bool tol_reached; + + /** + * Maximal number of mesh iterations for Hopf-Lax update. + */ + int maxIt; + + /** + * Indicates whether Gauss-Seidel or Jacobi iteration is used. + * 0 - Jacobi + * !=0 - Gauss-Seidel + */ + int GaussSeidelFlag; + + // ---> for test purposes: variables to count calculated and set updates + int calcUpdate_Cntr; + int setUpdate_Cntr; + // ---> end: for test purposes + +}; + +#endif // HL_SIGNEDDISTTRAVERSE diff --git a/AMDiS/Reinit/src/NormEps.cc b/AMDiS/Reinit/src/NormEps.cc new file mode 100644 index 00000000..93adae67 --- /dev/null +++ b/AMDiS/Reinit/src/NormEps.cc @@ -0,0 +1,29 @@ +#include "NormEps.h" + +double NormEps::eps = 0.0; + +double +NormEps::calcNormEps(const WorldVector<double> &x) +{ + FUNCNAME("NormEps::calcNormEps()"); + + static double result; + + TEST_EXIT(eps > 1.e-15)("illegal eps for norm regularization !\n"); + result = x*x + eps*eps; + + return(sqrt(result)); +} + +double +NormEps::calcNormEps2(const WorldVector<double> &x) +{ + FUNCNAME("NormEps::calcNormEps2()"); + + static double result; + + TEST_EXIT(eps > 1.e-15)("illegal eps for norm regularization !\n"); + result = x*x + eps*eps; + + return(result); +} diff --git a/AMDiS/Reinit/src/NormEps.h b/AMDiS/Reinit/src/NormEps.h new file mode 100644 index 00000000..1e83953b --- /dev/null +++ b/AMDiS/Reinit/src/NormEps.h @@ -0,0 +1,46 @@ +#ifndef NORMEPS_H +#define NORMEPS_H + +#include "FixVec.h" +#include "Global.h" +// #include "MemoryManager.h" +#include "Parameters.h" + +using namespace AMDiS; + +class NormEps +{ + public: + MEMORY_MANAGED(NormEps); + + /** + * Calculates regularized norm of WorldVector x. + */ + static double calcNormEps(const WorldVector<double> &x); + + /** + * Calculates square of regularized norm of WorldVector x. + */ + static double calcNormEps2(const WorldVector<double> &x); + + /** + * Set regularization epsilon eps. + */ + static inline void setEps() { + FUNCNAME("NormEps::setEps()"); + + eps = 0.0; + GET_PARAMETER(0, "NormEps->epsilon for norm regularization", "%f", &eps); + + TEST_EXIT(eps > 1.e-15) + ("illegal eps for norm regularization !\n"); + }; + + protected: + /** + * Epsilon for regularization. + */ + static double eps; +}; + +#endif // NORMEPS_H diff --git a/AMDiS/Reinit/src/VelocityExt.cc b/AMDiS/Reinit/src/VelocityExt.cc new file mode 100644 index 00000000..d7ca70b2 --- /dev/null +++ b/AMDiS/Reinit/src/VelocityExt.cc @@ -0,0 +1,260 @@ +#include "VelocityExt.h" + +void +VelocityExt::calcVelocityBoundary(DegreeOfFreedom *lokInd, const int indexV) +{ + double tempV; + + for (int nV=0; nV<nVelDOFs; ++nV) { + + tempV = 0.0; + for(int i=0; i<=dim; i++) + { + tempV += (*(origVelDOF[nV]))[lokInd[i]]*lamVec[indexV][i]; + } + (*(velDOF[nV]))[lokInd[indexV]]=tempV; + } +} + +void +VelocityExt::calcVelocity(DegreeOfFreedom *lokInd, const int indexV) +{ + double tempV; + int tempIndex; + if(indexFace>=0) //if there were several updates over element faces, + //take the coordinates that belong to the element face + //with the shortest distance to the interface + { + tempIndex=indexFace; + } + else //right coordinates are in lamVec[0] + { + tempIndex=0; + } + indexFace=-1; + +// // // test +// int zero = permutation[0]; +// int one = permutation[1]; +// int two = permutation[2]; +// // int three = permutation[3]; +// // // test + + for (int nV=0; nV<nVelDOFs; ++nV) { + + tempV = 0.0; + for(int i=0; i<=dim; i++) + { + tempV += (*(velDOF[nV]))[lokInd[permutation[i]]]*lamVec[tempIndex][i]; + } + (*(velDOF[nV]))[lokInd[indexV]]=tempV; + } +} + +void +VelocityExt::setBarycentricCoords_2D_boundary(const double &l_0, const double &l_1, const double &l_2, const int index) +{ + lamVec[index][0]=l_0; + lamVec[index][1]=l_1; + lamVec[index][2]=l_2; +} + +void +VelocityExt::setBarycentricCoords_2D(const double &l_0, const double &l_1, const double &l_2) +{ + setBarycentricCoords_2D_boundary(l_0, l_1, l_2, 0); +} + +void +VelocityExt::calcBarycentricCoords_2D(const double &c_delta, const double &c_alpha, const double &norm_zhminusyh, const double &norm_xhminusyh) +{ + double s_delta=sqrt(1-c_delta*c_delta); + double c_delta_alpha=c_delta*c_alpha+sqrt((1-c_alpha*c_alpha)*(1-c_delta*c_delta)); +// double c_delta_alpha=sqrt(c_delta*c_alpha+sqrt((1-c_alpha*c_alpha)*(1-c_delta*c_delta))); + double s_delta_alpha=sqrt(1-c_delta_alpha*c_delta_alpha); + double c=(s_delta_alpha*norm_xhminusyh)/s_delta; + double lambda=c/norm_zhminusyh; + setBarycentricCoords_2D(1-lambda, lambda, 0); +} + +void +VelocityExt::setBarycentricCoords_3D_boundary(const double &l_0, const double &l_1, const double &l_2, const double &l_3, const int index) +{ + lamVec[index][0]=l_0; + lamVec[index][1]=l_1; + lamVec[index][2]=l_2; + lamVec[index][3]=l_3; +} + +void +VelocityExt::calcBarycentricCoords_3D_boundary(const DimVec<double> sp1, const DimVec<double> sp2, const double lambda, int i) +{ + DimVec<double> tempVec(dim, NO_INIT); + tempVec[0] = sp1[0]+lambda*(sp2[0]-sp1[0]); + tempVec[1] = sp1[1]+lambda*(sp2[1]-sp1[1]); + tempVec[2] = sp1[2]+lambda*(sp2[2]-sp1[2]); + tempVec[3] = sp1[3]+lambda*(sp2[3]-sp1[3]); + setBarycentricCoords_3D_boundary(tempVec[0], tempVec[1], tempVec[2], tempVec[3], i); +} + +void +VelocityExt::copyAndExpandFaceCoords_3D(int vertNum,int index) +{ + double t0, t1, t2; + t0=lamVec[0][0]; + t1=lamVec[0][1]; + t2=lamVec[0][2]; + switch(vertNum) + { + case 0: //coordinates belong to element face 0 + setBarycentricCoords_3D_boundary(0,t0,t1,t2,index); + break; + + case 1: //coordinates belong to element face 1 + setBarycentricCoords_3D_boundary(t0,0,t1,t2,index); + break; + + case 2: //coordinates belong to element face 2 + setBarycentricCoords_3D_boundary(t0,t1,0,t2,index); + break; + + default: + break; + } + +} + +void +VelocityExt::setBarycentricCoords_3D(const double &l_0, const double &l_1, const double &l_2, const double &l_3) +{ + indexFace = -1; + setBarycentricCoords_3D_boundary(l_0, l_1, l_2, l_3, 0); +} + +void +VelocityExt::setIndexFaceWithShortestDist(int indexFace_) +{ + indexFace=indexFace_; +} + +void +VelocityExt::setPermutation(int vertNum, int mTrav) +{ + switch(dim) + { + case 2: + switch(mTrav) + { + case 0: //level + setPermutation(vertNum); + if(vertNum==1) + { + swapVertices(0,1); + } + break; + + case 1: //traverse + setPermutation(vertNum); + break; + + default: + break; + } + break; + + case 3: + switch(mTrav) + { + case 1: //traverse + setPermutation(vertNum); + break; + + default: + break; + } + break; + + default: + break; + } +} + +void +VelocityExt::setPermutation(int vertNum) +{ + switch(dim) + { + case 2: + switch(vertNum) + { + case 0: //update is for vertex 0 + setPermutation_2D(1,2,0); + break; + + case 1: //update is for vertex 1 + setPermutation_2D(2,0,1); + break; + + case 2: //update is for vertex 2 + setPermutation_2D(0,1,2); + break; + + default: + break; + } + break; + + case 3: + switch(vertNum) + { + case 0: //update is for vertex 0 + setPermutation_3D(1,2,3,0); + break; + + case 1: //update is for vertex 1 + setPermutation_3D(2,3,0,1); + break; + + case 2: //update is for vertex 2 + setPermutation_3D(3,0,1,2); + break; + + case 3: //update is for vertex 3 + setPermutation_3D(0,1,2,3); + break; + + default: + break; + } + break; + + default: + break; + } +} + +void +VelocityExt::setPermutation_2D(int i_0, int i_1, int i_2) +{ + permutation[0]=i_0; + permutation[1]=i_1; + permutation[2]=i_2; +} + + +void +VelocityExt::setPermutation_3D(int i0, int i1, int i2, int i3) +{ + permutation[0]=i0; + permutation[1]=i1; + permutation[2]=i2; + permutation[3]=i3; +} + +void +VelocityExt::swapVertices(int i1, int i2) +{ + int temp=permutation[i1]; + permutation[i1]=permutation[i2]; + permutation[i2]=temp; +} diff --git a/AMDiS/Reinit/src/VelocityExt.h b/AMDiS/Reinit/src/VelocityExt.h new file mode 100644 index 00000000..0260fca2 --- /dev/null +++ b/AMDiS/Reinit/src/VelocityExt.h @@ -0,0 +1,258 @@ +#ifndef VELOCITYEXT_H +#define VELOCITYEXT_H + +#include "AdaptInfo.h" +#include "DOFVector.h" +#include "Element.h" +#include "FileWriter.h" +#include "FixVec.h" +// #include "MemoryManager.h" + +using namespace AMDiS; + +class VelocityExt +{ + public: + MEMORY_MANAGED(VelocityExt); + + /** + * Constructor. + */ + VelocityExt(int dim_) + : dim(dim_), + nVelDOFs(0), + lamVec(dim_,dim_+1,NO_INIT), + permutation(dim_,NO_INIT) + { + indexFace = -1; + }; + + /** + * Destructor. + */ + virtual ~VelocityExt() + {}; + + /** + * Print velDOF to file. + */ + void printVelDOF(AdaptInfo *adaptInfo, int i = 0) + { + FUNCNAME("VelocityExt::printVelDOF()"); + + TEST_EXIT(i < velDOF.size())("illegal index !\n"); + + FileWriter *fileWriter = NEW FileWriter( + "VelocityExt->velocity output", + (velDOF[i])->getFESpace()->getMesh(), + const_cast<DOFVector<double> *>(velDOF[i])); + fileWriter->writeFiles(adaptInfo, false); + + DELETE fileWriter; + }; + + /** + * Print origVelDOF to file. + */ + void printOrigVelDOF(AdaptInfo *adaptInfo, int i = 0) + { + FUNCNAME("VelocityExt::printOrigVelDOF()"); + + TEST_EXIT(i < origVelDOF.size())("illegal index !\n"); + + FileWriter *fileWriter = NEW FileWriter( + "VelocityExt->interface velocity output", + (origVelDOF[i])->getFESpace()->getMesh(), + const_cast<DOFVector<double> *>(origVelDOF[i])); + fileWriter->writeFiles(adaptInfo, false); + + DELETE fileWriter; + }; + + /** + * Set velocity (one velocity vector). + */ + void setVelocity(DOFVector<double> *origVelDOF_, + DOFVector<double> *velDOF_) + { + FUNCNAME("VelocityExt::setVelocity()"); + + nVelDOFs = 1; + + TEST_EXIT(origVelDOF_)("illegal velocity vector origVelDOF !\n"); + TEST_EXIT(velDOF_)("illegal velocity vector velDOF !\n"); + TEST_EXIT(origVelDOF_->getFESpace() == velDOF_->getFESpace()) + ("different fe spaces !\n"); + + origVelDOF.clear(); + velDOF.clear(); + + origVelDOF.push_back(origVelDOF_); + velDOF.push_back(velDOF_); + }; + + /** + * Set velocity (multiple velocity vectors). + */ + void setVelocity(std::vector<DOFVector<double> *> &origVelDOF_, + std::vector<DOFVector<double> *> &velDOF_) + { + FUNCNAME("VelocityExt::setVelocity()"); + + nVelDOFs = origVelDOF_.size(); + + TEST_EXIT(nVelDOFs > 0)("illegal number of velocity vectors !\n"); + TEST_EXIT(nVelDOFs == velDOF_.size())("different sizes !\n"); + + for (int i=0; i<nVelDOFs; ++i) { + TEST_EXIT(origVelDOF_[i])("illegal velocity vector origVelDOF !\n"); + TEST_EXIT(velDOF_[i])("illegal velocity vector velDOF !\n"); + TEST_EXIT((origVelDOF_[i])->getFESpace() == (velDOF_[i])->getFESpace()) + ("different fe spaces !\n"); + } + + origVelDOF = origVelDOF_; + velDOF = velDOF_; + }; + + /** + * Calculates the velocity for a vertex on a boundary element. + * lokInd gives the lokal index of the element vertices. + * indexV is the index of the vertex(with respect to the numeration on the element), + * for that the velocity shall be calculated. + */ + virtual void calcVelocityBoundary(DegreeOfFreedom *lokInd, + const int indexV); + + /** + * Calculates the velocity for a vertex on a non-boundary element. + * lokInd gives the lokal index of the element vertices. + * indexV is the index of the vertex(with respect to the numeration on the element), + * for that the velocity shall be calculated. + */ + void calcVelocity(DegreeOfFreedom *lokInd, const int indexV); + + /** + * Sets barycentric coordinates for 2D for a vertex on a boundary element. + * l_0. l_1, l_2 are the coordinates. + * indexV is the index of the vertex(with respect to the numeration on the element), + * for that the coordinates shall be stored. + */ + void setBarycentricCoords_2D_boundary(const double &l_0, const double &l_1, const double &l_2, const int indexV); + + /** + * Sets barycentric coordinates for 2D for a vertex on a non-boundary element. + * l_0. l_1, l_2 are the coordinates. + */ + void setBarycentricCoords_2D(const double &l_0, const double &l_1, const double &l_2); + + /** + * Calculates the barycentric coordinates for 2D for a vertex on a non-boundary element. + */ + void calcBarycentricCoords_2D(const double &c_delta, const double &c_alpha, const double &norm_zhminusyh, const double &norm_xhminusyh); + + /** + * Sets barycentric coordinates for 3D for a vertex on a boundary element + * (in case the coordinates are already known). + * l_0, l_1, l-2, l_3 are the coordinates. + * indexV is the index of the vertex(with respect to the numeration on the element), + * for that the coordinates shall be stored. + */ + void setBarycentricCoords_3D_boundary(const double &l_0, const double &l_1, const double &l_2, const double &l_3, const int indexV); + + /** + * Calculates the barycentric coordinates for 3D for a boundary vertex. + */ + void calcBarycentricCoords_3D_boundary(const DimVec<double> sp1, const DimVec<double> sp2, const double lambda, int i); + + /** + * Expands 3 coordinates from a face update to 4 coordinates and stores them in lamVec[index]. + * vertNum is the index of the element face the coordinates belong to(0,1,or 2). + */ + void copyAndExpandFaceCoords_3D(int vertNum,int index); + +/** + * Sets barycentric coordinates for 3D for a vertex on a non-boundary element. + * l_0, l_1, l-2, l_3 are the coordinates. + */ + void setBarycentricCoords_3D(const double &l_0, const double &l_1, const double &l_2, const double &l_3); + + /** + * Stores the index of element face with the shortest distance to the interface so far. + * (with respect to the order of calculation) + */ + void setIndexFaceWithShortestDist(int indexC); + + /** + * Sets the permutation of the vertices. + * vertNum is the vertex number(with respect to the numeration on the element), + * for that the update is calculated. + * mTrav is an index for determining the way of mesh-traverse. + * mTrav=0:level + * mTrav=1:traverse + */ + void setPermutation(int vertNum, int mTrav); + + /** + * Sets the permutation. + */ + void setPermutation(int vertNum); + + /** + * Sets the permutation of the vertices in 2D. + */ + void setPermutation_2D(int i_0, int i_1, int i_2); + + /** + * Sets the permutation of the vertices in 3D. + */ + void setPermutation_3D(int i_0, int i_1, int i_2, int i_3); + + /** + * Swaps two vertices in the permutation. + */ + void swapVertices(int i1, int i2); + + protected: + /** + * Original velocity vector. + */ + std::vector<DOFVector<double> *> origVelDOF; + + /** + * Dimension of mesh. + */ + int dim; + + /** + * Dof vector with extended velocity. + */ + std::vector<DOFVector<double> *> velDOF; + + /** + * Number of velocity vectors to be extended. + */ + int nVelDOFs; + + /** + * Vector with barycentric coordinates of points from which the velocity is extended. + * Whole vector is needed for the calculation on the boundary elements. + * For non-boundary elements the first place is used. + * If the update is calculated with the element faces, the places two-dim are used. + */ + VectorOfFixVecs<DimVec<double> > lamVec; + + /** + * If the update is calculated with the element faces, indexFace stores the number of the element + * face with the shortest distance to the interface. + * Otherwise indexFace is -1; + */ + int indexFace; + + /** + * List with the permutation of the vertices. + */ + DimVec<int> permutation; +}; + +#endif // VELOCITYEXT_H diff --git a/AMDiS/Reinit/src/VelocityExtFromVelocityField.cc b/AMDiS/Reinit/src/VelocityExtFromVelocityField.cc new file mode 100644 index 00000000..d90c25b4 --- /dev/null +++ b/AMDiS/Reinit/src/VelocityExtFromVelocityField.cc @@ -0,0 +1,42 @@ +#include "VelocityExtFromVelocityField.h" + +// double NormEps::eps = 0.0; + +void +VelocityExtFromVelocityField::calcVelocityBoundary(DegreeOfFreedom *locInd, + const int indexV) +{ + FUNCNAME("VelocityExtFromVelocityField::calcVelocityBoundary()"); + + // ===== Calculate normal velocity in element vertices. ===== + + // Get gradient of lSFct on element. + DimVec<double> lambda(dim, DEFAULT_VALUE, 0.0); + lambda[0] = 1.0; + WorldVector<double> elGrd; + + for (int i=0; i<=dim; ++i) + lSFctVal[i] = (*lSFct)[locInd[i]]; + + basFcts->evalGrdUh(lambda, elInfo->getGrdLambda(), lSFctVal, &elGrd); + + // Calculate normal velocity. + double fac = 1.0 / NormEps::calcNormEps(elGrd); + double sP; + for (int i=0; i<=dim; ++i) { + sP = 0.0; + for (int j=0; j<dim; ++j) { + sP += (*velField[j])[locInd[i]] * elGrd[j]; + } + elNormalVel[i] = fac * sP; + } + + + // ===== Extend normal velocity from interface to element vertices. ===== + double tempV=0.0; + for(int i=0; i<=dim; i++) + { + tempV += elNormalVel[i]*lamVec[indexV][i]; + } + (*(velDOF[0]))[locInd[indexV]]=tempV; +} diff --git a/AMDiS/Reinit/src/VelocityExtFromVelocityField.h b/AMDiS/Reinit/src/VelocityExtFromVelocityField.h new file mode 100644 index 00000000..d606a982 --- /dev/null +++ b/AMDiS/Reinit/src/VelocityExtFromVelocityField.h @@ -0,0 +1,181 @@ +#ifndef VELOCITYEXTFROMVELOCITYFIELD_H +#define VELOCITYEXTFROMVELOCITYFIELD_H + +#include "AdaptInfo.h" +#include "BasisFunction.h" +#include "DOFVector.h" +#include "ElInfo.h" +// #include "MemoryManager.h" + +#include "NormEps.h" +#include "VelocityExt.h" + +using namespace AMDiS; + + +/* #ifndef NORMEPS_H */ +/* #define NORMEPS_H */ +/* ///////////////////////////////////////////////////////////////////////////// */ +/* // c l a s s N o r m E p s // */ +/* ///////////////////////////////////////////////////////////////////////////// */ +/* class NormEps */ +/* { */ +/* public: */ +/* MEMORY_MANAGED(NormEps); */ + +/* /\** */ +/* * Calculates regularized norm of WorldVector x. */ +/* *\/ */ +/* static double calcNormEps(const WorldVector<double> &x) */ +/* { */ +/* FUNCNAME("NormEps::calcNormEps()"); */ + +/* static double result; */ + +/* TEST_EXIT(eps > 1.e-15)("illegal eps for norm regularization !\n"); */ +/* result = x*x + eps*eps; */ + +/* return(std::sqrt(result)); */ +/* }; */ + +/* /\** */ +/* * Calculates square of regularized norm of WorldVector x. */ +/* *\/ */ +/* static double calcNormEps2(const WorldVector<double> &x) */ +/* { */ +/* FUNCNAME("NormEps::calcNormEps2()"); */ + +/* static double result; */ + +/* TEST_EXIT(eps > 1.e-15)("illegal eps for norm regularization !\n"); */ +/* result = x*x + eps*eps; */ + +/* return(result); */ +/* }; */ + +/* /\** */ +/* * Set regularization epsilon eps. */ +/* *\/ */ +/* static inline void setEps() { */ +/* FUNCNAME("NormEps::setEps()"); */ + +/* eps = 0.0; */ +/* GET_PARAMETER(0, "NormEps->epsilon for norm regularization", "%f", &eps); */ + +/* TEST_EXIT(eps > 1.e-15) */ +/* ("illegal eps for norm regularization !\n"); */ +/* }; */ + +/* protected: */ +/* /\** */ +/* * Epsilon for regularization. */ +/* *\/ */ +/* static double eps; */ +/* }; */ +/* #endif // NORMEPS_H */ + +///////////////////////////////////////////////////////////////////////////// +// c l a s s V e l o c i t y E x t F r o m V e l o c i t y F i e l d // +///////////////////////////////////////////////////////////////////////////// +class VelocityExtFromVelocityField : public VelocityExt +{ + public: + MEMORY_MANAGED(VelocityExtFromVelocityField); + + /** + * Constructor. + */ + VelocityExtFromVelocityField(int dim_) + : VelocityExt(dim_), + lSFct(NULL), + elNormalVel(dim_, NO_INIT), + basFcts(NULL) + { + FUNCNAME("VelocityExtFromVelocityField::VelocityExtFromVelocityField()"); + + lSFctVal = GET_MEMORY(double, dim+1); + + // ===== set epsilon for norm regularization ===== + NormEps::setEps(); + }; + + /** + * Destructor. + */ + ~VelocityExtFromVelocityField() + { + FREE_MEMORY(lSFctVal, double, dim+1); + }; + + /** + * Set velocity field. + */ + void setVelocityField(std::vector<DOFVector<double> *> &velField_, + const DOFVector<double> *lSFct_, + DOFVector<double> *velDOF_) + { + FUNCNAME("VelocityExtFromVelocityField::setVelocityField()"); + + nVelDOFs = 1; + + velField = velField_; + lSFct = lSFct_; + velDOF.clear(); + velDOF.push_back(velDOF_); + origVelDOF.clear(); + + TEST_EXIT(lSFct)("level set function not defined !\n"); + TEST_EXIT((int)velField.size() == dim)("illegal velocity field !\n"); + TEST_EXIT(lSFct->getFESpace() == velDOF_->getFESpace()) + ("different feSpaces !\n"); + + basFcts = lSFct->getFESpace()->getBasisFcts(); + }; + + /** + * Adaption of VelocityExt::calcVelocityBoundary(). + * Used to initialize normal velocity at interface elements. + */ + void calcVelocityBoundary(DegreeOfFreedom *locInd, const int indexV); + + /** + * Sets elInfo. + */ + inline void setElInfo(ElInfo *elInfo_) { + elInfo = elInfo_; + }; + + protected: + /** + * Velocity field at interface. + */ + std::vector<DOFVector<double> *> velField; + + /** + * Interface is zero level set of level set function lSFct. + */ + const DOFVector<double> *lSFct; + + /** + * Normal velocity on a single element. Used to set normal velocity + * in velDOF on interface elements. + */ + DimVec<double> elNormalVel; + + /** + * Values of level set function in vertices of element. + */ + double *lSFctVal; + + /** + * Basis functions. + */ + const BasisFunction *basFcts; + + /** + * ElInfo used in calcVelocityBoundary(). + */ + ElInfo *elInfo; +}; + +#endif // VELOCITYEXTFROMVELOCITYFIELD_H -- GitLab