CDT++
Causal Dynamical Triangulations in C++
Loading...
Searching...
No Matches
Foliated_triangulation.hpp
Go to the documentation of this file.
1/*******************************************************************************
2 Causal Dynamical Triangulations in C++ using CGAL
3
4 Copyright © 2018 Adam Getchell
5 ******************************************************************************/
6
20
21#ifndef CDT_PLUSPLUS_FOLIATEDTRIANGULATION_HPP
22#define CDT_PLUSPLUS_FOLIATEDTRIANGULATION_HPP
23
25#include "Utilities.hpp"
26
27template <int dimension>
28using Delaunay_t = typename TriangulationTraits<dimension>::Delaunay;
29
30template <int dimension>
31using Point_t = typename TriangulationTraits<dimension>::Point;
32
33template <int dimension>
34using Causal_vertices_t =
35 std::vector<std::pair<Point_t<dimension>, Int_precision>>;
36
37template <int dimension>
38using Cell_handle_t = typename TriangulationTraits<dimension>::Cell_handle;
39
40template <int dimension>
41using Face_handle_t = typename TriangulationTraits<dimension>::Face_handle;
42
43template <int dimension>
44using Facet_t = typename TriangulationTraits<dimension>::Facet;
45
46template <int dimension>
47using Edge_handle_t = typename TriangulationTraits<dimension>::Edge_handle;
48
49template <int dimension>
50using Vertex_handle_t = typename TriangulationTraits<dimension>::Vertex_handle;
51
52template <int dimension>
53using Spherical_points_generator_t =
55
60template <typename C>
61concept ContainerType = std::movable<C>;
62
64enum class Cell_type
65{
66 // 3D simplices
67 THREE_ONE = 31, // (3,1)
68 TWO_TWO = 22, // (2,2)
69 ONE_THREE = 13, // (1,3)
70 // 4D simplices
71 FOUR_ONE = 41, // (4,1)
72 THREE_TWO = 32, // (3,2)
73 TWO_THREE = 23, // (2,3)
74 ONE_FOUR = 14, // (1,4)
75 ACAUSAL = 99, // The vertex timevalues differ by > 1 or are all equal
76 UNCLASSIFIED = 0 // An error happened classifying cell
77};
78
79namespace foliated_triangulations
80{
81 static int constexpr MAX_FIX_PASSES = 50;
82
88 template <int dimension>
89 auto make_causal_vertices(std::span<Point_t<dimension> const> vertices,
90 std::span<size_t const> timevalues)
91 -> Causal_vertices_t<dimension>
92 {
93 if (vertices.size() != timevalues.size())
94 {
95 throw std::length_error("Vertices and timevalues must be the same size.");
96 }
97 Causal_vertices_t<dimension> causal_vertices;
98 causal_vertices.reserve(vertices.size());
99 std::ranges::transform(vertices, timevalues,
100 std::back_inserter(causal_vertices),
101 [](Point_t<dimension> point, size_t time) {
102 return std::make_pair(point, time);
103 });
104 return causal_vertices;
105 }
106
113 template <int dimension>
114 [[nodiscard]] auto collect_edges(Delaunay_t<dimension> const& delaunay)
115 {
116 assert(delaunay.is_valid());
117 std::vector<Edge_handle_t<dimension>> init_edges;
118 init_edges.reserve(delaunay.number_of_finite_edges());
119 for (auto eit = delaunay.finite_edges_begin();
120 eit != delaunay.finite_edges_end(); ++eit)
121 {
122 Cell_handle_t<3> const cell = eit->first;
123 Edge_handle_t<3> thisEdge{cell, cell->index(cell->vertex(eit->second)),
124 cell->index(cell->vertex(eit->third))};
125 // Each edge is valid in the triangulation
126 assert(delaunay.tds().is_valid(thisEdge.first, thisEdge.second,
127 thisEdge.third));
128 init_edges.emplace_back(thisEdge);
129 }
130 assert(init_edges.size() == delaunay.number_of_finite_edges());
131 return init_edges;
132 } // collect_edges
133
141 template <int dimension>
142 [[nodiscard]] auto find_vertex(Delaunay_t<dimension> const& delaunay,
143 Point_t<dimension> const& point)
144 -> std::optional<Vertex_handle_t<dimension>>
145 {
146 if (Vertex_handle_t<dimension> vertex{nullptr};
147 delaunay.is_vertex(point, vertex))
148 {
149 return vertex;
150 }
151 return std::nullopt;
152 } // find_vertex
153
164 template <int dimension>
165 [[nodiscard]] auto find_cell(Delaunay_t<dimension> const& delaunay,
166 Vertex_handle_t<dimension> const& vh1,
167 Vertex_handle_t<dimension> const& vh2,
168 Vertex_handle_t<dimension> const& vh3,
169 Vertex_handle_t<dimension> const& vh4)
170 -> std::optional<Cell_handle_t<dimension>>
171 {
172 if (Cell_handle_t<dimension> cell{nullptr};
173 delaunay.is_cell(vh1, vh2, vh3, vh4, cell))
174 {
175 return cell;
176 }
177 return std::nullopt;
178 } // find_cell
179
182 template <int dimension>
183 auto constexpr compare_v_info = [](Vertex_handle_t<dimension> const& lhs,
184 Vertex_handle_t<dimension> const& rhs) {
185 return lhs->info() < rhs->info();
186 };
187
191 template <int dimension, ContainerType Container>
192 [[nodiscard]] auto find_max_timevalue(Container&& t_vertices) -> Int_precision
193 {
194 auto vertices = std::forward<Container>(t_vertices);
195 assert(!vertices.empty());
196 auto max_element = std::max_element(vertices.begin(), vertices.end(),
197 compare_v_info<dimension>);
198 auto result_index = std::distance(vertices.begin(), max_element);
199 // std::distance may be negative if random-access iterators are used and
200 // first is reachable from last
201 assert(result_index >= 0);
202 auto const index = static_cast<std::size_t>(std::abs(result_index));
203 return vertices[index]->info();
204 } // find_max_timevalue
205
209 template <int dimension, ContainerType Container>
210 [[nodiscard]] auto find_min_timevalue(Container&& t_vertices) -> Int_precision
211 {
212 auto vertices = std::forward<Container>(t_vertices);
213 assert(!vertices.empty());
214 auto min_element = std::min_element(vertices.begin(), vertices.end(),
215 compare_v_info<dimension>);
216 auto result_index = std::distance(vertices.begin(), min_element);
217 assert(result_index >= 0);
218 auto const index = static_cast<std::size_t>(std::abs(result_index));
219 return vertices[index]->info();
220 } // find_min_timevalue
221
226 template <int dimension>
227 [[nodiscard]] auto classify_edge(Edge_handle_t<dimension> const& t_edge)
228 -> bool
229 {
230#ifndef NDEBUG
231 spdlog::debug("{} called.\n", __PRETTY_FUNCTION__);
232#endif
233 auto const& cell = t_edge.first;
234 auto time1 = cell->vertex(t_edge.second)->info();
235 auto time2 = cell->vertex(t_edge.third)->info();
236
237#ifndef NDEBUG
238 spdlog::trace("Edge: Vertex(1) timevalue: {} Vertex(2) timevalue: {}\n",
239 time1, time2);
240#endif
241
242 return time1 != time2;
243 } // classify_edge
244
249 template <int dimension>
250 [[nodiscard]] auto filter_edges(
251 std::vector<Edge_handle_t<dimension>> const& t_edges,
252 bool t_is_Timelike_pred) -> std::vector<Edge_handle_t<dimension>>
253 {
254 std::vector<Edge_handle_t<dimension>> filtered_edges;
255 // Short-circuit if no edges
256 if (t_edges.empty()) { return filtered_edges; }
257 std::copy_if(t_edges.begin(), t_edges.end(),
258 std::back_inserter(filtered_edges), [&](auto const& edge) {
259 return t_is_Timelike_pred == classify_edge<dimension>(edge);
260 });
261 return filtered_edges;
262 } // filter_edges
263
268 template <int dimension>
269 [[nodiscard]] auto filter_cells(
270 std::vector<Cell_handle_t<dimension>> const& t_cells,
271 Cell_type const& t_cell_type) -> std::vector<Cell_handle_t<dimension>>
272 {
273 std::vector<Cell_handle_t<dimension>> filtered_cells;
274 // Short-circuit if no cells
275 if (t_cells.empty()) { return filtered_cells; }
276 std::copy_if(t_cells.begin(), t_cells.end(),
277 std::back_inserter(filtered_cells),
278 [&t_cell_type](auto const& cell) {
279 return cell->info() == static_cast<int>(t_cell_type);
280 });
281 return filtered_cells;
282 } // filter_cells
283
288 template <int dimension>
289 [[nodiscard]] auto squared_radius(Vertex_handle_t<dimension> const& t_vertex)
290 -> double
291 {
293 return r_2(t_vertex->point(), TriangulationTraits<dimension>::ORIGIN_POINT);
294 } // squared_radius
295
308 template <int dimension>
309 [[nodiscard]] auto expected_timevalue(
310 Vertex_handle_t<dimension> const& t_vertex, double t_initial_radius,
311 double t_foliation_spacing) -> Int_precision
312 {
313 auto const radius = std::sqrt(squared_radius<dimension>(t_vertex));
314 return static_cast<Int_precision>(
315 std::lround((radius - t_initial_radius + t_foliation_spacing) /
316 t_foliation_spacing));
317 } // expected_timevalue
318
325 template <int dimension>
326 [[nodiscard]] auto is_vertex_timevalue_correct(
327 Vertex_handle_t<dimension> const& t_vertex, double const t_initial_radius,
328 double const t_foliation_spacing) -> bool
329 {
330 auto const timevalue = expected_timevalue<dimension>(
331 t_vertex, t_initial_radius, t_foliation_spacing);
332#ifndef NDEBUG
333 spdlog::trace("Vertex({}) timevalue {} has expected timevalue == {}\n",
334 utilities::point_to_str(t_vertex->point()), t_vertex->info(),
335 timevalue);
336#endif
337 return timevalue == t_vertex->info();
338 } // is_vertex_timevalue_correct
339
344 template <int dimension>
345 [[nodiscard]] auto collect_vertices(
346 Delaunay_t<dimension> const& t_triangulation)
347 {
348 std::vector<Vertex_handle_t<dimension>> vertices;
349 for (auto vit = t_triangulation.finite_vertices_begin();
350 vit != t_triangulation.finite_vertices_end(); ++vit)
351 {
352 // Each vertex is valid
353 assert(t_triangulation.tds().is_vertex(vit));
354 vertices.emplace_back(vit);
355 }
356 return vertices;
357 } // collect_vertices
358
366 template <int dimension>
367 [[nodiscard]] auto check_vertices(
368 Delaunay_t<dimension> const& t_triangulation, double t_initial_radius,
369 double t_foliation_spacing)
370 {
371 auto checked_vertices = collect_vertices<dimension>(t_triangulation);
372 return std::all_of(checked_vertices.begin(), checked_vertices.end(),
373 [&](auto const& vertex) {
374 return is_vertex_timevalue_correct<dimension>(
375 vertex, t_initial_radius, t_foliation_spacing);
376 });
377 } // check_vertices
378
383 template <int dimension>
384 [[nodiscard]] auto collect_cells(Delaunay_t<dimension> const& t_triangulation)
385 -> std::vector<Cell_handle_t<dimension>>
386 {
387 std::vector<Cell_handle_t<dimension>> cells;
388 for (auto cit = t_triangulation.finite_cells_begin();
389 cit != t_triangulation.finite_cells_end(); ++cit)
390 {
391 // Each cell is valid
392 assert(t_triangulation.tds().is_cell(cit));
393 cells.emplace_back(cit);
394 }
395 return cells;
396 } // collect_cells
397
401 template <int dimension>
402 [[nodiscard]] auto get_vertices_from_cells(
403 std::vector<Cell_handle_t<dimension>> const& t_cells)
404 {
405 std::unordered_set<Vertex_handle_t<dimension>> cell_vertices;
406 auto get_vertices = [&cell_vertices](auto const& t_cell) {
407 for (int i = 0; i < dimension + 1; ++i)
408 {
409 cell_vertices.emplace(t_cell->vertex(i));
410 }
411 };
412 std::for_each(t_cells.begin(), t_cells.end(), get_vertices);
413 std::vector<Vertex_handle_t<dimension>> result(cell_vertices.begin(),
414 cell_vertices.end());
415 return result;
416 } // get_vertices_from_cells
417
424 template <int dimension>
425 [[nodiscard]] auto find_incorrect_vertices(
426 std::vector<Cell_handle_t<dimension>> const& t_cells,
427 double t_initial_radius, double t_foliation_spacing)
428 {
429 auto checked_vertices = get_vertices_from_cells<dimension>(t_cells);
430 std::vector<Vertex_handle_t<dimension>> incorrect_vertices;
431
432 std::copy_if(checked_vertices.begin(), checked_vertices.end(),
433 std::back_inserter(incorrect_vertices),
434 [&](auto const& vertex) {
435 return !is_vertex_timevalue_correct<dimension>(
436 vertex, t_initial_radius, t_foliation_spacing);
437 });
438 return incorrect_vertices;
439 } // find_incorrect_vertices
440
448 template <int dimension>
449 [[nodiscard]] auto find_incorrect_vertices(
450 Delaunay_t<dimension> const& t_triangulation, double t_initial_radius,
451 double t_foliation_spacing)
452 {
453 auto cells_to_check = collect_cells<dimension>(t_triangulation);
454 return find_incorrect_vertices<dimension>(cells_to_check, t_initial_radius,
455 t_foliation_spacing);
456 } // find_incorrect_vertices
457
466 template <int dimension>
467 [[nodiscard]] auto fix_vertices(
468 std::vector<Cell_handle_t<dimension>> const& t_cells,
469 double t_initial_radius, double t_foliation_spacing)
470 {
471 auto incorrect_vertices = find_incorrect_vertices<dimension>(
472 t_cells, t_initial_radius, t_foliation_spacing);
473 std::for_each(incorrect_vertices.begin(), incorrect_vertices.end(),
474 [&](auto const& vertex) {
475 vertex->info() = expected_timevalue<dimension>(
476 vertex, t_initial_radius, t_foliation_spacing);
477 });
478 return !incorrect_vertices.empty();
479 } // fix_vertices
480
489 template <int dimension>
490 [[nodiscard]] auto fix_vertices(Delaunay_t<dimension> const& t_triangulation,
491 double const t_initial_radius,
492 double const t_foliation_spacing) -> bool
493 {
494 return fix_vertices<dimension>(collect_cells<dimension>(t_triangulation),
495 t_initial_radius, t_foliation_spacing);
496 } // fix_vertices
497
502 template <int dimension>
503 [[nodiscard]] auto expected_cell_type(Cell_handle_t<dimension> const& t_cell)
504 {
505#ifndef NDEBUG
506 spdlog::debug("{} called.\n", __PRETTY_FUNCTION__);
507#endif
508 std::array<int, static_cast<std::size_t>(dimension) + 1>
509 vertex_timevalues{};
510 // There are d+1 vertices in a d-dimensional simplex
511 for (auto i = 0; i < dimension + 1; ++i)
512 {
513 // Obtain timevalue of vertex
514 vertex_timevalues.at(static_cast<std::size_t>(i)) =
515 t_cell->vertex(i)->info();
516 }
517 auto const maxtime_ref =
518 std::max_element(vertex_timevalues.begin(), vertex_timevalues.end());
519 auto const mintime_ref =
520 std::min_element(vertex_timevalues.begin(), vertex_timevalues.end());
521 auto maxtime = *maxtime_ref;
522 auto mintime = *mintime_ref;
523 // A properly foliated simplex should have a timevalue difference of 1
524 if (maxtime - mintime != 1 || maxtime == mintime)
525 {
526#ifndef NDEBUG
527 spdlog::trace("This simplex is acausal:\n");
528 spdlog::trace("Max timevalue is {} and min timevalue is {}.\n", maxtime,
529 mintime);
530 spdlog::trace("--\n");
531#endif
532 return Cell_type::ACAUSAL;
533 }
534 std::multiset<int> const timevalues{vertex_timevalues.begin(),
535 vertex_timevalues.end()};
536 auto max_vertices = timevalues.count(maxtime);
537 auto min_vertices = timevalues.count(mintime);
538
539 // 3D simplices
540 if (max_vertices == 3 && min_vertices == 1) { return Cell_type::ONE_THREE; }
541 if (max_vertices == 2 && min_vertices == 2) { return Cell_type::TWO_TWO; }
542 if (max_vertices == 1 && min_vertices == 3) { return Cell_type::THREE_ONE; }
543
544 // 4D simplices
545 if (max_vertices == 4 && min_vertices == 1) { return Cell_type::ONE_FOUR; }
546 if (max_vertices == 3 && min_vertices == 2) { return Cell_type::TWO_THREE; }
547 if (max_vertices == 2 && min_vertices == 3) { return Cell_type::THREE_TWO; }
548 if (max_vertices == 1 && min_vertices == 4) { return Cell_type::FOUR_ONE; }
549
550 // If we got here, there's some kind of error
551#ifndef NDEBUG
552 spdlog::trace("This simplex has an error:\n");
553 spdlog::trace("Max timevalue is {} and min timevalue is {}.\n", maxtime,
554 mintime);
555 spdlog::trace(
556 "There are {} vertices with the max timevalue and {} vertices with "
557 "the min timevalue.\n",
558 max_vertices, min_vertices);
559 spdlog::trace("--\n");
560#endif
561 return Cell_type::UNCLASSIFIED;
562 } // expected_cell_type
563
568 template <int dimension>
569 [[nodiscard]] auto is_cell_type_correct(
570 Cell_handle_t<dimension> const& t_cell) -> bool
571 {
572 auto cell_type = expected_cell_type<dimension>(t_cell);
573 return cell_type != Cell_type::ACAUSAL &&
574 cell_type != Cell_type::UNCLASSIFIED &&
575 cell_type == static_cast<Cell_type>(t_cell->info());
576 } // is_cell_type_correct
577
583 template <int dimension>
584 [[nodiscard]] auto check_cells(Delaunay_t<dimension> const& t_triangulation)
585 -> bool
586 {
587 auto checked_cells = collect_cells<dimension>(t_triangulation);
588 return checked_cells.empty() ||
589 std::all_of(checked_cells.begin(), checked_cells.end(),
590 [&](auto const& cell) {
591 return is_cell_type_correct<dimension>(cell);
592 });
593 } // check_cells
594
599 template <int dimension>
600 [[nodiscard]] auto find_incorrect_cells(
601 Delaunay_t<dimension> const& t_triangulation)
602 {
603 auto checked_cells = collect_cells<dimension>(t_triangulation);
604
605 std::vector<Cell_handle_t<dimension>> incorrect_cells;
606 std::copy_if(checked_cells.begin(), checked_cells.end(),
607 std::back_inserter(incorrect_cells), [&](auto const& cell) {
608 return !is_cell_type_correct<dimension>(cell);
609 });
610 return incorrect_cells;
611 } // find_incorrect_cells
612
617 template <int dimension>
618 [[nodiscard]] auto fix_cells(Delaunay_t<dimension> const& t_triangulation)
619 -> bool
620 {
621 auto incorrect_cells = find_incorrect_cells<dimension>(t_triangulation);
622 std::for_each(
623 incorrect_cells.begin(), incorrect_cells.end(), [&](auto const& cell) {
624 cell->info() =
625 static_cast<Int_precision>(expected_cell_type<dimension>(cell));
626 });
627 return !incorrect_cells.empty();
628 } // fix_cells
629
633 template <int dimension>
634 void print_cell(Cell_handle_t<dimension> cell)
635 {
636 fmt::print("Cell info => {}\n", cell->info());
637 // There are d+1 vertices in a d-dimensional simplex
638 for (int j = 0; j < dimension + 1; ++j)
639 {
640 fmt::print("Vertex({}) Point: ({}) Timevalue: {}\n", j,
641 utilities::point_to_str(cell->vertex(j)->point()),
642 cell->vertex(j)->info());
643 }
644 fmt::print("---\n");
645 } // print_cell
646
651 template <int dimension, typename Container>
652 void print_cells(Container&& t_cells)
653 {
654 for (auto cells = std::forward<Container>(t_cells);
655 auto const& cell : cells)
656 {
657 print_cell<dimension>(cell);
658 }
659 } // print_cells
660
666 template <int dimension, ContainerType Container>
667 void debug_print_cells(Container&& t_cells)
668 {
669 for (auto cells = std::forward<Container>(t_cells);
670 auto const& cell : cells)
671 {
672 spdlog::debug("Cell info => {}\n", cell->info());
673 for (int j = 0; j < dimension + 1; ++j)
674 {
675 spdlog::debug("Vertex({}) Point: ({}) Timevalue: {}\n", j,
676 utilities::point_to_str(cell->vertex(j)->point()),
677 cell->vertex(j)->info());
678 }
679 spdlog::debug("---\n");
680 }
681 } // debug_print_cells
682
686 template <int dimension>
687 void print_neighboring_cells(Cell_handle_t<dimension> cell)
688 {
689 for (int j = 0; j < dimension + 1; ++j)
690 {
691 fmt::print("Neighboring cell {}:", j);
692 print_cell<dimension>(cell->neighbor(j));
693 }
694 } // print_neighboring_cells
695
704 template <int dimension>
705 void print_edge(Edge_handle_t<dimension> const& t_edge)
706 {
707 fmt::print(
708 "Edge: Vertex({}) Point({}) Timevalue: {} -> Vertex({}) Point({}) "
709 "Timevalue: {}\n",
710 t_edge.second,
711 utilities::point_to_str(t_edge.first->vertex(t_edge.second)->point()),
712 t_edge.first->vertex(t_edge.second)->info(), t_edge.third,
713 utilities::point_to_str(t_edge.first->vertex(t_edge.third)->point()),
714 t_edge.first->vertex(t_edge.third)->info());
715 } // print_edge
716
723 template <int dimension, ContainerType Container>
724 [[nodiscard]] auto volume_per_timeslice(Container&& t_facets)
725 -> std::multimap<Int_precision, Facet_t<3>>
726 {
727#ifndef NDEBUG
728 spdlog::debug("{} called.\n", __PRETTY_FUNCTION__);
729#endif
730 std::multimap<Int_precision, Facet_t<3>> space_faces;
731 for (auto facets = std::forward<Container>(t_facets);
732 auto const& face : facets)
733 {
734 Cell_handle_t<dimension> const cell = face.first;
735 auto index_of_facet = face.second;
736#ifndef NDEBUG
737 spdlog::trace("Facet index is {}\n", index_of_facet);
738#endif
739 std::set<Int_precision> facet_timevalues;
740 // There are d+1 vertices in a d-dimensional simplex
741 for (int i = 0; i < dimension + 1; ++i)
742 {
743 if (i != index_of_facet)
744 {
745#ifndef NDEBUG
746 spdlog::trace("Vertex[{}] has timevalue {}\n", i,
747 cell->vertex(i)->info());
748#endif
749 facet_timevalues.insert(cell->vertex(i)->info());
750 }
751 }
752 // If we have a 1-element set then all timevalues on that facet are
753 // equal
754 if (facet_timevalues.size() == 1)
755 {
756#ifndef NDEBUG
757 spdlog::trace("Facet is spacelike on timevalue {}.\n",
758 *facet_timevalues.begin());
759#endif
760 space_faces.insert({*facet_timevalues.begin(), face});
761 }
762 else
763 {
764#ifndef NDEBUG
765 spdlog::trace("Facet is timelike.\n");
766#endif
767 }
768 }
769 return space_faces;
770 } // volume_per_timeslice
771
786 template <int dimension>
787 [[nodiscard]] auto check_timevalues(
788 Delaunay_t<dimension> const& t_triangulation)
789 -> std::optional<std::vector<Cell_handle_t<dimension>>>
790 {
791 auto const& cells = collect_cells<dimension>(t_triangulation);
792 std::vector<Cell_handle_t<dimension>> invalid_cells;
793 std::copy_if(
794 cells.begin(), cells.end(), std::back_inserter(invalid_cells),
795 [](auto const& cell) {
796 return expected_cell_type<dimension>(cell) == Cell_type::ACAUSAL ||
797 expected_cell_type<dimension>(cell) == Cell_type::UNCLASSIFIED;
798 });
799 auto result = invalid_cells.empty() ? std::nullopt
800 : std::make_optional(invalid_cells);
801 return result;
802 } // check_timevalues
803
808 template <int dimension>
809 [[nodiscard]] auto find_bad_vertex(Cell_handle_t<dimension> const& cell)
810 -> Vertex_handle_t<dimension>
811 {
812#ifndef NDEBUG
813 spdlog::debug("{} called.\n", __PRETTY_FUNCTION__);
814 spdlog::debug("===Invalid Cell===\n");
815 std::vector<Cell_handle_t<dimension>> bad_cell{cell};
816 debug_print_cells<dimension>(std::span{bad_cell});
817#endif
818 std::multimap<Int_precision, Vertex_handle_t<dimension>> vertices;
819 for (int i = 0; i < dimension + 1; ++i)
820 {
821 vertices.emplace(
822 std::make_pair(cell->vertex(i)->info(), cell->vertex(i)));
823 }
824 // Now it's sorted in the multimap
825 auto const minvalue = vertices.cbegin()->first;
826 auto const maxvalue = vertices.crbegin()->first;
827 auto const minvalue_count = vertices.count(minvalue);
828 auto const maxvalue_count = vertices.count(maxvalue);
829 // Return the vertex with the highest value if there are equal or more
830 // vertices with lower values. Note that we preferentially return higher
831 // timeslice vertices because there are typically more cells at higher
832 // timeslices (see expected_points_per_timeslice())
833 return minvalue_count >= maxvalue_count ? vertices.rbegin()->second
834 : vertices.begin()->second;
835 } // find_bad_vertex
836
842 template <int dimension>
843 [[nodiscard]] auto fix_timevalues(Delaunay_t<dimension>& t_triangulation)
844 -> bool
845 {
846 // Obtain a container of cells that are incorrectly foliated
847 if (auto invalid_cells = check_timevalues<dimension>(t_triangulation);
848 invalid_cells)
849 {
850 std::set<Vertex_handle_t<dimension>> vertices_to_remove;
851 // Transform the invalid cells into a set of vertices to remove
852 // Reduction to unique vertices happens via the set container
853 std::transform(
854 invalid_cells->begin(), invalid_cells->end(),
855 std::inserter(vertices_to_remove, vertices_to_remove.begin()),
856 find_bad_vertex<dimension>);
857 // Remove the vertices
858#ifndef NDEBUG
859 spdlog::warn("There are {} invalid vertices.\n",
860 vertices_to_remove.size());
861#endif
862 t_triangulation.remove(vertices_to_remove.begin(),
863 vertices_to_remove.end());
864 assert(t_triangulation.tds().is_valid());
865 assert(t_triangulation.is_valid());
866 return true;
867 }
868 return false;
869 } // fix_timevalues
870
881 template <int dimension>
882 [[nodiscard]] auto make_foliated_ball(
883 Int_precision const t_simplices, Int_precision const t_timeslices,
884 double const initial_radius = INITIAL_RADIUS,
885 double const foliation_spacing = FOLIATION_SPACING)
886 {
887 Causal_vertices_t<dimension> causal_vertices;
888 causal_vertices.reserve(static_cast<std::size_t>(t_simplices));
889 auto const points_per_timeslice = utilities::expected_points_per_timeslice(
890 dimension, t_simplices, t_timeslices);
891 assert(points_per_timeslice >= 2);
892
893 for (gsl::index i = 0; i < t_timeslices; ++i)
894 {
895 auto const radius =
896 initial_radius + static_cast<double>(i) * foliation_spacing;
897 Spherical_points_generator_t<dimension> gen{radius};
898 // Generate random points at the radius
899 for (gsl::index j = 0;
900 j < static_cast<Int_precision>(points_per_timeslice * radius); ++j)
901 {
902 causal_vertices.emplace_back(*gen++, i + 1);
903 } // j
904 } // i
905 return causal_vertices;
906 } // make_foliated_ball
907
915 template <int dimension>
916 [[nodiscard]] auto make_triangulation(
917 Int_precision const t_simplices, Int_precision t_timeslices,
918 double const initial_radius = INITIAL_RADIUS,
919 double const foliation_spacing = FOLIATION_SPACING)
920 -> Delaunay_t<dimension>
921 {
922#ifndef NDEBUG
923 spdlog::debug("{} called.\n", __PRETTY_FUNCTION__);
924#endif
925 fmt::print("\nGenerating universe ...\n");
926#ifdef CGAL_LINKED_WITH_TBB
927 // Construct the locking data-structure
928 // using the bounding-box of the points
929 auto bounding_box_size = static_cast<double>(t_timeslices + 1);
930 typename Delaunay_t<dimension>::Lock_data_structure locking_ds{
931 CGAL::Bbox_3{-bounding_box_size, -bounding_box_size, -bounding_box_size,
932 bounding_box_size, bounding_box_size, bounding_box_size},
933 50
934 };
935 Delaunay_t<dimension> triangulation =
936 Delaunay_t<dimension>{TriangulationTraits<3>::Kernel{}, &locking_ds};
937#else
938 Delaunay_t<dimension> triangulation = Delaunay_t<dimension>{};
939#endif
940
941 // Make initial triangulation
942 auto causal_vertices = make_foliated_ball<dimension>(
943 t_simplices, t_timeslices, initial_radius, foliation_spacing);
944 triangulation.insert(causal_vertices.begin(), causal_vertices.end());
945
946 // Fix vertices
947 for (auto passes = 1; passes < MAX_FIX_PASSES + 1; ++passes)
948 {
949 if (!fix_vertices<dimension>(triangulation, initial_radius,
950 foliation_spacing))
951 {
952 break;
953 }
954#ifndef NDEBUG
955 spdlog::warn("Deleting incorrect vertices pass #{}\n", passes);
956#endif
957 }
958
959 // Fix timeslices
960 for (auto passes = 1; passes < MAX_FIX_PASSES + 1; ++passes)
961 {
962 if (!fix_timevalues<dimension>(triangulation)) { break; }
963#ifndef NDEBUG
964 spdlog::warn("Fixing timeslices pass #{}\n", passes);
965#endif
966 }
967
968 // Fix cells
969 for (auto i = 1; i < MAX_FIX_PASSES + 1; ++i)
970 {
971 if (!fix_cells<dimension>(triangulation)) { break; }
972#ifndef NDEBUG
973 spdlog::warn("Fixing incorrect cells pass #{}\n", i);
974#endif
975 }
976
977 utilities::print_delaunay(triangulation);
978 assert(!check_timevalues<dimension>(triangulation));
979 return triangulation;
980 } // make_triangulation
981
984 template <int dimension>
986
994 template <>
995 class [[nodiscard("This contains data!")]] FoliatedTriangulation<3> // NOLINT
996 {
997 using Delaunay = Delaunay_t<3>;
998 using Cell_handle = Cell_handle_t<3>;
999 using Cell_container = std::vector<Cell_handle>;
1000 using Face_container = std::vector<Face_handle_t<3>>;
1001 using Edge_container = std::vector<Edge_handle_t<3>>;
1002 using Vertex_handle = Vertex_handle_t<3>;
1003 using Vertex_container = std::vector<Vertex_handle>;
1004 using Volume_by_timeslice = std::multimap<Int_precision, Facet_t<3>>;
1005
1008 Delaunay m_triangulation{Delaunay{}};
1009 double m_initial_radius{INITIAL_RADIUS};
1010 double m_foliation_spacing{FOLIATION_SPACING};
1011 Vertex_container m_vertices;
1012 Cell_container m_cells;
1013 Cell_container m_three_one;
1014 Cell_container m_two_two;
1015 Cell_container m_one_three;
1016 Face_container m_faces;
1017 Volume_by_timeslice m_spacelike_facets;
1018 Edge_container m_edges;
1019 Edge_container m_timelike_edges;
1020 Edge_container m_spacelike_edges;
1021 Int_precision m_max_timevalue{0};
1022 Int_precision m_min_timevalue{0};
1023
1024 public:
1027
1030
1034 static_cast<Delaunay const&>(other.get_delaunay()),
1035 other.m_initial_radius, other.m_foliation_spacing)
1036 {}
1037
1041 {
1042 swap(other, *this);
1043 return *this;
1044 }
1045
1049 {
1050 swap(other, *this);
1051 }
1052
1059 friend void swap(FoliatedTriangulation& swap_from,
1060 FoliatedTriangulation& swap_into) noexcept
1061 {
1062#ifndef NDEBUG
1063 spdlog::debug("{} called.\n", __PRETTY_FUNCTION__);
1064#endif
1065 // Uses the triangulation swap method in CGAL
1066 // This assumes that the first triangulation is not used afterward!
1067 // See
1068 // https://doc.cgal.org/latest/Triangulation_3/classCGAL_1_1Triangulation__3.html#a767066a964b4d7b14376e5f5d1a04b34
1069 swap_into.m_triangulation.swap(swap_from.m_triangulation);
1070 using std::swap;
1071 swap(swap_from.m_initial_radius, swap_into.m_initial_radius);
1072 swap(swap_from.m_foliation_spacing, swap_into.m_foliation_spacing);
1073 swap(swap_from.m_vertices, swap_into.m_vertices);
1074 swap(swap_from.m_cells, swap_into.m_cells);
1075 swap(swap_from.m_three_one, swap_into.m_three_one);
1076 swap(swap_from.m_two_two, swap_into.m_two_two);
1077 swap(swap_from.m_one_three, swap_into.m_one_three);
1078 swap(swap_from.m_faces, swap_into.m_faces);
1079 swap(swap_from.m_spacelike_facets, swap_into.m_spacelike_facets);
1080 swap(swap_from.m_edges, swap_into.m_edges);
1081 swap(swap_from.m_timelike_edges, swap_into.m_timelike_edges);
1082 swap(swap_from.m_spacelike_edges, swap_into.m_spacelike_edges);
1083 swap(swap_from.m_max_timevalue, swap_into.m_max_timevalue);
1084 swap(swap_from.m_min_timevalue, swap_into.m_min_timevalue);
1085
1086 } // swap
1087
1095 Delaunay triangulation, double const initial_radius = INITIAL_RADIUS,
1096 double const foliation_spacing = FOLIATION_SPACING)
1097 : m_triangulation{std::move(triangulation)}
1098 , m_initial_radius{initial_radius}
1099 , m_foliation_spacing{foliation_spacing}
1100 , m_vertices{classify_vertices(collect_vertices<3>(m_triangulation))}
1101 , m_cells{classify_cells(collect_cells<3>(m_triangulation))}
1102 , m_three_one{filter_cells<3>(m_cells, Cell_type::THREE_ONE)}
1103 , m_two_two{filter_cells<3>(m_cells, Cell_type::TWO_TWO)}
1104 , m_one_three{filter_cells<3>(m_cells, Cell_type::ONE_THREE)}
1105 , m_faces{collect_faces()}
1106 , m_spacelike_facets{volume_per_timeslice<3>(std::span{m_faces})}
1107 , m_edges{collect_edges()}
1108 , m_timelike_edges{filter_edges<3>(m_edges, true)}
1109 , m_spacelike_edges{filter_edges<3>(m_edges, false)}
1110 , m_max_timevalue{find_max_timevalue<3>(std::span{m_vertices})}
1111 , m_min_timevalue{find_min_timevalue<3>(std::span{m_vertices})}
1112 {}
1113
1120 Int_precision const t_timeslices,
1121 double const t_initial_radius = INITIAL_RADIUS,
1122 double const t_foliation_spacing = FOLIATION_SPACING)
1124 make_triangulation<3>(t_simplices, t_timeslices, t_initial_radius,
1125 t_foliation_spacing),
1126 t_initial_radius, t_foliation_spacing}
1127 {}
1128
1135 Causal_vertices_t<3> const& causal_vertices,
1136 double const t_initial_radius = INITIAL_RADIUS,
1137 double const t_foliation_spacing = FOLIATION_SPACING)
1139 Delaunay{causal_vertices.begin(), causal_vertices.end()},
1140 t_initial_radius, t_foliation_spacing
1141 }
1142 {}
1143
1150 [[nodiscard]] auto is_foliated() const -> bool
1151 {
1152 return !static_cast<bool>(check_timevalues<3>(this->get_delaunay()));
1153 } // is_foliated
1154
1156 [[nodiscard]] auto is_delaunay() const -> bool
1157 {
1158 return get_delaunay().is_valid();
1159 } // is_delaunay
1160
1162 [[nodiscard]] auto is_tds_valid() const -> bool
1163 {
1164 return get_delaunay().tds().is_valid();
1165 } // is_tds_valid
1166
1168 [[nodiscard]] auto is_correct() const -> bool
1169 {
1170 return is_foliated() && is_tds_valid() && check_all_cells();
1171 } // is_correct
1172
1175 [[nodiscard]] auto is_initialized() const -> bool
1176 {
1177 return is_correct() && is_delaunay();
1178 } // is_initialized
1179
1181 [[nodiscard]] auto is_fixed() -> bool
1182 {
1183 auto const fixed_vertices = foliated_triangulations::fix_vertices<3>(
1184 m_triangulation, m_initial_radius, m_foliation_spacing);
1185 auto const fixed_cells =
1186 foliated_triangulations::fix_cells<3>(m_triangulation);
1187 auto const fixed_timeslices =
1188 foliated_triangulations::fix_timevalues<3>(m_triangulation);
1189 return fixed_vertices || fixed_cells || fixed_timeslices;
1190 } // is_fixed
1191
1193 [[nodiscard]] auto delaunay() -> Delaunay& { return m_triangulation; }
1194
1196 [[nodiscard]] auto get_delaunay() const -> Delaunay const&
1197 {
1198 return std::cref(m_triangulation);
1199 } // get_delaunay
1200
1202 [[nodiscard]] auto number_of_finite_cells() const
1203 {
1204 return m_triangulation.number_of_finite_cells();
1205 } // number_of_finite_cells
1206
1208 [[nodiscard]] auto number_of_finite_facets() const
1209 {
1210 return m_triangulation.number_of_finite_facets();
1211 } // number_of_finite_facets
1212
1214 [[nodiscard]] auto number_of_finite_edges() const
1215 {
1216 return m_triangulation.number_of_finite_edges();
1217 } // number_of_finite_edges
1218
1220 [[nodiscard]] auto number_of_vertices() const
1221 {
1222 return m_triangulation.number_of_vertices();
1223 } // number_of_vertices
1224
1227 template <typename VertexHandle>
1228 [[nodiscard]] auto is_infinite(VertexHandle&& t_vertex) const
1229 {
1230 return m_triangulation.is_infinite(std::forward<VertexHandle>(t_vertex));
1231 } // is_infinite
1232
1241 template <typename... Ts>
1242 [[nodiscard]] auto flip(Ts&&... args)
1243 {
1244 return m_triangulation.flip(std::forward<Ts>(args)...);
1245 } // flip
1246
1248 [[maybe_unused]] [[nodiscard]] auto infinite_vertex() const
1249 {
1250 return m_triangulation.infinite_vertex();
1251 } // infinite_vertex
1252
1254 [[nodiscard]] auto dimension() const { return m_triangulation.dimension(); }
1255
1257 [[nodiscard]] auto N2_SL() const
1258 -> std::multimap<Int_precision, TriangulationTraits<3>::Facet> const&
1259 {
1260 return m_spacelike_facets;
1261 } // N2_SL
1262
1264 [[nodiscard]] auto N1_TL() const
1265 {
1266 return static_cast<Int_precision>(m_timelike_edges.size());
1267 } // N1_TL
1268
1270 [[nodiscard]] auto N1_SL() const
1271 {
1272 return static_cast<Int_precision>(m_spacelike_edges.size());
1273 } // N1_SL
1274
1276 [[nodiscard]] auto get_timelike_edges() const noexcept
1277 -> Edge_container const&
1278 {
1279 return m_timelike_edges;
1280 } // get_timelike_edges
1281
1283 [[nodiscard]] auto get_spacelike_edges() const -> Edge_container const&
1284 {
1285 return m_spacelike_edges;
1286 } // get_spacelike_edges
1287
1289 [[nodiscard]] auto get_vertices() const noexcept -> Vertex_container const&
1290 {
1291 return m_vertices;
1292 } // get_vertices
1293
1295 [[nodiscard]] auto get_vertices_span() const noexcept
1296 -> std::span<Vertex_handle const>
1297 {
1298 return std::span{m_vertices};
1299 } // get_vertices_span
1300
1302 [[nodiscard]] auto max_time() const { return m_max_timevalue; }
1303
1305 [[nodiscard]] auto min_time() const { return m_min_timevalue; }
1306
1308 [[nodiscard]] auto initial_radius() const { return m_initial_radius; }
1309
1311 [[nodiscard]] auto foliation_spacing() const { return m_foliation_spacing; }
1312
1317 template <typename VertexHandle>
1318 [[nodiscard]] auto degree(VertexHandle&& t_vertex) const
1319 {
1320 return m_triangulation.degree(std::forward<VertexHandle>(t_vertex));
1321 } // degree
1322
1331 template <typename VertexHandle>
1332 [[nodiscard]] auto incident_cells(VertexHandle&& t_vh) const noexcept
1333 -> decltype(auto)
1334 {
1335 Cell_container inc_cells;
1336 get_delaunay().tds().incident_cells(std::forward<VertexHandle>(t_vh),
1337 std::back_inserter(inc_cells));
1338 return inc_cells;
1339 } // incident_cells
1340
1348 template <typename... Ts>
1349 [[nodiscard]] auto incident_cells(Ts&&... args) const noexcept
1350 -> decltype(auto)
1351 {
1352 return get_delaunay().tds().incident_cells(std::forward<Ts>(args)...);
1353 } // incident_cells
1354
1360 Vertex_handle_t<3> const t_vertex) const -> bool
1361 {
1362 auto const actual_radius_squared = squared_radius<3>(t_vertex);
1363 auto const radius = expected_radius(t_vertex);
1364 auto const expected_radius_squared = std::pow(radius, 2);
1365 return actual_radius_squared >
1366 expected_radius_squared * (1 - TOLERANCE) &&
1367 actual_radius_squared < expected_radius_squared * (1 + TOLERANCE);
1368 } // does_vertex_radius_match_timevalue
1369
1379 [[nodiscard]] auto expected_radius(Vertex_handle_t<3> const& t_vertex) const
1380 -> double
1381 {
1382 auto const timevalue = t_vertex->info();
1383 return m_initial_radius + m_foliation_spacing * (timevalue - 1);
1384 } // expected_radial_distance
1385
1389 [[nodiscard]] auto expected_timevalue(
1390 Vertex_handle_t<3> const& t_vertex) const -> int
1391 {
1392 return foliated_triangulations::expected_timevalue<3>(
1393 t_vertex, m_initial_radius, m_foliation_spacing);
1394 } // expected_timevalue
1395
1397 [[nodiscard]] auto check_all_vertices() const -> bool
1398 {
1399 return foliated_triangulations::check_vertices<3>(
1400 m_triangulation, m_initial_radius, m_foliation_spacing);
1401 } // check_all_vertices
1402
1404 [[nodiscard]] auto find_incorrect_vertices() const
1405 {
1406 return foliated_triangulations::find_incorrect_vertices<3>(
1407 m_triangulation, m_initial_radius, m_foliation_spacing);
1408 } // find_incorrect_vertices
1409
1411 [[nodiscard]] auto fix_vertices() const -> bool
1412 {
1413 return foliated_triangulations::fix_vertices<3>(
1414 m_triangulation, m_initial_radius, m_foliation_spacing);
1415 } // fix_vertices
1416
1418 void print_vertices() const
1419 {
1420 for (auto const& vertex : m_vertices)
1421 {
1422 fmt::print("Vertex Point: ({}) Timevalue: {} Expected Timevalue: {}\n",
1423 utilities::point_to_str(vertex->point()), vertex->info(),
1424 expected_timevalue(vertex));
1425 }
1426 } // print_vertices
1427
1430 void print_edges() const
1431 {
1432 for (auto const& edge : m_edges)
1433 {
1434 if (classify_edge<3>(edge)) { fmt::print("==> timelike\n"); }
1435 else { fmt::print("==> spacelike\n"); }
1436 }
1437 } // print_edges
1438
1441 {
1442 for (auto j = min_time(); j <= max_time(); ++j)
1443 {
1444 fmt::print("Timeslice {} has {} spacelike faces.\n", j,
1445 m_spacelike_facets.count(j));
1446 }
1447 } // print_volume_per_timeslice
1448
1450 [[nodiscard]] auto get_cells() const -> Cell_container const&
1451 {
1452 assert(m_cells.size() == number_of_finite_cells());
1453 return m_cells;
1454 } // get_cells
1455
1457 [[nodiscard]] auto get_three_one() const noexcept
1458 -> std::span<Cell_handle const>
1459 {
1460 return std::span{m_three_one};
1461 } // get_three_one
1462
1464 [[nodiscard]] auto get_two_two() const noexcept -> Cell_container const&
1465 {
1466 return m_two_two;
1467 } // get_two_two
1468
1470 [[nodiscard]] auto get_one_three() const noexcept -> Cell_container const&
1471 {
1472 return m_one_three;
1473 } // get_one_three
1474
1480 [[nodiscard]] auto check_all_cells() const -> bool
1481 {
1482 return foliated_triangulations::check_cells<3>(get_delaunay());
1483 } // check_all_cells
1484
1486 auto fix_cells() const -> bool
1487 {
1488 return foliated_triangulations::fix_cells<3>(get_delaunay());
1489 } // fix_cells
1490
1493 void print_cells() const
1494 {
1495 foliated_triangulations::print_cells<3>(m_cells);
1496 }
1497
1499 void print() const
1500 {
1501 fmt::print(
1502 "Triangulation has {} vertices and {} edges and {} faces and {} "
1503 "simplices.\n",
1504 this->number_of_vertices(), this->number_of_finite_edges(),
1505 this->number_of_finite_facets(), this->number_of_finite_cells());
1506 }
1507
1508 private:
1509 [[nodiscard]] auto classify_vertices(Vertex_container const& vertices) const
1510 -> Vertex_container
1511 {
1512 assert(vertices.size() == number_of_vertices());
1513 for (auto const& vertex : vertices)
1514 {
1515 vertex->info() = expected_timevalue(vertex);
1516 }
1517 return vertices;
1518 } // classify_vertices
1519
1523 [[nodiscard]] auto classify_cells(Cell_container const& cells) const
1524 -> Cell_container
1525 {
1526 assert(cells.size() == number_of_finite_cells());
1527 for (auto const& cell : cells)
1528 {
1529 cell->info() = static_cast<int>(expected_cell_type<3>(cell));
1530 }
1531 return cells;
1532 } // classify_cells
1533
1535 [[nodiscard]] auto collect_faces() const -> Face_container
1536 {
1537 // Somewhere in bistellar_flip_really a vertex is rendered invalid
1538 assert(is_tds_valid());
1539 Face_container init_faces;
1540 init_faces.reserve(get_delaunay().number_of_finite_facets());
1541 for (auto fit = get_delaunay().finite_facets_begin();
1542 fit != get_delaunay().finite_facets_end(); ++fit)
1543 {
1544 Cell_handle_t<3> const cell = fit->first;
1545 // Each face is valid in the triangulation
1546 assert(get_delaunay().tds().is_facet(cell, fit->second));
1547 Face_handle_t<3> const thisFacet{std::make_pair(cell, fit->second)};
1548 init_faces.emplace_back(thisFacet);
1549 }
1550 assert(init_faces.size() == get_delaunay().number_of_finite_facets());
1551 return init_faces;
1552 } // collect_faces
1553
1555 [[nodiscard]] auto collect_edges() const -> Edge_container
1556 {
1557 assert(is_tds_valid());
1558 Edge_container init_edges;
1559 init_edges.reserve(number_of_finite_edges());
1560 for (auto eit = get_delaunay().finite_edges_begin();
1561 eit != get_delaunay().finite_edges_end(); ++eit)
1562 {
1563 Cell_handle_t<3> const cell = eit->first;
1564 Edge_handle_t<3> const thisEdge{cell,
1565 cell->index(cell->vertex(eit->second)),
1566 cell->index(cell->vertex(eit->third))};
1567 // Each edge is valid in the triangulation
1568 assert(get_delaunay().tds().is_valid(thisEdge.first, thisEdge.second,
1569 thisEdge.third));
1570 init_edges.emplace_back(thisEdge);
1571 }
1572 assert(init_edges.size() == number_of_finite_edges());
1573 return init_edges;
1574 } // collect_edges
1575 };
1576
1577 using FoliatedTriangulation_3 = FoliatedTriangulation<3>;
1578
1580 template <>
1581 class [[nodiscard("This contains data!")]] FoliatedTriangulation<4>
1582 {};
1583
1585
1586} // namespace foliated_triangulations
1587
1588#endif // CDT_PLUSPLUS_FOLIATEDTRIANGULATION_HPP
void print_edge(Edge_handle_t< dimension > const &t_edge)
Print edge.
auto get_vertices_from_cells(std::vector< Cell_handle_t< dimension > > const &t_cells)
Extracts vertices from cells.
auto find_min_timevalue(Container &&t_vertices) -> Int_precision
auto filter_edges(std::vector< Edge_handle_t< dimension > > const &t_edges, bool t_is_Timelike_pred) -> std::vector< Edge_handle_t< dimension > >
auto squared_radius(Vertex_handle_t< dimension > const &t_vertex) -> double
Calculate the squared radius from the origin.
auto make_causal_vertices(std::span< Point_t< dimension > const > vertices, std::span< size_t const > timevalues) -> Causal_vertices_t< dimension >
Create causal vertices from vertices and timevalues.
auto fix_timevalues(Delaunay_t< dimension > &t_triangulation) -> bool
Fix the vertices of a cell to be consistent with the foliation.
void print_neighboring_cells(Cell_handle_t< dimension > cell)
Print neighboring cells.
auto check_cells(Delaunay_t< dimension > const &t_triangulation) -> bool
Check all finite cells in the Delaunay triangulation.
auto collect_vertices(Delaunay_t< dimension > const &t_triangulation)
Obtain all finite vertices in the Delaunay triangulation.
auto check_timevalues(Delaunay_t< dimension > const &t_triangulation) -> std::optional< std::vector< Cell_handle_t< dimension > > >
Check cells for correct foliation.
auto is_cell_type_correct(Cell_handle_t< dimension > const &t_cell) -> bool
Checks if a cell is classified correctly.
void print_cell(Cell_handle_t< dimension > cell)
Print a cell in the triangulation.
auto expected_timevalue(Vertex_handle_t< dimension > const &t_vertex, double t_initial_radius, double t_foliation_spacing) -> Int_precision
Find the expected timevalue for a vertex.
auto collect_edges(Delaunay_t< dimension > const &delaunay)
Returns a container of all the finite edges in the triangulation.
auto classify_edge(Edge_handle_t< dimension > const &t_edge) -> bool
Predicate to classify edge as timelike or spacelike.
auto check_vertices(Delaunay_t< dimension > const &t_triangulation, double t_initial_radius, double t_foliation_spacing)
Check if vertices have the correct timevalues.
auto find_vertex(Delaunay_t< dimension > const &delaunay, Point_t< dimension > const &point) -> std::optional< Vertex_handle_t< dimension > >
Returns the vertex containing the given point.
Cell_type
(n,m) is number of vertices on (lower, higher) timeslice
auto find_incorrect_vertices(std::vector< Cell_handle_t< dimension > > const &t_cells, double t_initial_radius, double t_foliation_spacing)
Obtain vertices with incorrect timevalues.
auto is_vertex_timevalue_correct(Vertex_handle_t< dimension > const &t_vertex, double const t_initial_radius, double const t_foliation_spacing) -> bool
Checks if vertex timevalue is correct.
void debug_print_cells(Container &&t_cells)
Write to debug log timevalues of each vertex in the cell and the resulting cell->info.
auto collect_cells(Delaunay_t< dimension > const &t_triangulation) -> std::vector< Cell_handle_t< dimension > >
Obtain all finite cells in the Delaunay triangulation.
auto volume_per_timeslice(Container &&t_facets) -> std::multimap< Int_precision, Facet_t< 3 > >
Collect spacelike facets into a container indexed by time value.
auto fix_cells(Delaunay_t< dimension > const &t_triangulation) -> bool
Fix simplices with the wrong type.
auto filter_cells(std::vector< Cell_handle_t< dimension > > const &t_cells, Cell_type const &t_cell_type) -> std::vector< Cell_handle_t< dimension > >
auto find_max_timevalue(Container &&t_vertices) -> Int_precision
auto expected_cell_type(Cell_handle_t< dimension > const &t_cell)
Classifies cells by their timevalues.
auto find_cell(Delaunay_t< dimension > const &delaunay, Vertex_handle_t< dimension > const &vh1, Vertex_handle_t< dimension > const &vh2, Vertex_handle_t< dimension > const &vh3, Vertex_handle_t< dimension > const &vh4) -> std::optional< Cell_handle_t< dimension > >
Returns the cell containing the vertices.
void print_cells(Container &&t_cells)
Print timevalues of each vertex in the cell and the resulting cell->info()
auto find_incorrect_cells(Delaunay_t< dimension > const &t_triangulation)
Check all finite cells in the Delaunay triangulation.
auto find_bad_vertex(Cell_handle_t< dimension > const &cell) -> Vertex_handle_t< dimension >
Find the vertex that is causing a cell's foliation to be invalid.
auto fix_vertices(std::vector< Cell_handle_t< dimension > > const &t_cells, double t_initial_radius, double t_foliation_spacing)
Fix vertices with incorrect timevalues.
auto make_foliated_ball(Int_precision const t_simplices, Int_precision const t_timeslices, double const initial_radius=INITIAL_RADIUS, double const foliation_spacing=FOLIATION_SPACING)
Make foliated ball.
auto make_triangulation(Int_precision const t_simplices, Int_precision t_timeslices, double const initial_radius=INITIAL_RADIUS, double const foliation_spacing=FOLIATION_SPACING) -> Delaunay_t< dimension >
Make a Delaunay triangulation.
static double constexpr TOLERANCE
Sets epsilon values for floating point comparisons.
Definition: Settings.hpp:51
std::int_fast32_t Int_precision
Definition: Settings.hpp:31
static double constexpr INITIAL_RADIUS
Default foliated triangulation spacings.
Definition: Settings.hpp:47
Traits class for particular uses of CGAL.
Utility functions.
auto incident_cells(Ts &&... args) const noexcept -> decltype(auto)
Perfect forwarding to TriangulationDataStructure_3::incident_cells.
FoliatedTriangulation(FoliatedTriangulation &&other) noexcept
Move ctor.
auto is_foliated() const -> bool
Verifies the triangulation is properly foliated.
FoliatedTriangulation(Int_precision const t_simplices, Int_precision const t_timeslices, double const t_initial_radius=INITIAL_RADIUS, double const t_foliation_spacing=FOLIATION_SPACING)
Constructor with parameters.
void print_edges() const
Print timevalues of each vertex in the edge and classify as timelike or spacelike.
auto get_vertices_span() const noexcept -> std::span< Vertex_handle const >
auto degree(VertexHandle &&t_vertex) const
Perfect forwarding to TriangulationDataStructure_3::degree.
auto N2_SL() const -> std::multimap< Int_precision, TriangulationTraits< 3 >::Facet > const &
auto get_spacelike_edges() const -> Edge_container const &
auto get_one_three() const noexcept -> Cell_container const &
void print_volume_per_timeslice() const
Print the number of spacelike faces per timeslice.
FoliatedTriangulation(Delaunay triangulation, double const initial_radius=INITIAL_RADIUS, double const foliation_spacing=FOLIATION_SPACING)
Constructor using delaunay triangulation Pass-by-value-then-move. Delaunay is the ctor for the Delaun...
auto get_three_one() const noexcept -> std::span< Cell_handle const >
FoliatedTriangulation(Causal_vertices_t< 3 > const &causal_vertices, double const t_initial_radius=INITIAL_RADIUS, double const t_foliation_spacing=FOLIATION_SPACING)
Constructor from Causal_vertices.
auto does_vertex_radius_match_timevalue(Vertex_handle_t< 3 > const t_vertex) const -> bool
Check the radius of a vertex from the origin with its timevalue.
FoliatedTriangulation(FoliatedTriangulation const &other) noexcept
Copy Constructor.
auto flip(Ts &&... args)
Call one of the TSD3.flip functions.
auto get_timelike_edges() const noexcept -> Edge_container const &
auto fix_vertices() const -> bool
Fix vertices with wrong timevalues after foliation.
auto fix_cells() const -> bool
Fix all cells in the triangulation.
void print() const
Print triangulation statistics.
auto get_vertices() const noexcept -> Vertex_container const &
auto operator=(FoliatedTriangulation other) noexcept -> FoliatedTriangulation &
Copy/Move Assignment operator.
auto incident_cells(VertexHandle &&t_vh) const noexcept -> decltype(auto)
Perfect forwarding to TriangulationDataStructure_3::incident_cells.
auto expected_timevalue(Vertex_handle_t< 3 > const &t_vertex) const -> int
Calculate the expected timevalue for a vertex.
auto get_two_two() const noexcept -> Cell_container const &
auto expected_radius(Vertex_handle_t< 3 > const &t_vertex) const -> double
Calculates the expected radial distance of a vertex.
friend void swap(FoliatedTriangulation &swap_from, FoliatedTriangulation &swap_into) noexcept
Non-member swap function for Foliated Triangulations.
auto check_all_cells() const -> bool
Check that all cells are correctly classified.
void print_cells() const
Print timevalues of each vertex in the cell and the resulting cell->info()
auto classify_cells(Cell_container const &cells) const -> Cell_container
Classify cells.
This is std::movable from <concepts>