Tatooine
topological_skeleton.h
Go to the documentation of this file.
1#ifndef TATOOINE_TOPOLIGICAL_SKELEKTON
2#define TATOOINE_TOPOLIGICAL_SKELEKTON
3//==============================================================================
4#include <vector>
5#include <tatooine/tensor.h>
6#include <tatooine/grid_sampler.h>
7#include <tatooine/sampled_field.h>
8#include <tatooine/integration/integrator.h>
9#include <tatooine/line.h>
12//==============================================================================
13namespace tatooine {
14//==============================================================================
15template <typename Real, size_t N, template <typename> typename Interpolator>
17//==============================================================================
18// 2D
19//==============================================================================
20template <typename Real, template <typename> typename Interpolator>
21struct topological_skeleton<Real, 2, Interpolator> {
22 std::vector<vec<Real, 2>> saddles, centers, sources, sinks, repelling_foci,
23 attracting_foci, boundary_switch_points;
24 std::vector<parameterized_line<Real, 2, Interpolator>> separatrices;
25};
26//==============================================================================
29template <typename Real, typename Integrator,
30 template <typename> typename Interpolator>
32 const sampled_field<
33 grid_sampler<Real, 2, vec<Real, 2>, interpolation::linear,
35 Real, 2, 2>& v,
36 const integration::integrator<Real, 2, Interpolator, Integrator>&
37 integrator, const Real tau = 100, const Real eps = 1e-7) {
38 using integral_t = typename Integrator::integral_t;
40
41 auto vn = normalize(v);
42 auto J = diff(v);
43
44 // critical points
45 std::vector<mat<Real, 2, 2>> saddle_eigvecs;
46 std::vector<vec<Real, 2>> saddle_eigvals;
47 for (const auto& cp : find_critical_points(v.sampler())) {
48 auto [eigvecs, eigvals] = eigenvectors(J(cp));
49 if (std::abs(eigvals(0).imag()) < 1e-10 &&
50 std::abs(eigvals(1).imag()) < 1e-10) {
51 // non-swirling behavior
52 if (eigvals(0).real() < 0 && eigvals(1).real() < 0) {
53 skel.sinks.push_back(cp);
54 } else if (eigvals(0).real() > 0 && eigvals(1).real() > 0) {
55 skel.sources.push_back(cp);
56 } else {
57 skel.saddles.push_back(cp);
58 saddle_eigvecs.push_back(real(eigvecs));
59 saddle_eigvals.push_back(real(eigvals));
60 }
61 } else {
62 // swirling behavior
63 if (eigvals(0).real() < -1e-10 && eigvals(1).real() < -1e-10) {
64 skel.attracting_foci.push_back(cp);
65 } else if (eigvals(0).real() > 1e-10 && eigvals(1).real() > 1e-10) {
66 skel.repelling_foci.push_back(cp);
67 } else {
68 skel.centers.push_back(cp);
69 }
70 }
71 }
72 // create separatrices starting from saddle points
73 auto saddle_eigvecs_it = begin(saddle_eigvecs);
74 auto saddle_eigvals_it = begin(saddle_eigvals);
75 for (const auto& saddle : skel.saddles) {
76 const auto& eigvecs = *(saddle_eigvecs_it++);
77 const auto& eigvals = *(saddle_eigvals_it++);
78 for (size_t i = 0; i < 2; ++i) {
79 const double cur_tau = eigvals(i) > 0 ? tau : -tau;
80 skel.separatrices.push_back(integrator.integrate(
81 vn, saddle + normalize(eigvecs.col(i)) * eps, 0, cur_tau));
82 skel.separatrices.push_back(integrator.integrate(
83 vn, saddle - normalize(eigvecs.col(i)) * eps, 0, cur_tau));
84 }
85 }
86
87 // boundary switch points
88 for (const auto& bsp : find_boundary_switch_points(v)) {
89 skel.boundary_switch_points.push_back(bsp);
90
91 // calculate separatrices if flowing into domain
92 auto a = J(bsp) * v(bsp);
93 bool integrate = true;
94
95 if (bsp(0) == v.sampler().dimension(0).front()) {
96 if (a(0) < 0) { integrate = false; }
97 } else if (bsp(0) == v.sampler().dimension(0).back()) {
98 if (a(0) > 0) { integrate = false; }
99 } else if (bsp(1) == v.sampler().dimension(1).front()) {
100 if (a(1) < 0) { integrate = false; }
101 } else if (bsp(1) == v.sampler().dimension(1).back()) {
102 if (a(1) > 0) { integrate = false; }
103 }
104
105 if (integrate) {
106 skel.separatrices.push_back(integrator.integrate(vn, bsp, 0, tau));
107 skel.separatrices.push_back(integrator.integrate(vn, bsp, 0, -tau));
108 }
109 }
110 return skel;
111}
112
113//==============================================================================
114} // namespace tatooine
115//==============================================================================
116#endif
Definition: algorithm.h:6
auto begin(Range &&range)
Definition: iterator_facade.h:318
auto real(base_tensor< Tensor, std::complex< T >, Dims... > const &t)
Definition: complex_tensor_views.h:173
auto find_critical_points(detail::rectilinear_grid::vertex_property_sampler< detail::rectilinear_grid::typed_vertex_property_interface< Grid, vec< Real, 2 >, HasNonConstReference >, interpolation::linear, interpolation::linear > const &s)
Definition: critical_points.h:15
constexpr auto normalize(base_tensor< Tensor, T, N > const &t_in) -> vec< T, N >
Definition: tensor_operations.h:100
auto find_boundary_switch_points(const grid_sampler< Real, 2, vec< Real, 2 >, interpolation::linear, interpolation::linear > &sampler)
Definition: boundary_switch.h:12
auto imag(base_tensor< Tensor, std::complex< T >, Dims... > const &tensor)
Definition: complex_tensor_views.h:86
constexpr auto diff(polynomial< Real, Degree > const &f)
Definition: polynomial.h:179
auto compute_topological_skeleton(const sampled_field< grid_sampler< Real, 2, vec< Real, 2 >, interpolation::linear, interpolation::linear >, Real, 2, 2 > &v, const integration::integrator< Real, 2, Interpolator, Integrator > &integrator, const Real tau=100, const Real eps=1e-7)
Definition: topological_skeleton.h:31
auto eigenvectors(Mat &&B)
Definition: eigenvalues.h:123
Definition: interpolation.h:16
std::vector< vec< Real, 2 > > attracting_foci
Definition: topological_skeleton.h:23
std::vector< vec< Real, 2 > > centers
Definition: topological_skeleton.h:22
std::vector< parameterized_line< Real, 2, Interpolator > > separatrices
Definition: topological_skeleton.h:24
Definition: topological_skeleton.h:16
Definition: vec.h:12