ViennaGrid - The Vienna Grid Library
2.1.0
|
00001 #ifndef VIENNAGRID_ALGORITHM_VORONOI_HPP 00002 #define VIENNAGRID_ALGORITHM_VORONOI_HPP 00003 00004 /* ======================================================================= 00005 Copyright (c) 2011-2014, Institute for Microelectronics, 00006 Institute for Analysis and Scientific Computing, 00007 TU Wien. 00008 00009 ----------------- 00010 ViennaGrid - The Vienna Grid Library 00011 ----------------- 00012 00013 License: MIT (X11), see file LICENSE in the base directory 00014 ======================================================================= */ 00015 00016 #include <iostream> 00017 #include <sstream> 00018 #include <string> 00019 #include <stdexcept> 00020 00021 #include "viennagrid/forwards.hpp" 00022 #include "viennagrid/mesh/segmentation.hpp" 00023 #include "viennagrid/mesh/coboundary_iteration.hpp" 00024 #include "viennagrid/algorithm/circumcenter.hpp" 00025 #include "viennagrid/algorithm/spanned_volume.hpp" 00026 #include "viennagrid/algorithm/volume.hpp" 00027 #include "viennagrid/algorithm/inner_prod.hpp" 00028 00029 00035 namespace viennagrid 00036 { 00037 namespace result_of 00038 { 00043 template <typename ConstCellHandleT> 00044 struct voronoi_cell_contribution 00045 { 00046 typedef std::vector< std::pair<ConstCellHandleT, double> > type; 00047 }; 00048 } 00049 00050 00051 namespace detail 00052 { 00055 template <typename ContainerT, typename PairT> 00056 void voronoi_unique_quantity_update(ContainerT & container, 00057 PairT const & update_pair) 00058 { 00059 bool found = false; 00060 for (typename ContainerT::iterator it = container.begin(); 00061 it != container.end(); 00062 ++it) 00063 { 00064 if (it->first == update_pair.first) 00065 { 00066 it->second += update_pair.second; 00067 found = true; 00068 break; 00069 } 00070 } 00071 00072 if (!found) 00073 { 00074 container.push_back(update_pair); 00075 } 00076 } 00077 00078 00080 template <typename CellTag, 00081 typename MeshT, 00082 typename InterfaceAreaAccessorT, 00083 typename InterfaceAreaCellContributionAccessorT, 00084 typename VertexBoxVolumeAccessorT, 00085 typename VertexBoxVolumeCellContributionAccessorT, 00086 typename EdgeBoxVolumeAccessorT, 00087 typename EdgeBoxVolumeCellContributionAccessorT> 00088 void write_voronoi_info(MeshT const & mesh_obj, 00089 InterfaceAreaAccessorT interface_area_accessor, 00090 InterfaceAreaCellContributionAccessorT interface_area_cell_contribution_accessor, 00091 VertexBoxVolumeAccessorT vertex_box_volume_accessor, 00092 VertexBoxVolumeCellContributionAccessorT vertex_box_volume_cell_contribution_accessor, 00093 EdgeBoxVolumeAccessorT edge_box_volume_accessor, 00094 EdgeBoxVolumeCellContributionAccessorT edge_box_volume_cell_contribution_accessor, 00095 viennagrid::simplex_tag<1>) 00096 { 00097 typedef typename viennagrid::result_of::element<MeshT, CellTag>::type CellType; 00098 00099 typedef typename viennagrid::result_of::element<MeshT, vertex_tag>::type VertexType; 00100 00101 typedef typename viennagrid::result_of::const_element_range<MeshT, CellTag>::type CellRange; 00102 typedef typename viennagrid::result_of::iterator<CellRange>::type CellIterator; 00103 00104 00105 typedef typename viennagrid::result_of::const_element_range<CellType, vertex_tag>::type VertexOnCellRange; 00106 typedef typename viennagrid::result_of::iterator<VertexOnCellRange>::type VertexOnCellIterator; 00107 00108 // 00109 // Write Voronoi information 00110 // 00111 00112 CellRange cells = viennagrid::elements<CellTag>(mesh_obj); 00113 for (CellIterator cit = cells.begin(); 00114 cit != cells.end(); 00115 ++cit) 00116 { 00117 interface_area_accessor(*cit) = 1; 00118 interface_area_cell_contribution_accessor(*cit).push_back( std::make_pair( cit.handle(), 1) ); 00119 00120 double edge_contribution = 0; 00121 VertexOnCellRange vertices_on_cell = viennagrid::elements<VertexType>(*cit); 00122 for (VertexOnCellIterator vocit = vertices_on_cell.begin(); 00123 vocit != vertices_on_cell.end(); 00124 ++vocit) 00125 { 00126 double contribution = volume(*cit) / 2.0; 00127 edge_contribution += contribution; 00128 00129 vertex_box_volume_accessor(*vocit) += contribution; 00130 vertex_box_volume_cell_contribution_accessor(*vocit).push_back( std::make_pair( cit.handle(), contribution) ); 00131 } 00132 00133 edge_box_volume_accessor(*cit) = edge_contribution; 00134 edge_box_volume_cell_contribution_accessor(*cit).push_back( std::make_pair( cit.handle(), edge_contribution) ); 00135 00136 } 00137 } 00138 00140 template <typename CellTag, 00141 typename MeshT, 00142 typename InterfaceAreaAccessorT, 00143 typename InterfaceAreaCellContributionAccessorT, 00144 typename VertexBoxVolumeAccessorT, 00145 typename VertexBoxVolumeCellContributionAccessorT, 00146 typename EdgeBoxVolumeAccessorT, 00147 typename EdgeBoxVolumeCellContributionAccessorT> 00148 void write_voronoi_info(MeshT const & mesh_obj, 00149 InterfaceAreaAccessorT interface_area_accessor, 00150 InterfaceAreaCellContributionAccessorT interface_area_cell_contribution_accessor, 00151 VertexBoxVolumeAccessorT vertex_box_volume_accessor, 00152 VertexBoxVolumeCellContributionAccessorT vertex_box_volume_cell_contribution_accessor, 00153 EdgeBoxVolumeAccessorT edge_box_volume_accessor, 00154 EdgeBoxVolumeCellContributionAccessorT edge_box_volume_cell_contribution_accessor, 00155 viennagrid::hypercube_tag<1>) 00156 { 00157 write_voronoi_info<CellTag>(mesh_obj, 00158 interface_area_accessor, interface_area_cell_contribution_accessor, 00159 vertex_box_volume_accessor, vertex_box_volume_cell_contribution_accessor, 00160 edge_box_volume_accessor, edge_box_volume_cell_contribution_accessor, 00161 viennagrid::simplex_tag<1>()); 00162 } 00163 00164 // 00165 // Voronoi information in two (topological) dimensions 00166 // 00168 template <typename CellTag, 00169 typename MeshT, 00170 typename InterfaceAreaAccessorT, 00171 typename InterfaceAreaCellContributionAccessorT, 00172 typename VertexBoxVolumeAccessorT, 00173 typename VertexBoxVolumeCellContributionAccessorT, 00174 typename EdgeBoxVolumeAccessorT, 00175 typename EdgeBoxVolumeCellContributionAccessorT> 00176 void write_voronoi_info(MeshT const & mesh_obj, 00177 InterfaceAreaAccessorT interface_area_accessor, 00178 InterfaceAreaCellContributionAccessorT interface_area_cell_contribution_accessor, 00179 VertexBoxVolumeAccessorT vertex_box_volume_accessor, 00180 VertexBoxVolumeCellContributionAccessorT vertex_box_volume_cell_contribution_accessor, 00181 EdgeBoxVolumeAccessorT edge_box_volume_accessor, 00182 EdgeBoxVolumeCellContributionAccessorT edge_box_volume_cell_contribution_accessor, 00183 viennagrid::quadrilateral_tag) 00184 { 00185 typedef typename viennagrid::result_of::element<MeshT, CellTag>::type CellType; 00186 00187 typedef typename viennagrid::result_of::point<MeshT>::type PointType; 00188 typedef typename viennagrid::result_of::element<MeshT, vertex_tag>::type VertexType; 00189 typedef typename viennagrid::result_of::element<MeshT, line_tag>::type EdgeType; 00190 00191 typedef typename viennagrid::result_of::const_element_range<MeshT, CellTag>::type CellRange; 00192 typedef typename viennagrid::result_of::iterator<CellRange>::type CellIterator; 00193 00194 typedef typename viennagrid::result_of::const_element_range<CellType, line_tag>::type EdgeOnCellRange; 00195 typedef typename viennagrid::result_of::iterator<EdgeOnCellRange>::type EdgeOnCellIterator; 00196 00197 typedef typename viennagrid::result_of::const_element_range<EdgeType, vertex_tag>::type VertexOnEdgeRange; 00198 typedef typename viennagrid::result_of::iterator<VertexOnEdgeRange>::type VertexOnEdgeIterator; 00199 00200 00201 // 00202 // Algorithm: Iterate over all cells, compute circumcenter and add interface area to edge, box volume to vertex. 00203 // 00204 00205 CellRange cells = viennagrid::elements<CellTag>(mesh_obj); 00206 for (CellIterator cit = cells.begin(); 00207 cit != cells.end(); 00208 ++cit) 00209 { 00210 PointType circ_center = circumcenter(*cit); 00211 00212 //iterate over edges: 00213 EdgeOnCellRange edges_on_cell = viennagrid::elements<EdgeType>(*cit); 00214 for (EdgeOnCellIterator eocit = edges_on_cell.begin(); 00215 eocit != edges_on_cell.end(); 00216 ++eocit) 00217 { 00218 PointType edge_midpoint = circumcenter(*eocit); 00219 00220 // interface contribution: 00221 double interface_contribution = spanned_volume(circ_center, edge_midpoint); 00222 00223 interface_area_accessor(*eocit) += interface_contribution; 00224 interface_area_cell_contribution_accessor(*eocit).push_back( std::make_pair( cit.handle(), interface_contribution) ); 00225 00226 //box volume contribution: 00227 double edge_contribution = 0; 00228 VertexOnEdgeRange vertices_on_edge = viennagrid::elements<VertexType>(*eocit); 00229 for (VertexOnEdgeIterator voeit = vertices_on_edge.begin(); 00230 voeit != vertices_on_edge.end(); 00231 ++voeit) 00232 { 00233 double contribution = spanned_volume(circ_center, edge_midpoint, viennagrid::point(*voeit)); 00234 edge_contribution += contribution; 00235 00236 vertex_box_volume_accessor(*voeit) += contribution; 00237 vertex_box_volume_cell_contribution_accessor(*voeit).push_back( std::make_pair( cit.handle(), contribution) ); 00238 } 00239 00240 edge_box_volume_accessor(*eocit) += edge_contribution; 00241 edge_box_volume_cell_contribution_accessor(*eocit).push_back( std::make_pair( cit.handle(), edge_contribution) ); 00242 00243 } //for edges on cells 00244 00245 } //for cells 00246 00247 } //write_voronoi_info(triangle_tag) 00248 00249 00251 //template <typename PointType, typename ConfigType> 00252 //PointType point_to_local_coordinates(PointType const & p, viennagrid::element<ConfigType, viennagrid::simplex_tag<2> > const & triangle) 00253 template<typename TriangleType> 00254 typename viennagrid::result_of::point<TriangleType>::type point_to_local_coordinates( typename viennagrid::result_of::point<TriangleType>::type const & p, 00255 const TriangleType & triangle) 00256 { 00257 typedef TriangleType CellType; 00258 typedef typename viennagrid::result_of::const_element_range<CellType, vertex_tag>::type VertexRange; 00259 typedef typename viennagrid::result_of::point<TriangleType>::type PointType; 00260 00261 VertexRange vertices = viennagrid::elements<viennagrid::vertex_tag>(triangle); 00262 00263 PointType const & a = viennagrid::point(vertices[0]); 00264 PointType const & b = viennagrid::point(vertices[1]); 00265 PointType const & c = viennagrid::point(vertices[2]); 00266 00267 PointType v0 = b - a; 00268 PointType v1 = c - a; 00269 PointType vp = p - a; 00270 00271 double det = v0[0] * v1[1] - v0[1] * v1[0]; 00272 00273 return PointType( (v1[1] * vp[0] - v1[0] * vp[1]) / det, 00274 (v0[0] * vp[1] - v0[1] * vp[0]) / det ); 00275 } 00276 00277 00279 template <typename PointType> 00280 PointType line_intersection(PointType const & a, PointType const & b, 00281 PointType const & c, PointType const & d) 00282 { 00283 double det = (a[0] - b[0])*(c[1] - d[1]) - (a[1] - b[1])*(c[0] - d[0]); 00284 00285 if (std::fabs(det) < 1e-10 * viennagrid::norm(b-a)) 00286 std::cerr << "viennagrid::detail::line_intersection(): Warning: Determinant is close to zero!" << std::endl; 00287 00288 double px = (a[0]*b[1] - a[1]*b[0]) * (c[0] - d[0]) 00289 - (a[0] - b[0]) * (c[0]*d[1] - c[1]*d[0]); 00290 double py = (a[0]*b[1] - a[1]*b[0]) * (c[1] - d[1]) 00291 - (a[1] - b[1]) * (c[0]*d[1] - c[1]*d[0]); 00292 00293 return PointType(px / det, py / det); 00294 } 00295 00296 00298 template <typename CellTag, 00299 typename MeshT, 00300 typename InterfaceAreaAccessorT, 00301 typename InterfaceAreaCellContributionAccessorT, 00302 typename VertexBoxVolumeAccessorT, 00303 typename VertexBoxVolumeCellContributionAccessorT, 00304 typename EdgeBoxVolumeAccessorT, 00305 typename EdgeBoxVolumeCellContributionAccessorT> 00306 void write_voronoi_info(MeshT const & mesh_obj, 00307 InterfaceAreaAccessorT interface_area_accessor, 00308 InterfaceAreaCellContributionAccessorT interface_area_cell_contribution_accessor, 00309 VertexBoxVolumeAccessorT vertex_box_volume_accessor, 00310 VertexBoxVolumeCellContributionAccessorT vertex_box_volume_cell_contribution_accessor, 00311 EdgeBoxVolumeAccessorT edge_box_volume_accessor, 00312 EdgeBoxVolumeCellContributionAccessorT edge_box_volume_cell_contribution_accessor, 00313 viennagrid::triangle_tag) 00314 { 00315 typedef typename viennagrid::result_of::element<MeshT, CellTag>::type CellType; 00316 typedef typename viennagrid::result_of::const_handle<MeshT, CellTag>::type ConstCellHandleType; 00317 00318 typedef typename viennagrid::result_of::point<MeshT>::type PointType; 00319 typedef typename viennagrid::result_of::element<MeshT, vertex_tag>::type VertexType; 00320 typedef typename viennagrid::result_of::element<MeshT, line_tag>::type EdgeType; 00321 00322 typedef typename viennagrid::result_of::const_element_range<MeshT, CellTag>::type CellRange; 00323 typedef typename viennagrid::result_of::iterator<CellRange>::type CellIterator; 00324 00325 typedef typename viennagrid::result_of::const_element_range<CellType, vertex_tag>::type VertexOnCellRange; 00326 00327 typedef typename viennagrid::result_of::const_coboundary_range<MeshT, EdgeType, CellTag>::type CellOnEdgeRange; 00328 00329 // typedef typename viennagrid::result_of::const_element_range<EdgeType, CellTag>::type CellOnEdgeRange; 00330 typedef typename viennagrid::result_of::iterator<CellOnEdgeRange>::type CellOnEdgeIterator; 00331 00332 typedef typename viennagrid::result_of::const_element_range<CellType, line_tag>::type EdgeOnCellRange; 00333 typedef typename viennagrid::result_of::iterator<EdgeOnCellRange>::type EdgeOnCellIterator; 00334 00335 typedef typename viennagrid::result_of::const_element_range<EdgeType, vertex_tag>::type VertexOnEdgeRange; 00336 typedef typename viennagrid::result_of::iterator<VertexOnEdgeRange>::type VertexOnEdgeIterator; 00337 00338 CellRange cells = viennagrid::elements<CellTag>(mesh_obj); 00339 for (CellIterator cit = cells.begin(); 00340 cit != cells.end(); 00341 ++cit) 00342 { 00343 PointType circ_center = circumcenter(*cit); 00344 00345 00346 PointType circ_center_local = point_to_local_coordinates(circ_center, *cit); 00347 00348 if ( (circ_center_local[0] < 0) 00349 || (circ_center_local[1] < 0) 00350 || (circ_center_local[0] + circ_center_local[1] > 1.0) ) //circumcenter is outside triangle - things get complicated 00351 { 00352 EdgeOnCellRange edges_on_cell = viennagrid::elements<EdgeType>(*cit); 00353 VertexOnCellRange vertices_on_cell = viennagrid::elements<VertexType>(*cit); 00354 00355 // 00356 // Step 1: Get intersected edge, find opposite vertex and the 'other' triangle 00357 // 00358 EdgeType const * intersected_edge_ptr = NULL; 00359 VertexType const * opposite_vertex_ptr = NULL; 00360 if (circ_center_local[1] < 0) 00361 { 00362 intersected_edge_ptr = &(edges_on_cell[0]); 00363 opposite_vertex_ptr = &(vertices_on_cell[2]); 00364 } 00365 else if (circ_center_local[0] < 0) 00366 { 00367 intersected_edge_ptr = &(edges_on_cell[1]); 00368 opposite_vertex_ptr = &(vertices_on_cell[1]); 00369 } 00370 else 00371 { 00372 intersected_edge_ptr = &(edges_on_cell[2]); 00373 opposite_vertex_ptr = &(vertices_on_cell[0]); 00374 } 00375 00376 //find 'other' triangle 00377 ConstCellHandleType other_cell; 00378 00379 // CellType const * other_cell = NULL; 00380 CellOnEdgeRange other_cells = viennagrid::coboundary_elements<EdgeType, CellTag>(mesh_obj, viennagrid::handle(mesh_obj, *intersected_edge_ptr) ); 00381 detail::set_handle_invalid( other_cells, other_cell ); 00382 00383 for (CellOnEdgeIterator coeit = other_cells.begin(); 00384 coeit != other_cells.end(); 00385 ++coeit) 00386 { 00387 if ( coeit->id() != cit->id() ) 00388 { 00389 other_cell = coeit.handle(); 00390 break; 00391 } 00392 } 00393 00394 // 00395 // Step 2: Precompute intersection of opposite vertex with intersected edge 00396 // 00397 VertexOnEdgeRange vertices_on_intersected_edge = viennagrid::elements<VertexType>(*intersected_edge_ptr); 00398 PointType opposite_vertex_edge_intersection = line_intersection( viennagrid::point(*opposite_vertex_ptr), circ_center, 00399 viennagrid::point(vertices_on_intersected_edge[0]), 00400 viennagrid::point(vertices_on_intersected_edge[1])); 00401 00402 // 00403 // Step 3: Compute contributions 00404 // 00405 for (EdgeOnCellIterator eocit = edges_on_cell.begin(); 00406 eocit != edges_on_cell.end(); 00407 ++eocit) 00408 { 00409 PointType edge_midpoint = circumcenter(*eocit); 00410 00411 if ( intersected_edge_ptr != &(*eocit) ) // non-intersected edge: Split contributions into contributions from cell itself and contribution from other cell 00412 { 00413 PointType edge_intersection = line_intersection( edge_midpoint, circ_center, 00414 viennagrid::point(vertices_on_intersected_edge[0]), 00415 viennagrid::point(vertices_on_intersected_edge[1])); 00416 00417 // 00418 // Interface contributions (two contributions: From edge midpoint to intersected edge, and from intersected edge to circumcenter) 00419 // 00420 00421 double interface_contribution = 0; 00422 00423 // contribution from cell: 00424 interface_contribution = spanned_volume(edge_intersection, edge_midpoint); 00425 00426 interface_area_accessor(*eocit) += interface_contribution; 00427 voronoi_unique_quantity_update(interface_area_cell_contribution_accessor(*eocit), std::make_pair( cit.handle(), interface_contribution) ); 00428 00429 // contribution from other cell containing the circumcenter: 00430 interface_contribution = spanned_volume(edge_intersection, circ_center); 00431 interface_area_accessor(*eocit) += interface_contribution; 00432 //if ( other_cell != NULL) 00433 if (!detail::is_handle_invalid( other_cells, other_cell )) 00434 voronoi_unique_quantity_update(interface_area_cell_contribution_accessor(*eocit), std::make_pair( other_cell, interface_contribution) ); 00435 00436 00437 // 00438 // Box volume contribution: 00439 // 00440 double edge_contribution = 0; 00441 00442 // contribution from cell itself: 00443 VertexOnEdgeRange vertices_on_edge = viennagrid::elements<VertexType>(*eocit); 00444 for (VertexOnEdgeIterator voeit = vertices_on_edge.begin(); 00445 voeit != vertices_on_edge.end(); 00446 ++voeit) 00447 { 00448 double contribution = spanned_volume(edge_intersection, edge_midpoint, viennagrid::point(*voeit)); 00449 edge_contribution += contribution; 00450 00451 vertex_box_volume_accessor(*voeit) += contribution; 00452 voronoi_unique_quantity_update(vertex_box_volume_cell_contribution_accessor(*voeit), std::make_pair( cit.handle(), contribution) ); 00453 00454 if ( &(*voeit) != opposite_vertex_ptr ) // non-splitted contribution 00455 { 00456 // if (other_cell != NULL) 00457 if (!detail::is_handle_invalid( other_cells, other_cell )) 00458 { 00459 double contribution_other = spanned_volume(circ_center, edge_intersection, viennagrid::point(*voeit)); 00460 vertex_box_volume_accessor(*voeit) += contribution_other; 00461 voronoi_unique_quantity_update(vertex_box_volume_cell_contribution_accessor(*voeit), 00462 std::make_pair(other_cell, contribution_other) ); 00463 edge_box_volume_accessor(*eocit) += contribution_other; 00464 voronoi_unique_quantity_update(edge_box_volume_cell_contribution_accessor(*eocit), 00465 std::make_pair(other_cell, contribution_other) ); 00466 } 00467 } 00468 else //splitted contribution around center of the edge. Contributes to opposite vertex 00469 { 00470 double contribution_cell = spanned_volume(opposite_vertex_edge_intersection, edge_intersection, viennagrid::point(*voeit)); 00471 vertex_box_volume_accessor(*voeit) += contribution_cell; 00472 voronoi_unique_quantity_update(vertex_box_volume_cell_contribution_accessor(*voeit), 00473 std::make_pair( cit.handle(), contribution_cell) ); 00474 edge_box_volume_accessor(*eocit) += contribution_cell; 00475 voronoi_unique_quantity_update(edge_box_volume_cell_contribution_accessor(*eocit), 00476 std::make_pair( cit.handle(), contribution_cell) ); 00477 00478 // if (other_cell != NULL) 00479 if (!detail::is_handle_invalid( other_cells, other_cell )) 00480 { 00481 double contribution_other = spanned_volume(circ_center, edge_intersection, opposite_vertex_edge_intersection); 00482 vertex_box_volume_accessor(*voeit) += contribution_other; 00483 voronoi_unique_quantity_update(vertex_box_volume_cell_contribution_accessor(*voeit), 00484 std::make_pair(other_cell, contribution_other) ); 00485 edge_box_volume_accessor(*eocit) += contribution_other; 00486 voronoi_unique_quantity_update(edge_box_volume_cell_contribution_accessor(*eocit), 00487 std::make_pair(other_cell, contribution_other) ); 00488 } 00489 } 00490 00491 00492 } 00493 edge_box_volume_accessor(*eocit) += edge_contribution; 00494 voronoi_unique_quantity_update(edge_box_volume_cell_contribution_accessor(*eocit), 00495 std::make_pair( cit.handle(), edge_contribution) ); 00496 00497 } 00498 // else if (other_cell != NULL)// intersected edge: Write negative contributions to other cell 00499 else if (!detail::is_handle_invalid( other_cells, other_cell )) 00500 { 00501 // interface contribution: 00502 double interface_contribution = spanned_volume(circ_center, edge_midpoint); 00503 interface_area_accessor(*eocit) -= interface_contribution; 00504 voronoi_unique_quantity_update(interface_area_cell_contribution_accessor(*eocit), 00505 std::make_pair(other_cell, -1.0 * interface_contribution) ); 00506 00507 00508 //box volume contribution: 00509 double edge_contribution = 0; 00510 VertexOnEdgeRange vertices_on_edge = viennagrid::elements<VertexType>(*eocit); 00511 for (VertexOnEdgeIterator voeit = vertices_on_edge.begin(); 00512 voeit != vertices_on_edge.end(); 00513 ++voeit) 00514 { 00515 double contribution = spanned_volume(circ_center, edge_midpoint, viennagrid::point(*voeit)); 00516 edge_contribution += contribution; 00517 vertex_box_volume_accessor(*voeit) -= contribution; 00518 voronoi_unique_quantity_update(vertex_box_volume_cell_contribution_accessor(*voeit), 00519 std::make_pair(other_cell, -1.0 * contribution) ); 00520 } 00521 edge_box_volume_accessor(*eocit) -= edge_contribution; 00522 voronoi_unique_quantity_update(edge_box_volume_cell_contribution_accessor(*eocit), 00523 std::make_pair(other_cell, -1.0 * edge_contribution) ); 00524 } 00525 // else {} //nothing to do for a boundary edge 00526 00527 } //for edges on cells 00528 00529 } 00530 else // circumcenter is inside triangle (everything is simple... ;-) ) 00531 { 00532 00533 //iterate over edges: 00534 EdgeOnCellRange edges_on_cell = viennagrid::elements<EdgeType>(*cit); 00535 for (EdgeOnCellIterator eocit = edges_on_cell.begin(); 00536 eocit != edges_on_cell.end(); 00537 ++eocit) 00538 { 00539 PointType edge_midpoint = circumcenter(*eocit); 00540 00541 // interface contribution: 00542 double interface_contribution = spanned_volume(circ_center, edge_midpoint); 00543 interface_area_accessor(*eocit) += interface_contribution; 00544 voronoi_unique_quantity_update(interface_area_cell_contribution_accessor(*eocit), 00545 std::make_pair( cit.handle(), interface_contribution) ); 00546 00547 00548 //box volume contribution: 00549 double edge_contribution = 0; 00550 VertexOnEdgeRange vertices_on_edge = viennagrid::elements<VertexType>(*eocit); 00551 for (VertexOnEdgeIterator voeit = vertices_on_edge.begin(); 00552 voeit != vertices_on_edge.end(); 00553 ++voeit) 00554 { 00555 double contribution = spanned_volume(circ_center, edge_midpoint, viennagrid::point(*voeit)); 00556 edge_contribution += contribution; 00557 vertex_box_volume_accessor(*voeit) += contribution; 00558 voronoi_unique_quantity_update(vertex_box_volume_cell_contribution_accessor(*voeit), 00559 std::make_pair( cit.handle(), contribution) ); 00560 } 00561 edge_box_volume_accessor(*eocit) += edge_contribution; 00562 voronoi_unique_quantity_update(edge_box_volume_cell_contribution_accessor(*eocit), 00563 std::make_pair( cit.handle(), edge_contribution) ); 00564 } //for edges on cells 00565 00566 } 00567 00568 } //for cells 00569 00570 } 00571 00572 00573 // 00574 // Voronoi information in three dimensions 00575 // 00576 00585 template <typename CellTag, 00586 typename MeshT, 00587 typename InterfaceAreaAccessorT, 00588 typename InterfaceAreaCellContributionAccessorT, 00589 typename VertexBoxVolumeAccessorT, 00590 typename VertexBoxVolumeCellContributionAccessorT, 00591 typename EdgeBoxVolumeAccessorT, 00592 typename EdgeBoxVolumeCellContributionAccessorT> 00593 void write_voronoi_info(MeshT const & mesh_obj, 00594 InterfaceAreaAccessorT interface_area_accessor, 00595 InterfaceAreaCellContributionAccessorT interface_area_cell_contribution_accessor, 00596 VertexBoxVolumeAccessorT vertex_box_volume_accessor, 00597 VertexBoxVolumeCellContributionAccessorT vertex_box_volume_cell_contribution_accessor, 00598 EdgeBoxVolumeAccessorT edge_box_volume_accessor, 00599 EdgeBoxVolumeCellContributionAccessorT edge_box_volume_cell_contribution_accessor, 00600 viennagrid::tetrahedron_tag) 00601 { 00602 typedef typename viennagrid::result_of::element<MeshT, CellTag>::type CellType; 00603 typedef typename viennagrid::result_of::const_handle<MeshT, CellTag>::type ConstCellHandleType; 00604 00605 typedef typename viennagrid::result_of::point<MeshT>::type PointType; 00606 typedef typename viennagrid::result_of::element<MeshT, vertex_tag>::type VertexType; 00607 typedef typename viennagrid::result_of::element<MeshT, line_tag>::type EdgeType; 00608 typedef typename viennagrid::result_of::const_handle<MeshT, line_tag>::type ConstEdgeHandleType; 00609 typedef typename viennagrid::result_of::element<MeshT, triangle_tag>::type FacetType; 00610 typedef typename viennagrid::result_of::const_handle<MeshT, triangle_tag>::type ConstFacetHandleType; 00611 00612 typedef typename viennagrid::result_of::coord<PointType>::type CoordType; 00613 00614 typedef typename viennagrid::result_of::const_element_range<MeshT, CellTag>::type CellRange; 00615 typedef typename viennagrid::result_of::iterator<CellRange>::type CellIterator; 00616 00617 typedef typename viennagrid::result_of::const_element_range<MeshT, typename CellTag::facet_tag>::type FacetRange; 00618 typedef typename viennagrid::result_of::iterator<FacetRange>::type FacetIterator; 00619 00620 typedef typename viennagrid::result_of::const_element_range<MeshT, line_tag>::type EdgeRange; 00621 typedef typename viennagrid::result_of::iterator<EdgeRange>::type EdgeIterator; 00622 00623 typedef typename viennagrid::result_of::const_element_range<CellType, typename CellTag::facet_tag>::type FacetOnCellRange; 00624 typedef typename viennagrid::result_of::iterator<FacetOnCellRange>::type FacetOnCellIterator; 00625 00626 typedef typename viennagrid::result_of::const_element_range<FacetType, line_tag>::type EdgeOnFacetRange; 00627 typedef typename viennagrid::result_of::iterator<EdgeOnFacetRange>::type EdgeOnFacetIterator; 00628 00629 typedef typename viennagrid::result_of::const_element_range<EdgeType, vertex_tag>::type VertexOnEdgeRange; 00630 typedef typename viennagrid::result_of::iterator<VertexOnEdgeRange>::type VertexOnEdgeIterator; 00631 00632 typedef std::pair<PointType, ConstCellHandleType> PointWithCellInfo; 00633 typedef std::pair<std::pair<PointType, PointType>, 00634 ConstCellHandleType> EdgePointsWithCellInfo; 00635 typedef std::vector< PointWithCellInfo > CircumcenterContainer; 00636 00637 00638 // 00639 // Step one: Write circumcenters to facets 00640 // 00641 00642 viennagrid::detail::dereference_handle_comparator<MeshT> comp(mesh_obj); 00643 00644 std::map< ConstFacetHandleType, CircumcenterContainer, viennagrid::detail::dereference_handle_comparator<MeshT> > 00645 circumcenters_on_facets( comp ); 00646 //std::map< EdgeType const *, 00647 std::map< ConstEdgeHandleType, 00648 std::vector< EdgePointsWithCellInfo >, 00649 viennagrid::detail::dereference_handle_comparator<MeshT> 00650 > interface_boundaries_on_edges(comp); 00651 00652 00653 CellRange cells = viennagrid::elements<CellType>(mesh_obj); 00654 for (CellIterator cit = cells.begin(); 00655 cit != cells.end(); 00656 ++cit) 00657 { 00658 const CellType & cell = *cit; 00659 PointType circ_center = circumcenter(cell); 00660 00661 FacetOnCellRange facets_on_cell = viennagrid::elements<FacetType>(cell); 00662 for (FacetOnCellIterator focit = facets_on_cell.begin(); 00663 focit != facets_on_cell.end(); 00664 ++focit) 00665 { 00666 circumcenters_on_facets[focit.handle()].push_back( PointWithCellInfo(circ_center, cit.handle()) ); 00667 } //for edges on cells 00668 } //for cells 00669 00670 00671 // 00672 // Step two: Write lines connecting circumcenters to edges 00673 // 00674 FacetRange facets = viennagrid::elements<FacetType>(mesh_obj); 00675 for (FacetIterator fit = facets.begin(); 00676 fit != facets.end(); 00677 ++fit) 00678 { 00679 CircumcenterContainer & circ_centers = circumcenters_on_facets[fit.handle()]; 00680 const FacetType & facet = *fit; 00681 00682 EdgeOnFacetRange edges_on_facet = viennagrid::elements<EdgeType>( facet ); 00683 for (EdgeOnFacetIterator eofit = edges_on_facet.begin(); 00684 eofit != edges_on_facet.end(); 00685 ++eofit) 00686 { 00687 const EdgeType & edge = *eofit; 00688 00689 if (circ_centers.size() == 1) 00690 { 00691 interface_boundaries_on_edges[eofit.handle()].push_back(std::make_pair( std::make_pair(circ_centers[0].first, circumcenter(facet)), 00692 circ_centers[0].second) 00693 ); 00694 interface_boundaries_on_edges[eofit.handle()].push_back(std::make_pair( std::make_pair(circumcenter(edge), circumcenter(facet)), 00695 circ_centers[0].second) 00696 ); 00697 } 00698 else if (circ_centers.size() == 2) 00699 { 00700 PointType edge_mid = circ_centers[0].first + circ_centers[1].first; 00701 edge_mid /= 2.0; 00702 00703 interface_boundaries_on_edges[eofit.handle()].push_back(std::make_pair( std::make_pair(circ_centers[0].first, edge_mid), 00704 circ_centers[0].second) 00705 ); 00706 interface_boundaries_on_edges[eofit.handle()].push_back(std::make_pair( std::make_pair(edge_mid, circ_centers[1].first), 00707 circ_centers[1].second) 00708 ); 00709 } 00710 else 00711 { 00712 std::cerr << "circ_centers.size() = " << circ_centers.size() << std::endl; 00713 std::cerr << "*fit: " << facet << std::endl; 00714 throw std::runtime_error("More than two circumcenters for a facet in three dimensions!"); 00715 } 00716 00717 } //for edges on cells 00718 } 00719 00720 00721 // 00722 // Step three: Compute Voronoi information: 00723 // 00724 EdgeRange edges = viennagrid::elements<EdgeType>(mesh_obj); 00725 for (EdgeIterator eit = edges.begin(); 00726 eit != edges.end(); 00727 ++eit) 00728 { 00729 const EdgeType & edge = *eit; 00730 00731 //get vertices of edge: 00732 VertexOnEdgeRange vertices_on_edge = viennagrid::elements<VertexType>(edge); 00733 VertexOnEdgeIterator voeit = vertices_on_edge.begin(); 00734 00735 00736 00737 VertexType const & v0 = *voeit; 00738 ++voeit; 00739 VertexType const & v1 = *voeit; 00740 00741 double edge_length = spanned_volume( viennagrid::point(mesh_obj, v0), viennagrid::point(mesh_obj, v1)); 00742 00743 std::vector< EdgePointsWithCellInfo > & interface_segments = interface_boundaries_on_edges[eit.handle()]; 00744 00745 // 00746 // determine inner point of convex interface polygon: 00747 // 00748 PointType inner_point = (interface_segments[0].first.first + interface_segments[0].first.second) / 2.0; 00749 for (std::size_t i=1; i<interface_segments.size(); ++i) 00750 { 00751 inner_point += (interface_segments[i].first.first + interface_segments[i].first.second) / 2.0; 00752 } 00753 inner_point /= static_cast<CoordType>(interface_segments.size()); 00754 00755 // 00756 // compute interface area 00757 // 00758 double interface_area = 0.0; 00759 for (std::size_t i=0; i<interface_segments.size(); ++i) 00760 { 00761 // interface area: 00762 double interface_contribution = spanned_volume(interface_segments[i].first.first, interface_segments[i].first.second, inner_point); 00763 if (interface_contribution > 0) 00764 { 00765 voronoi_unique_quantity_update(interface_area_cell_contribution_accessor( edge ), 00766 std::make_pair(interface_segments[i].second, interface_contribution) ); 00767 interface_area += interface_contribution; 00768 00769 // box volume: 00770 double volume_contribution = interface_contribution * edge_length / 6.0; 00771 voronoi_unique_quantity_update(edge_box_volume_cell_contribution_accessor( edge ), 00772 std::make_pair(interface_segments[i].second, 2.0 * volume_contribution) ); //volume contribution of both box volumes associated with the edge 00773 voronoi_unique_quantity_update(vertex_box_volume_cell_contribution_accessor(v0), 00774 std::make_pair( interface_segments[i].second, volume_contribution) ); 00775 voronoi_unique_quantity_update(vertex_box_volume_cell_contribution_accessor(v1), 00776 std::make_pair( interface_segments[i].second, volume_contribution) ); 00777 } 00778 } 00779 00780 // 00781 // Write Voronoi info: 00782 // 00783 00784 //std::cout << "Interface area: " << interface_area << std::endl; 00785 interface_area_accessor( edge ) = interface_area; 00786 double volume_contribution = interface_area * edge_length / 6.0; 00787 edge_box_volume_accessor(edge) = 2.0 * volume_contribution; //volume contribution of both box volumes associated with the edge 00788 vertex_box_volume_accessor(v0) += volume_contribution; 00789 vertex_box_volume_accessor(v1) += volume_contribution; 00790 00791 } //for edges 00792 00793 } //write_voronoi_info(tetrahedron_tag) 00794 00795 00796 00798 template <typename CellTag, 00799 typename MeshT, 00800 typename InterfaceAreaAccessorT, 00801 typename InterfaceAreaCellContributionAccessorT, 00802 typename VertexBoxVolumeAccessorT, 00803 typename VertexBoxVolumeCellContributionAccessorT, 00804 typename EdgeBoxVolumeAccessorT, 00805 typename EdgeBoxVolumeCellContributionAccessorT> 00806 void write_voronoi_info(MeshT const & mesh_obj, 00807 InterfaceAreaAccessorT interface_area_accessor, 00808 InterfaceAreaCellContributionAccessorT interface_area_cell_contribution_accessor, 00809 VertexBoxVolumeAccessorT vertex_box_volume_accessor, 00810 VertexBoxVolumeCellContributionAccessorT vertex_box_volume_cell_contribution_accessor, 00811 EdgeBoxVolumeAccessorT edge_box_volume_accessor, 00812 EdgeBoxVolumeCellContributionAccessorT edge_box_volume_cell_contribution_accessor, 00813 viennagrid::hexahedron_tag) 00814 { 00815 //std::cout << "Warning: Voronoi info for hexahedron is only correct when having regular cuboids only." << std::endl; 00816 00817 typedef typename viennagrid::result_of::element<MeshT, CellTag>::type CellType; 00818 00819 typedef typename viennagrid::result_of::point<MeshT>::type PointType; 00820 typedef typename viennagrid::result_of::element<MeshT, vertex_tag>::type VertexType; 00821 typedef typename viennagrid::result_of::element<MeshT, line_tag>::type EdgeType; 00822 typedef typename viennagrid::result_of::element<MeshT, quadrilateral_tag>::type FacetType; 00823 00824 typedef typename viennagrid::result_of::const_element_range<MeshT, CellTag>::type CellRange; 00825 typedef typename viennagrid::result_of::iterator<CellRange>::type CellIterator; 00826 00827 typedef typename viennagrid::result_of::const_element_range<CellType, quadrilateral_tag>::type FacetOnCellRange; 00828 typedef typename viennagrid::result_of::iterator<FacetOnCellRange>::type FacetOnCellIterator; 00829 00830 typedef typename viennagrid::result_of::const_element_range<FacetType, line_tag>::type EdgeOnFacetRange; 00831 typedef typename viennagrid::result_of::iterator<EdgeOnFacetRange>::type EdgeOnFacetIterator; 00832 00833 typedef typename viennagrid::result_of::const_element_range<EdgeType, vertex_tag>::type VertexOnEdgeRange; 00834 typedef typename viennagrid::result_of::iterator<VertexOnEdgeRange>::type VertexOnEdgeIterator; 00835 00836 // 00837 // Algorithm: Iterate over all cells, compute circumcenter and add interface area to edge, box volume to vertex. 00838 // 00839 00840 CellRange cells = viennagrid::elements<CellTag>(mesh_obj); 00841 for (CellIterator cit = cells.begin(); 00842 cit != cells.end(); 00843 ++cit) 00844 { 00845 const CellType & cell = *cit; 00846 PointType cell_center = circumcenter(cell); 00847 00848 FacetOnCellRange facets_on_cell = viennagrid::elements<viennagrid::quadrilateral_tag>(cell); 00849 for (FacetOnCellIterator focit = facets_on_cell.begin(); 00850 focit != facets_on_cell.end(); 00851 ++focit) 00852 { 00853 PointType facet_center = circumcenter(*focit); 00854 00855 //iterate over edges: 00856 EdgeOnFacetRange edges_on_facet = viennagrid::elements<EdgeType>(*focit); 00857 for (EdgeOnFacetIterator eocit = edges_on_facet.begin(); 00858 eocit != edges_on_facet.end(); 00859 ++eocit) 00860 { 00861 PointType edge_midpoint = viennagrid::circumcenter(*eocit); 00862 00863 // interface contribution: 00864 double interface_contribution = spanned_volume(cell_center, facet_center, edge_midpoint); 00865 interface_area_cell_contribution_accessor(*eocit).push_back(std::make_pair(cit.handle(), interface_contribution) ); //Note: Due to iteration over cells there is no need to use a voronoi_unique_quantity_update() here 00866 interface_area_accessor(*eocit) += interface_contribution; 00867 00868 //box volume contribution: 00869 double edge_contribution = 0; 00870 VertexOnEdgeRange vertices_on_edge = viennagrid::elements<VertexType>(*eocit); 00871 for (VertexOnEdgeIterator voeit = vertices_on_edge.begin(); 00872 voeit != vertices_on_edge.end(); 00873 ++voeit) 00874 { 00875 //double contribution = spanned_volume(cell_center, facet_center, edge_midpoint, voeit->point()); 00876 double contribution = spanned_volume(cell_center, facet_center, edge_midpoint, viennagrid::point(mesh_obj, *voeit)); 00877 vertex_box_volume_cell_contribution_accessor(*voeit).push_back(std::make_pair( cit.handle(), contribution) ); 00878 vertex_box_volume_accessor(*voeit) += contribution; 00879 edge_contribution += contribution; 00880 } 00881 edge_box_volume_cell_contribution_accessor(*eocit).push_back(std::make_pair( cit.handle(), edge_contribution) ); 00882 edge_box_volume_accessor(*eocit) += edge_contribution; 00883 } //for edges on facet 00884 00885 } //for facets on cell 00886 00887 } //for cells 00888 00889 } 00890 00891 } //namespace detail 00892 00893 // 00894 // The public interface 00895 // 00896 00908 template <typename ElementTypeOrTagT, 00909 typename MeshT, 00910 typename InterfaceAreaAccessorT, 00911 typename InterfaceAreaCellContributionAccessorT, 00912 typename VertexBoxVolumeAccessorT, 00913 typename VertexBoxVolumeCellContributionAccessorT, 00914 typename EdgeBoxVolumeAccessorT, 00915 typename EdgeBoxVolumeCellContributionAccessorT> 00916 void apply_voronoi(MeshT const & mesh_obj, 00917 InterfaceAreaAccessorT interface_area_accessor, 00918 InterfaceAreaCellContributionAccessorT interface_area_cell_contribution_accessor, 00919 VertexBoxVolumeAccessorT vertex_box_volume_accessor, 00920 VertexBoxVolumeCellContributionAccessorT vertex_box_volume_cell_contribution_accessor, 00921 EdgeBoxVolumeAccessorT edge_box_volume_accessor, 00922 EdgeBoxVolumeCellContributionAccessorT edge_box_volume_cell_contribution_accessor) 00923 { 00924 typedef typename viennagrid::result_of::element_tag<ElementTypeOrTagT>::type ElementTag; 00925 00926 detail::write_voronoi_info<ElementTag>(mesh_obj, 00927 interface_area_accessor, 00928 interface_area_cell_contribution_accessor, 00929 vertex_box_volume_accessor, 00930 vertex_box_volume_cell_contribution_accessor, 00931 edge_box_volume_accessor, 00932 edge_box_volume_cell_contribution_accessor, 00933 ElementTag()); 00934 } 00935 00936 } //namespace viennagrid 00937 #endif