LCOV - code coverage report
Current view: top level - ugbase/lib_grid/algorithms/geom_obj_util - volume_util.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 107 0
Test Date: 2025-09-21 23:31:46 Functions: 0.0 % 10 0

            Line data    Source code
       1              : /*
       2              :  * Copyright (c) 2009-2015:  G-CSC, Goethe University Frankfurt
       3              :  * Authors: Sebastian Reiter, Martin Stepniewski
       4              :  * 
       5              :  * This file is part of UG4.
       6              :  * 
       7              :  * UG4 is free software: you can redistribute it and/or modify it under the
       8              :  * terms of the GNU Lesser General Public License version 3 (as published by the
       9              :  * Free Software Foundation) with the following additional attribution
      10              :  * requirements (according to LGPL/GPL v3 §7):
      11              :  * 
      12              :  * (1) The following notice must be displayed in the Appropriate Legal Notices
      13              :  * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
      14              :  * 
      15              :  * (2) The following notice must be displayed at a prominent place in the
      16              :  * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
      17              :  * 
      18              :  * (3) The following bibliography is recommended for citation and must be
      19              :  * preserved in all covered files:
      20              :  * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
      21              :  *   parallel geometric multigrid solver on hierarchically distributed grids.
      22              :  *   Computing and visualization in science 16, 4 (2013), 151-164"
      23              :  * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
      24              :  *   flexible software system for simulating pde based models on high performance
      25              :  *   computers. Computing and visualization in science 16, 4 (2013), 165-179"
      26              :  * 
      27              :  * This program is distributed in the hope that it will be useful,
      28              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      29              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      30              :  * GNU Lesser General Public License for more details.
      31              :  */
      32              : 
      33              : #include "volume_util.h"
      34              : #include "lib_grid/lg_base.h"
      35              : #include "edge_util.h"
      36              : #include "lib_grid/grid_objects/tetrahedron_rules.h"
      37              : 
      38              : using namespace std;
      39              : 
      40              : namespace ug
      41              : {
      42              : 
      43              : ////////////////////////////////////////////////////////////////////////
      44              : //      GetNeighbours - sreiter
      45            0 : void GetNeighbours(std::vector<Volume*>& vVolsOut, Grid& grid, Volume* v,
      46              :                                         int side, bool clearContainer)
      47              : {
      48            0 :         if(clearContainer)
      49              :                 vVolsOut.clear();
      50              : 
      51              : //      if VOLOPT_AUTOGENERATE_FACES and FACEOPT_STORE_ASSOCIATED_VOLUMES are
      52              : //      activated, we may use them to find the connected volume quite fast.
      53            0 :         if(grid.option_is_enabled(VOLOPT_AUTOGENERATE_FACES
      54              :                                                         | FACEOPT_STORE_ASSOCIATED_VOLUMES))
      55              :         {
      56            0 :                 Face* f = grid.get_face(v, side);
      57            0 :                 Grid::AssociatedVolumeIterator iterEnd = grid.associated_volumes_end(f);
      58            0 :                 for(Grid::AssociatedVolumeIterator iter = grid.associated_volumes_begin(f);
      59            0 :                         iter != iterEnd; ++iter)
      60              :                 {
      61            0 :                         if(*iter != v)
      62            0 :                                 vVolsOut.push_back(*iter);
      63              :                 }
      64              : 
      65              :                 return;
      66              :         }
      67              : 
      68              : //      we can't assume that associated faces exist.
      69              : //      we have to find the neighbour by hand.
      70              : //      mark all vertices of the side
      71            0 :         grid.begin_marking();
      72              : 
      73            0 :         FaceDescriptor fd;
      74            0 :         v->face_desc(side, fd);
      75              :         uint numFaceVrts = fd.num_vertices();
      76            0 :         for(uint i = 0; i < numFaceVrts; ++ i)
      77            0 :                 grid.mark(fd.vertex(i));
      78              : 
      79              : //      iterate over associated volumes of the first vertex and count
      80              : //      the number of marked vertices it contains.
      81              :         Vertex* vrt = fd.vertex(0);
      82            0 :         Grid::AssociatedVolumeIterator iterEnd = grid.associated_volumes_end(vrt);
      83            0 :         for(Grid::AssociatedVolumeIterator iter = grid.associated_volumes_begin(vrt);
      84            0 :                 iter != iterEnd; ++iter)
      85              :         {
      86            0 :                 Volume* vol = *iter;
      87            0 :                 if(vol != v){
      88              :                         size_t count = 0;
      89            0 :                         uint numVrts = vol->num_vertices();
      90            0 :                         for(uint i = 0; i < numVrts; ++i){
      91            0 :                                 if(grid.is_marked(vol->vertex(i)))
      92            0 :                                         ++count;
      93              :                         }
      94              : 
      95              :                 //      if the number of marked vertices in vol matches the
      96              :                 //      number of vertices of the specified side, we consider
      97              :                 //      the volume to be a neighbout of that side.
      98            0 :                         if(count == numFaceVrts)
      99            0 :                                 vVolsOut.push_back(vol);
     100              :                 }
     101              :         }
     102              : 
     103            0 :         grid.end_marking();
     104              : }
     105              : 
     106              : 
     107              : ////////////////////////////////////////////////////////////////////////////////////////////
     108              : //      CalculateVolumeMinHeight - mstepnie
     109            0 : number CalculateMinVolumeHeight(Tetrahedron* tet,
     110              :                                                                 Grid::VertexAttachmentAccessor<APosition>& aaPos)
     111              : {
     112              :         vector3 vfaceNormal;
     113              :         number minHeight = std::numeric_limits<double>::max();
     114              :         number tmpMinHeight;
     115              : 
     116              : 
     117              : //      Iterate over all tetrahedron vertices and calculate height to opposing face
     118            0 :         for(size_t i = 0; i < 4; ++i)
     119              :         {
     120            0 :                 Vertex* vrt = tet->vertex(i);
     121            0 :                 FaceDescriptor fd = tet->face_desc(tet->get_opposing_object(vrt).second);
     122              : 
     123            0 :                 CalculateNormal(vfaceNormal, &fd, aaPos);
     124            0 :                 tmpMinHeight = DistancePointToPlane(aaPos[vrt], aaPos[fd.vertex(0)], vfaceNormal);
     125              : 
     126            0 :                 if(tmpMinHeight < minHeight)
     127              :                 {
     128              :                         minHeight = tmpMinHeight;
     129              :                 }
     130              :         }
     131              : 
     132            0 :         return minHeight;
     133              : }
     134              : 
     135              : 
     136              : ////////////////////////////////////////////////////////////////////////////////////////////
     137              : //      CalculateTetrahedronAspectRatio - mstepnie
     138            0 : number CalculateTetrahedronAspectRatio(Grid& grid, Tetrahedron* tet,
     139              :                                                                            Grid::VertexAttachmentAccessor<AVector3>& aaPos)
     140              : {
     141              :         /*
     142              :          * optimal Aspect Ratio of a regular tetrahedron with edge lengths a:
     143              :          * Q = hmin/lmax = sqrt(2/3)*a / a = 0.8164...
     144              :          *
     145              :          * Info: return value is normalized by factor sqrt(3/2)
     146              :          * (s. Shewchuk 2002)
     147              :          */
     148              : 
     149              :         number aspectRatio;
     150              :         number maxEdgeLength;
     151              :         number minTetrahedronHeight;
     152              : 
     153              : //      Collect tetrahedron edges, find longest edge and calculate its length
     154              :         vector<Edge*> edges;
     155              :         CollectAssociated(edges, grid, tet);
     156            0 :         Edge* longestEdge = FindLongestEdge(edges.begin(), edges.end(), aaPos);
     157            0 :         maxEdgeLength = EdgeLength(longestEdge, aaPos);
     158              : 
     159              : //      Calculate the minimal tetrahedron height
     160            0 :         minTetrahedronHeight = CalculateMinVolumeHeight(tet, aaPos);
     161              : 
     162              : //      Calculate the aspect ratio
     163            0 :         aspectRatio =  std::sqrt(3/2.0) * minTetrahedronHeight / maxEdgeLength;
     164              : 
     165            0 :         return aspectRatio;
     166            0 : }
     167              : 
     168              : ////////////////////////////////////////////////////////////////////////////////////////////
     169              : // CalculateHexahedronAspectRatio
     170              : ////////////////////////////////////////////////////////////////////////////////////////////
     171            0 : number CalculateHexahedronAspectRatio(Grid& grid, Hexahedron* hex,
     172              :                                                                            Grid::VertexAttachmentAccessor<AVector3>& aaPos)
     173              : {
     174              :         /*
     175              :          * Another important indicator of the mesh quality is the aspect ratio.
     176              :          * The aspect ratio is a measure of the stretching of a cell. It is computed
     177              :          * as the ratio of the maximum value to the minimum value of any of the
     178              :          * following distances: the normal distances between the cell centroid and
     179              :          * face centroids (computed as a dot product of the distance vector and the
     180              :          * face normal), and the distances between the cell centroid and nodes.
     181              :          * For a unit cube (see Figure 5.23: Calculating the Aspect Ratio for a Unit
     182              :          * Cube), the maximum distance is 0.866, and the minimum distance is 0.5,
     183              :          * so the aspect ratio is 1.732. This type of definition can be applied on
     184              :          * any type of mesh, including polyhedral.
     185              :          *
     186              :          * \see https://www.sharcnet.ca/Software/Ansys/17.0/en-us/help/flu_ug/flu_ug_mesh_quality.html
     187              :          *
     188              :          */
     189              :         vector<Face*> faces;
     190              :         CollectAssociated(faces, grid, hex);
     191            0 :         ug::vector3 center = CalculateCenter(hex, aaPos);
     192              : 
     193              :         /// Max distance to face center
     194              :         std::vector<number> As;
     195            0 :         for (size_t i = 0; i < faces.size(); i++)
     196              :         {
     197              :                 vector3 dir;
     198            0 :                 vector3 faceCenter = CalculateCenter(faces[i], aaPos);
     199              :                 VecSubtract(dir, faceCenter, center);
     200              :                 vector3 n;
     201            0 :                 CalculateNormal(n, faces[i], aaPos);
     202            0 :                 number dist = VecDot(dir, n);
     203            0 :                 As.push_back(dist);
     204              :         }
     205            0 :         number max = *std::max_element(As.begin(), As.end());
     206              : 
     207              :         /// Min distance to node of hexaeder
     208              :         std::vector<number> Bs;
     209            0 :         for (size_t i = 0; i < hex->num_vertices(); i++)
     210              :         {
     211            0 :                 number dist = VecDistance(aaPos[hex->vertex(i)], center);
     212            0 :                 Bs.push_back(dist);
     213              :         }
     214            0 :         number min = *std::min_element(Bs.begin(), Bs.end());
     215              : 
     216              :         UG_COND_WARNING(std::abs(min) < SMALL, "Near 0-length minimum distance detected.");
     217              : 
     218            0 :         return max / min;
     219            0 : }
     220              : 
     221              : ////////////////////////////////////////////////////////////////////////////////////////////
     222              : // CalculateHexahedronAspectRatio
     223              : // order of vertices should be the same as described in \sa PyramidDescriptor
     224              : // v1, v2, v3, v4: bottom-vertices in counterclockwise order (if viewed from the top).
     225              : // v5: top-vertex.
     226              : ////////////////////////////////////////////////////////////////////////////////////////////
     227            0 : number CalculatePyramidAspectRatio
     228              : (
     229              :         Grid& grid,
     230              :         Pyramid* pyr,
     231              :         Grid::VertexAttachmentAccessor<AVector3>& aaPos
     232              : )
     233              : {
     234              :         // average edge length of base of pyramid
     235              :         number avg_edge_length = 0;
     236            0 :         for (size_t i = 0; i < 4; i++)
     237              :         {
     238            0 :                 avg_edge_length += VecDistance(aaPos[pyr->vertex(i%4)], aaPos[pyr->vertex((i+1)%4)]);
     239              :         }
     240            0 :         avg_edge_length /= 4;
     241              : 
     242              :         // distance from base to top of pyramid
     243            0 :         const Face* const face = grid.get_element(FaceDescriptor(pyr->vertex(0), pyr->vertex(1), pyr->vertex(2), pyr->vertex(3)));
     244              :         vector3 normal;
     245            0 :         CalculateNormal(normal, face, aaPos);
     246            0 :         const number distance = VecDot(normal, aaPos[pyr->vertex(4)]);
     247              : 
     248              :         // AR of pyramid is ratio between distance and average edge length of base
     249            0 :         return distance / avg_edge_length;
     250              : }
     251              : 
     252              : 
     253              : ////////////////////////////////////////////////////////////////////////////////////////////
     254              : //      CalculateTetrahedronRootMeanSquareFaceArea - mstepnie
     255              : ////////////////////////////////////////////////////////////////////////////////////////////
     256              : UG_API
     257            0 : number CalculateTetrahedronRootMeanSquareFaceArea(Grid& grid,
     258              :                                                                                                   Tetrahedron* tet,
     259              :                                                                                                   Grid::VertexAttachmentAccessor<APosition>& aaPos)
     260              : {
     261              : //      Collect tetrahedron faces
     262              :         vector<Face*> faces;
     263              :         CollectAssociated(faces, grid, tet);
     264              : 
     265              :         number A;
     266              :         number A_rms = 0.0;
     267              : 
     268            0 :         for(size_t i = 0; i < faces.size(); ++i)
     269              :         {
     270            0 :                 A = FaceArea(faces[i], aaPos);
     271            0 :                 A_rms += A*A;
     272              :         }
     273              : 
     274            0 :         A_rms *= 0.25;
     275            0 :         A_rms = std::sqrt(A_rms);
     276              : 
     277            0 :         return A_rms;
     278            0 : }
     279              : 
     280              : 
     281              : ////////////////////////////////////////////////////////////////////////////////////////////
     282              : //      CalculateTetrahedronVolToRMSFaceAreaRatio - mstepnie
     283              : ////////////////////////////////////////////////////////////////////////////////////////////
     284              : UG_API
     285            0 : number CalculateTetrahedronVolToRMSFaceAreaRatio(Grid& grid,
     286              :                                                                                                  Tetrahedron* tet,
     287              :                                                                                                  Grid::VertexAttachmentAccessor<APosition>& aaPos)
     288              : {
     289              :         /*
     290              :          * optimal volume to root-mean-square face area ratio of a
     291              :          * regular tetrahedron with edge lengths a:
     292              :          * Q = V/A_rms^(3/2)
     293              :          *
     294              :          * Info: return value is normalized by factor pow(3, 7/4.0) / 2.0 / sqrt(2);
     295              :          * (s. Shewchuk 2002)
     296              :          */
     297              : 
     298            0 :         number vol = CalculateTetrahedronVolume(aaPos[tet->vertex(0)],
     299            0 :                                                                                         aaPos[tet->vertex(1)],
     300            0 :                                                                                         aaPos[tet->vertex(2)],
     301            0 :                                                                                         aaPos[tet->vertex(3)]);
     302              : 
     303            0 :         number A_rms = CalculateTetrahedronRootMeanSquareFaceArea(grid, tet, aaPos);
     304              :         number normalization = std::pow(3, 7/4.0) / 2.0 / std::sqrt(2);
     305              : 
     306            0 :         return normalization * vol / std::pow(A_rms, 3/2.0);
     307              : }
     308              : 
     309              : ////////////////////////////////////////////////////////////////////////////////////////////
     310              : //      CalculateHexahedronVolToRMSFaceAreaRatio - sgrein
     311              : ////////////////////////////////////////////////////////////////////////////////////////////
     312              : UG_API
     313            0 : number CalculateHexahedronVolToRMSFaceAreaRatio(Grid& grid,
     314              :                                                                                                 Hexahedron* hex,
     315              :                                                                                                 Grid::VertexAttachmentAccessor<APosition>& aaPos)
     316              : {
     317            0 :         UG_THROW("ERROR in CalculateHexahedronVolToRMSFaceAreaRatio: Not yet implemented");
     318              :         return NAN;
     319              : }
     320              : 
     321              : 
     322              : ////////////////////////////////////////////////////////////////////////
     323              : // IntersectPlaneWithTetrahedron
     324            0 : size_t IntersectPlaneWithTetrahedron
     325              : (
     326              :         vector3 intsOut[4],
     327              :         const vector3& planePoint,
     328              :         const vector3& planeNormal,
     329              :         const vector3 t[4]
     330              : )
     331              : {
     332              :     using namespace tet_rules;
     333              :     size_t numIntersections = 0;
     334              :     int intersectingEdges[4];
     335            0 :     for(size_t ie = 0; ie < (size_t) NUM_EDGES; ++ie)
     336              :     {
     337            0 :         vector3 v0 = t[EDGE_VRT_INDS[ie][0]];
     338            0 :         vector3 v1 = t[EDGE_VRT_INDS[ie][1]];
     339              :         vector3 dir;
     340              :         VecSubtract(dir, v1, v0);
     341              : 
     342              :         vector3 p;
     343              :         number s;
     344            0 :         if(RayPlaneIntersection(p, s, v0, dir, planePoint, planeNormal))
     345              :         {
     346            0 :             if(s > 0 && s < 1)
     347              :             {
     348            0 :                 if (numIntersections >= 4) // to avoid numerical artefacts
     349            0 :                         UG_THROW ("IntersectPlaneWithTetrahedron:"
     350              :                                 " Illegal number of intersections of a plane with a tetrahedron.");
     351            0 :                 intsOut[numIntersections] = p;
     352            0 :                 intersectingEdges[numIntersections] = ie;
     353            0 :                 ++numIntersections;
     354              :             }
     355              :         }
     356              :     }
     357              :     
     358            0 :     if(numIntersections == 4)
     359              :     {
     360            0 :         if(intersectingEdges[1] == OPPOSED_EDGE[intersectingEdges[0]])
     361              :             swap(intsOut[1], intsOut[2]);
     362            0 :         else if(intersectingEdges[2] == OPPOSED_EDGE[intersectingEdges[1]])
     363              :             swap(intsOut[0], intsOut[1]);
     364              :     }
     365              : 
     366            0 :     return numIntersections;
     367              : }
     368              : 
     369            0 : void InsertCenterVertex(Grid& g, Volume* vol, Vertex* vrt, bool eraseOldVol)
     370              : {
     371              : //      get the sides of the volume and create new elements
     372            0 :         FaceDescriptor fd;
     373            0 :         for(size_t i = 0; i < vol->num_faces(); ++i){
     374            0 :                 vol->face_desc(i, fd);
     375            0 :                 if(fd.num_vertices() == 3){
     376              :                 //      create a tetrahedron
     377            0 :                         g.create<Tetrahedron>(TetrahedronDescriptor(fd.vertex(2), fd.vertex(1),
     378              :                                                                                                                 fd.vertex(0), vrt), vol);
     379              :                 }
     380            0 :                 else if(fd.num_vertices() == 4){
     381              :                 //      create a pyramid
     382            0 :                         g.create<Pyramid>(PyramidDescriptor(fd.vertex(3), fd.vertex(2),
     383              :                                                                                                 fd.vertex(1), fd.vertex(0), vrt), vol);
     384              :                 }
     385              :                 else{
     386            0 :                         UG_THROW("Unsupported face type in InsertCenterVertex (#Corners "
     387              :                                         << fd.num_vertices() << ")");
     388              :                 }
     389              :         }
     390              : 
     391            0 :         if(eraseOldVol)
     392            0 :                 g.erase(vol);
     393            0 : }
     394              : 
     395              : /*
     396              : double CMesh::calculate_volume_gauss() {
     397              :         
     398              :         double volume = 0.0;
     399              :         
     400              :         for(uint i = 0; i < number_of_triangles; i++) {
     401              :                 
     402              :          uint a = triangles[i].a;
     403              :                 uint b = triangles[i].b;
     404              :                 uint c = triangles[i].c;
     405              :                 
     406              :                 //printf("%f %f %f\n", vertices[b].x(), vertices[b].y(), vertices[b].z());
     407              :                 
     408              :                 double x = (vertices[b].y() - vertices[a].y()) * (vertices[c].z() - vertices[a].z()) - (vertices[b].z() - vertices[a].z()) * (vertices[c].y() - vertices[a].y());
     409              :                 double y = (vertices[b].z() - vertices[a].z()) * (vertices[c].x() - vertices[a].x()) - (vertices[b].x() - vertices[a].x()) * (vertices[c].z() - vertices[a].z());
     410              :                 double z = (vertices[b].x() - vertices[a].x()) * (vertices[c].y() - vertices[a].y()) - (vertices[b].y() - vertices[a].y()) * (vertices[c].x() - vertices[a].x());
     411              :                 
     412              :                 double length = sqrt(x * x + y * y + z * z);
     413              :                 
     414              :                 double surface = 0.5 * length;
     415              :                 
     416              :                 if(length > 0.0) {
     417              :                 
     418              :                  x /= length;
     419              :                 y /= length;
     420              :                 z /= length;
     421              :                         
     422              :                         double sx = (vertices[a].x() + vertices[b].x() + vertices[c].x()) / 3.0;
     423              :                         double sy = (vertices[a].y() + vertices[b].y() + vertices[c].y()) / 3.0;
     424              :                         double sz = (vertices[a].z() + vertices[b].z() + vertices[c].z()) / 3.0;
     425              :                         
     426              :                         volume += 1.0 / 3.0 * surface * (sx * x + sy * y + sz * z);
     427              :                 
     428              :                 }
     429              :                 
     430              :                 
     431              :         }
     432              :         
     433              :         return volume;
     434              :         
     435              :         
     436              :         
     437              : }
     438              : */
     439              : }//     end of namespace
     440              : 
     441              : 
        

Generated by: LCOV version 2.0-1