Tatooine
parallel_vectors.h
Go to the documentation of this file.
1#ifndef TATOOINE_PARALLEL_VECTORS_H
2#define TATOOINE_PARALLEL_VECTORS_H
3//==============================================================================
4#if TATOOINE_PARALLEL_FOR_LOOPS_AVAILABLE
6
7#endif
9#include <tatooine/field.h>
10#include <tatooine/for_loop.h>
11#include <tatooine/line.h>
14
15#include <array>
16#include <boost/range/adaptor/transformed.hpp>
17#include <boost/range/numeric.hpp>
18#include <optional>
19#include <ranges>
20#include <tuple>
21#include <vector>
22//==============================================================================
96//==============================================================================
97namespace tatooine {
98//==============================================================================
99namespace detail {
100//==============================================================================
102template <typename Real, invocable<Vec3<Real>>... Preds>
103constexpr auto pv_on_tri(Vec3<Real> const& p0, Vec3<Real> const& v0,
104 Vec3<Real> const& w0, Vec3<Real> const& p1,
105 Vec3<Real> const& v1, Vec3<Real> const& w1,
106 Vec3<Real> const& p2, Vec3<Real> const& v2,
107 Vec3<Real> const& w2, Preds&&... preds)
108 -> std::optional<Vec3<Real>> {
109 Mat3<Real> V, W, M;
110 V.col(0) = v0;
111 V.col(1) = v1;
112 V.col(2) = v2;
113 W.col(0) = w0;
114 W.col(1) = w1;
115 W.col(2) = w2;
116
117 if (std::abs(det(V)) > 0) {
118 M = *solve(V, W);
119 } else if (std::abs(det(W)) > 0) {
120 M = *solve(W, V);
121 } else {
122 return {};
123 }
124
125 auto const [eigvecs, eigvals] = eigenvectors(M);
126 auto const ieig = imag(eigvecs);
127 auto const reig = real(eigvecs);
128
129 auto barycentric_coords = std::vector<Vec3<Real>>{};
130 for (std::size_t i = 0; i < 3; ++i) {
131 if ((ieig(0, i) == 0 && ieig(1, i) == 0 && ieig(2, i) == 0) &&
132 ((reig(0, i) <= 0 && reig(1, i) <= 0 && reig(2, i) <= 0) ||
133 (reig(0, i) >= 0 && reig(1, i) >= 0 && reig(2, i) >= 0))) {
134 Vec3<Real> const bc = real(eigvecs.col(i)) / sum(real(eigvecs.col(i)));
135 barycentric_coords.push_back(bc);
136 }
137 }
138
139 if (barycentric_coords.empty()) {
140 return {};
141 }
142
143 if (barycentric_coords.size() == 1) {
144 auto pos = barycentric_coords.front()(0) * p0 +
145 barycentric_coords.front()(1) * p1 +
146 barycentric_coords.front()(2) * p2;
147 if constexpr (sizeof...(Preds) > 0) {
148 if ((preds(pos) && ...)) {
149 return pos;
150 }
151 return {};
152 } else {
153 return pos;
154 }
155 } else {
156 // check if all found barycentric coordinates are the same
157 Real const eps = 1e-5;
158 for (unsigned int i = 1; i < barycentric_coords.size(); i++) {
159 for (unsigned int j = 0; j < i; j++) {
160 if (!approx_equal(barycentric_coords[i], barycentric_coords[j], eps)) {
161 return {};
162 }
163 }
164 }
165 auto const pos = barycentric_coords.front()(0) * p0 +
166 barycentric_coords.front()(1) * p1 +
167 barycentric_coords.front()(2) * p2;
168 return pos;
169 }
170}
171//----------------------------------------------------------------------------
172template <typename Real>
173static auto check_tet(std::optional<Vec3<Real>> const& tri0,
174 std::optional<Vec3<Real>> const& tri1,
175 std::optional<Vec3<Real>> const& tri2,
176 std::optional<Vec3<Real>> const& tri3,
177 std::vector<Line3<Real>>& lines) {
178 auto tris = std::vector<std::optional<Vec3<Real>> const*>{};
179 if (tri0) {
180 tris.push_back(&tri0);
181 }
182 if (tri1) {
183 tris.push_back(&tri1);
184 }
185 if (tri2) {
186 tris.push_back(&tri2);
187 }
188 if (tri3) {
189 tris.push_back(&tri3);
190 }
191
192 if (tris.size() == 1) {
193 // only 1 point
194 } else if (tris.size() == 2) {
195 merge(lines, Line3<Real>{*(*tris[0]), *(*tris[1])},
197 } else if (tris.size() == 3) {
198 // 3 points
199 } else if (tris.size() == 4) {
200 // several solutions;
201 }
202}
203//------------------------------------------------------------------------------
204auto constexpr is_even(integral auto const i) { return i % 2 == 0; }
205//------------------------------------------------------------------------------
206template <signed_integral Int = int>
207auto constexpr sign(bool pred) -> Int {
208 return pred ? 1 : -1;
209}
210//------------------------------------------------------------------------------
211auto constexpr turned(integral auto const... is) -> bool {
212 return (sign(is_even(is)) * ...) < 0;
213}
214//------------------------------------------------------------------------------
215auto check_turned_cube(auto const& x_faces, auto const& y_faces,
216 auto const& z_faces, auto const& inner_faces, auto& ls,
217 auto const ix, auto const iy) {
218 // 0236
219 check_tet(x_faces(ix, iy)[1], // 026
220 y_faces(ix, iy + 1)[0], // 236
221 z_faces(0, ix, iy)[1], // 023
222 inner_faces(ix, iy)[1], // 036
223 ls);
224 // 0135
225 check_tet(x_faces(ix + 1, iy)[0], // 135
226 y_faces(ix, iy)[0], // 015
227 z_faces(0, ix, iy)[0], // 013
228 inner_faces(ix, iy)[0], // 035
229 ls);
230 // 3567
231 check_tet(x_faces(ix + 1, iy)[1], // 357
232 y_faces(ix, iy + 1)[1], // 367
233 z_faces(1, ix, iy)[1], // 567
234 inner_faces(ix, iy)[2], // 356
235 ls);
236 // 0456
237 check_tet(x_faces(ix, iy)[0], // 046
238 y_faces(ix, iy)[1], // 045
239 z_faces(1, ix, iy)[0], // 456
240 inner_faces(ix, iy)[3], // 056
241 ls);
242 // 0356
243 check_tet(inner_faces(ix, iy)[0], // 035
244 inner_faces(ix, iy)[1], // 036
245 inner_faces(ix, iy)[2], // 356
246 inner_faces(ix, iy)[3], // 056
247 ls);
248}
249//------------------------------------------------------------------------------
250auto check_unturned_cube(auto const& x_faces, auto const& y_faces,
251 auto const& z_faces, auto const& inner_faces, auto& ls,
252 auto const ix, auto const iy) {
253 // 0124
254 check_tet(x_faces(ix, iy)[0], // 024
255 y_faces(ix, iy)[0], // 014
256 z_faces(0, ix, iy)[0], // 012
257 inner_faces(ix, iy)[0], // 124
258 ls);
259 // 1457
260 check_tet(x_faces(ix + 1, iy)[0], // 157
261 y_faces(ix, iy)[1], // 145
262 z_faces(1, ix, iy)[0], // 457
263 inner_faces(ix, iy)[2], // 147
264 ls);
265 // 2467
266 check_tet(x_faces(ix, iy)[1], // 246
267 y_faces(ix, iy + 1)[1], // 267
268 z_faces(1, ix, iy)[1], // 467
269 inner_faces(ix, iy)[3], // 247
270 ls);
271 // 1237
272 check_tet(x_faces(ix + 1, iy)[1], // 137
273 y_faces(ix, iy + 1)[0], // 237
274 z_faces(0, ix, iy)[1], // 123
275 inner_faces(ix, iy)[1], // 127
276 ls);
277 // 1247
278 check_tet(inner_faces(ix, iy)[0], // 124
279 inner_faces(ix, iy)[1], // 127
280 inner_faces(ix, iy)[2], // 147
281 inner_faces(ix, iy)[3], // 247
282 ls);
283}
284//------------------------------------------------------------------------------
285auto check_cube(auto const& x_faces, auto const& y_faces, auto const& z_faces,
286 auto const& inner_faces, auto& ls, auto const ix, auto const iy,
287 auto const iz) {
288 if (turned(ix, iy, iz)) {
289 check_turned_cube(x_faces, y_faces, z_faces, inner_faces, ls, ix, iy);
290 } else {
291 check_unturned_cube(x_faces, y_faces, z_faces, inner_faces, ls, ix, iy);
292 }
293}
294//------------------------------------------------------------------------------
295#if TATOOINE_PARALLEL_FOR_LOOPS_AVAILABLE
305template <typename Real, typename GetV, typename GetW, typename XDomain,
306 typename YDomain, typename ZDomain, invocable<Vec3<Real>>... Preds>
308 GetV&& getv, GetW&& getw,
310 execution_policy::parallel_t const policy, Preds&&... preds)
311 -> std::vector<Line3<Real>> {
312 // turned tets per cube: [0]: 0236 | [1]: 0135 | [2]: 3567 | [3]: 0356
313 // non-turned tets per cube: [0]: 0124 | [1]: 1457 | [2]: 2467 | [3]: 1247
314 using vec3 = Vec3<Real>;
315 using maybe_vec3 = std::optional<vec3>;
316 using maybe_vec3_arr2 = std::array<maybe_vec3, 2>;
317 using maybe_vec3_arr4 = std::array<maybe_vec3, 4>;
319 using inner_faces_arr = dynamic_multidim_array<maybe_vec3_arr4>;
320 auto iz = std::size_t(0);
321 auto const resolution = g.size();
322 auto const gv = g.vertices();
323 // turned inner tet order:
324 // [0]: 046 / 157 | [1]: 026 / 137
325 // non-turned inner tet order:
326 // [0]: 024 / 135 | [1]: 246 / 357
327 auto x_faces = faces_arr{resolution[0], resolution[1] - 1};
328 // turned inner tet order:
329 // [0]: 015 / 237 | [1]: 045 / 267
330 // non-turned inner tet order:
331 // [0]: 014 / 236 | [1]: 145 / 367
332 auto y_faces = faces_arr{resolution[0] - 1, resolution[1]};
333 // turned inner tet order:
334 // [0]: 013 / 457 | [1]: 023 / 467
335 // non-turned inner tet order:
336 // [0]: 012 / 456 | [1]: 123 / 567
337 auto z_faces = faces_arr{2, resolution[0] - 1, resolution[1] - 1};
338 // turned inner tet order:
339 // [0]: 035 | [1]: 036 | [2]: 356 | [3]: 056
340 // non-turned inner tet order:
341 // [0]: 124 | [1]: 127 | [2]: 147 | [3]: 247
342 auto inner_faces = inner_faces_arr{resolution[0] - 1, resolution[1] - 1};
343
344 auto update_x_faces = [&](std::size_t const ix, std::size_t const iy) {
345 auto const p = std::array{
346 gv(ix, iy, iz), // 0
347 gv(ix, iy, iz + 1), // 4
348 gv(ix, iy + 1, iz), // 2
349 gv(ix, iy + 1, iz + 1) // 6
350 };
351
352 decltype(auto) v0 = getv(ix, iy, iz, p[0]);
353 if (isnan(v0)) {
354 return;
355 }
356 decltype(auto) v4 = getv(ix, iy, iz + 1, p[1]);
357 if (isnan(v4)) {
358 return;
359 }
360 decltype(auto) v2 = getv(ix, iy + 1, iz, p[2]);
361 if (isnan(v2)) {
362 return;
363 }
364 decltype(auto) v6 = getv(ix, iy + 1, iz + 1, p[3]);
365 if (isnan(v6)) {
366 return;
367 }
368 decltype(auto) w0 = getw(ix, iy, iz, p[0]);
369 if (isnan(w0)) {
370 return;
371 }
372 decltype(auto) w4 = getw(ix, iy, iz + 1, p[1]);
373 if (isnan(w4)) {
374 return;
375 }
376 decltype(auto) w2 = getw(ix, iy + 1, iz, p[2]);
377 if (isnan(w2)) {
378 return;
379 }
380 decltype(auto) w6 = getw(ix, iy + 1, iz + 1, p[3]);
381 if (isnan(w6)) {
382 return;
383 }
384 if (turned(ix, iy, iz)) {
385 x_faces(ix, iy)[0] = // 046
386 detail::pv_on_tri(p[0], v0, w0, p[1], v4, w4, p[3], v6, w6,
387 std::forward<Preds>(preds)...);
388 x_faces(ix, iy)[1] = // 026
389 detail::pv_on_tri(p[0], v0, w0, p[3], v6, w6, p[2], v2, w2,
390 std::forward<Preds>(preds)...);
391 } else {
392 x_faces(ix, iy)[0] = // 024
393 detail::pv_on_tri(p[0], v0, w0, p[1], v4, w4, p[2], v2, w2,
394 std::forward<Preds>(preds)...);
395 x_faces(ix, iy)[1] = // 246
396 detail::pv_on_tri(p[1], v4, w4, p[3], v6, w6, p[2], v2, w2,
397 std::forward<Preds>(preds)...);
398 }
399 };
400 auto update_y_faces = [&](std::size_t const ix, std::size_t const iy) {
401 auto const p = std::array{
402 gv(ix, iy, iz), // 0
403 gv(ix + 1, iy, iz), // 1
404 gv(ix, iy, iz + 1), // 4
405 gv(ix + 1, iy, iz + 1) // 5
406 };
407
408 decltype(auto) v0 = getv(ix, iy, iz, p[0]);
409 if (isnan(v0)) {
410 return;
411 }
412 decltype(auto) v1 = getv(ix + 1, iy, iz, p[1]);
413 if (isnan(v1)) {
414 return;
415 }
416 decltype(auto) v4 = getv(ix, iy, iz + 1, p[2]);
417 if (isnan(v4)) {
418 return;
419 }
420 decltype(auto) v5 = getv(ix + 1, iy, iz + 1, p[3]);
421 if (isnan(v5)) {
422 return;
423 }
424 decltype(auto) w0 = getw(ix, iy, iz, p[0]);
425 if (isnan(w0)) {
426 return;
427 }
428 decltype(auto) w1 = getw(ix + 1, iy, iz, p[1]);
429 if (isnan(w1)) {
430 return;
431 }
432 decltype(auto) w4 = getw(ix, iy, iz + 1, p[2]);
433 if (isnan(w4)) {
434 return;
435 }
436 decltype(auto) w5 = getw(ix + 1, iy, iz + 1, p[3]);
437 if (isnan(w5)) {
438 return;
439 }
440 if (turned(ix, iy, iz)) {
441 y_faces(ix, iy)[0] = // 015
442 detail::pv_on_tri(p[0], v0, w0, p[1], v1, w1, p[3], v5, w5,
443 std::forward<Preds>(preds)...);
444 y_faces(ix, iy)[1] = // 045
445 detail::pv_on_tri(p[0], v0, w0, p[3], v5, w5, p[2], v4, w4,
446 std::forward<Preds>(preds)...);
447 } else {
448 y_faces(ix, iy)[0] = // 014
449 detail::pv_on_tri(p[0], v0, w0, p[1], v1, w1, p[2], v4, w4,
450 std::forward<Preds>(preds)...);
451 y_faces(ix, iy)[1] = // 145
452 detail::pv_on_tri(p[1], v1, w1, p[3], v5, w5, p[2], v4, w4,
453 std::forward<Preds>(preds)...);
454 }
455 };
456 auto update_z = [&](std::size_t const ix, std::size_t const iy,
457 std::size_t const iz, std::size_t const write_iz) {
458 assert(write_iz == 0 || write_iz == 1);
459 auto const p = std::array{
460 gv(ix, iy, iz), // 0
461 gv(ix + 1, iy, iz), // 1
462 gv(ix, iy + 1, iz), // 2
463 gv(ix + 1, iy + 1, iz) // 3
464 };
465
466 decltype(auto) v0 = getv(ix, iy, iz, p[0]);
467 if (isnan(v0)) {
468 return;
469 }
470 decltype(auto) v1 = getv(ix + 1, iy, iz, p[1]);
471 if (isnan(v1)) {
472 return;
473 }
474 decltype(auto) v2 = getv(ix, iy + 1, iz, p[2]);
475 if (isnan(v2)) {
476 return;
477 }
478 decltype(auto) v3 = getv(ix + 1, iy + 1, iz, p[3]);
479 if (isnan(v3)) {
480 return;
481 }
482 decltype(auto) w0 = getw(ix, iy, iz, p[0]);
483 if (isnan(w0)) {
484 return;
485 }
486 decltype(auto) w1 = getw(ix + 1, iy, iz, p[1]);
487 if (isnan(w1)) {
488 return;
489 }
490 decltype(auto) w2 = getw(ix, iy + 1, iz, p[2]);
491 if (isnan(w2)) {
492 return;
493 }
494 decltype(auto) w3 = getw(ix + 1, iy + 1, iz, p[3]);
495 if (isnan(w3)) {
496 return;
497 }
498 if (turned(ix, iy, iz)) {
499 z_faces(write_iz, ix, iy)[0] = // 013
500 detail::pv_on_tri(p[0], v0, w0, p[1], v1, w1, p[3], v3, w3,
501 std::forward<Preds>(preds)...);
502 z_faces(write_iz, ix, iy)[1] = // 023
503 detail::pv_on_tri(p[0], v0, w0, p[3], v3, w3, p[2], v2, w2,
504 std::forward<Preds>(preds)...);
505 } else {
506 z_faces(write_iz, ix, iy)[0] = // 012
507 detail::pv_on_tri(p[0], v0, w0, p[1], v1, w1, p[2], v2, w2,
508 std::forward<Preds>(preds)...);
509 z_faces(write_iz, ix, iy)[1] = // 123
510 detail::pv_on_tri(p[1], v1, w1, p[3], v3, w3, p[2], v2, w2,
511 std::forward<Preds>(preds)...);
512 }
513 };
514 auto move_zs = [&]() {
516 [&](auto const... is) { z_faces(0, is...) = z_faces(1, is...); },
517 policy, resolution[0] - 1, resolution[1] - 1);
518 };
519 // initialize front constant-z-face
520 tatooine::for_loop([&](auto const... is) { update_z(is..., 0, 0); }, policy,
521 resolution[0] - 1, resolution[1] - 1);
522 auto update_z_faces = [&](std::size_t const ix, std::size_t const iy) {
523 update_z(ix, iy, iz + 1, 1);
524 };
525
526 auto update_inner_faces = [&](std::size_t const ix, std::size_t const iy) {
527 auto const gv = g.vertices();
528 if (turned(ix, iy, iz)) {
529 auto const p = std::array{gv(ix, iy, iz), gv(ix + 1, iy + 1, iz),
530 gv(ix + 1, iy, iz + 1), gv(ix, iy + 1, iz + 1)};
531
532 decltype(auto) v0 = getv(ix, iy, iz, p[0]);
533 if (isnan(v0)) {
534 return;
535 }
536 decltype(auto) v3 = getv(ix + 1, iy + 1, iz, p[1]);
537 if (isnan(v3)) {
538 return;
539 }
540 decltype(auto) v5 = getv(ix + 1, iy, iz + 1, p[2]);
541 if (isnan(v5)) {
542 return;
543 }
544 decltype(auto) v6 = getv(ix, iy + 1, iz + 1, p[3]);
545 if (isnan(v6)) {
546 return;
547 }
548 decltype(auto) w0 = getw(ix, iy, iz, p[0]);
549 if (isnan(w0)) {
550 return;
551 }
552 decltype(auto) w3 = getw(ix + 1, iy + 1, iz, p[1]);
553 if (isnan(w3)) {
554 return;
555 }
556 decltype(auto) w5 = getw(ix + 1, iy, iz + 1, p[2]);
557 if (isnan(w5)) {
558 return;
559 }
560 decltype(auto) w6 = getw(ix, iy + 1, iz + 1, p[3]);
561 if (isnan(w6)) {
562 return;
563 }
564 inner_faces(ix, iy)[0] = // 035
565 detail::pv_on_tri(p[0], v0, w0, p[2], v5, w5, p[1], v3, w3,
566 std::forward<Preds>(preds)...);
567 inner_faces(ix, iy)[1] = // 036
568 detail::pv_on_tri(p[0], v0, w0, p[1], v3, w3, p[3], v6, w6,
569 std::forward<Preds>(preds)...);
570 inner_faces(ix, iy)[2] = // 356
571 detail::pv_on_tri(p[1], v3, w3, p[2], v5, w5, p[3], v6, w6,
572 std::forward<Preds>(preds)...);
573 inner_faces(ix, iy)[3] = // 056
574 detail::pv_on_tri(p[0], v0, w0, p[3], v6, w6, p[2], v5, w5,
575 std::forward<Preds>(preds)...);
576 } else {
577 auto const p1 = gv(ix + 1, iy, iz);
578 auto const p2 = gv(ix, iy + 1, iz);
579 auto const p4 = gv(ix, iy, iz + 1);
580 auto const p7 = gv(ix + 1, iy + 1, iz + 1);
581
582 decltype(auto) v1 = getv(ix + 1, iy, iz, p1);
583 if (isnan(v1)) {
584 return;
585 }
586 decltype(auto) v2 = getv(ix, iy + 1, iz, p2);
587 if (isnan(v2)) {
588 return;
589 }
590 decltype(auto) v4 = getv(ix, iy, iz + 1, p4);
591 if (isnan(v4)) {
592 return;
593 }
594 decltype(auto) v7 = getv(ix + 1, iy + 1, iz + 1, p7);
595 if (isnan(v7)) {
596 return;
597 }
598 decltype(auto) w1 = getw(ix + 1, iy, iz, p1);
599 if (isnan(w1)) {
600 return;
601 }
602 decltype(auto) w2 = getw(ix, iy + 1, iz, p2);
603 if (isnan(w2)) {
604 return;
605 }
606 decltype(auto) w4 = getw(ix, iy, iz + 1, p4);
607 if (isnan(w4)) {
608 return;
609 }
610 decltype(auto) w7 = getw(ix + 1, iy + 1, iz + 1, p7);
611 if (isnan(w7)) {
612 return;
613 }
614 inner_faces(ix, iy)[0] = // 124
615 detail::pv_on_tri(p1, v1, w1, p4, v4, w4, p2, v2, w2,
616 std::forward<Preds>(preds)...);
617 inner_faces(ix, iy)[1] = // 127
618 detail::pv_on_tri(p1, v1, w1, p7, v7, w7, p2, v2, w2,
619 std::forward<Preds>(preds)...);
620 inner_faces(ix, iy)[2] = // 147
621 detail::pv_on_tri(p1, v1, w1, p4, v4, w4, p7, v7, w7,
622 std::forward<Preds>(preds)...);
623 inner_faces(ix, iy)[3] = // 247
624 detail::pv_on_tri(p2, v2, w2, p7, v7, w7, p4, v4, w4,
625 std::forward<Preds>(preds)...);
626 }
627 };
628 auto num_threads = for_loop_num_parallel_threads();
629 auto line_sets_per_thread =
630 std::vector<aligned<std::vector<Line3<Real>>>>(num_threads);
631
632 auto compute_line_segments = [&](auto const... ixy) {
633 check_cube(x_faces, y_faces, z_faces, inner_faces,
634 *line_sets_per_thread[omp_get_thread_num()], ixy..., iz);
635 };
636 for (; iz < resolution[2] - 1; ++iz) {
637 tatooine::for_loop(update_x_faces, policy, resolution[0],
638 resolution[1] - 1);
639 tatooine::for_loop(update_y_faces, policy, resolution[0] - 1,
640 resolution[1]);
641 tatooine::for_loop(update_z_faces, policy, resolution[0] - 1,
642 resolution[1] - 1);
643 tatooine::for_loop(update_inner_faces, policy, resolution[0] - 1,
644 resolution[1] - 1);
645 tatooine::for_loop(compute_line_segments, policy, resolution[0] - 1,
646 resolution[1] - 1);
647 if (iz < resolution[2] - 2) {
648 move_zs();
649 }
650 }
651 using boost::accumulate;
652 using boost::adaptors::transformed;
653 auto const s = [](auto const& l) { return l->size(); };
654 auto all_lines = std::vector<Line3<Real>>{};
655 all_lines.reserve(
656 accumulate(line_sets_per_thread | transformed(s), std::size_t(0)));
657 for (auto const& line_set : line_sets_per_thread) {
658 for (auto const& line : *line_set) {
660 }
661 }
662 return all_lines;
663}
664#endif
665//------------------------------------------------------------------------------
675template <typename Real, typename GetV, typename GetW, typename XDomain,
676 typename YDomain, typename ZDomain, invocable<Vec3<Real>>... Preds>
678 GetV&& getv, GetW&& getw,
680 execution_policy::sequential_t const policy, Preds&&... preds) {
681 // turned tets per cube: [0]: 0236 | [1]: 0135 | [2]: 3567 | [3]: 0356
682 // non-turned tets per cube: [0]: 0124 | [1]: 1457 | [2]: 2467 | [3]: 1247
683 using vec3 = Vec3<Real>;
684 using maybe_vec3 = std::optional<vec3>;
685 using maybe_vec3_arr2 = std::array<maybe_vec3, 2>;
686 using maybe_vec3_arr4 = std::array<maybe_vec3, 4>;
688 using inner_faces_arr = dynamic_multidim_array<maybe_vec3_arr4>;
689 auto iz = std::size_t(0);
690 auto const resolution = g.size();
691 auto const gv = g.vertices();
692 // turned inner tet order:
693 // [0]: 046 / 157 | [1]: 026 / 137
694 // non-turned inner tet order:
695 // [0]: 024 / 135 | [1]: 246 / 357
696 auto x_faces = faces_arr{resolution[0], resolution[1] - 1};
697 auto update_x_faces = [&](std::size_t const ix, std::size_t const iy) {
698 auto const p = std::array{
699 gv(ix, iy, iz), // 0
700 gv(ix, iy, iz + 1), // 4
701 gv(ix, iy + 1, iz), // 2
702 gv(ix, iy + 1, iz + 1) // 6
703 };
704
705 decltype(auto) v0 = getv(ix, iy, iz, p[0]);
706 if (isnan(v0)) {
707 return;
708 }
709 decltype(auto) v4 = getv(ix, iy, iz + 1, p[1]);
710 if (isnan(v4)) {
711 return;
712 }
713 decltype(auto) v2 = getv(ix, iy + 1, iz, p[2]);
714 if (isnan(v2)) {
715 return;
716 }
717 decltype(auto) v6 = getv(ix, iy + 1, iz + 1, p[3]);
718 if (isnan(v6)) {
719 return;
720 }
721 decltype(auto) w0 = getw(ix, iy, iz, p[0]);
722 if (isnan(w0)) {
723 return;
724 }
725 decltype(auto) w4 = getw(ix, iy, iz + 1, p[1]);
726 if (isnan(w4)) {
727 return;
728 }
729 decltype(auto) w2 = getw(ix, iy + 1, iz, p[2]);
730 if (isnan(w2)) {
731 return;
732 }
733 decltype(auto) w6 = getw(ix, iy + 1, iz + 1, p[3]);
734 if (isnan(w6)) {
735 return;
736 }
737 if (turned(ix, iy, iz)) {
738 x_faces(ix, iy)[0] = // 046
739 detail::pv_on_tri(p[0], v0, w0, p[1], v4, w4, p[3], v6, w6,
740 std::forward<Preds>(preds)...);
741 x_faces(ix, iy)[1] = // 026
742 detail::pv_on_tri(p[0], v0, w0, p[3], v6, w6, p[2], v2, w2,
743 std::forward<Preds>(preds)...);
744 } else {
745 x_faces(ix, iy)[0] = // 024
746 detail::pv_on_tri(p[0], v0, w0, p[1], v4, w4, p[2], v2, w2,
747 std::forward<Preds>(preds)...);
748 x_faces(ix, iy)[1] = // 246
749 detail::pv_on_tri(p[1], v4, w4, p[3], v6, w6, p[2], v2, w2,
750 std::forward<Preds>(preds)...);
751 }
752 };
753 // turned inner tet order:
754 // [0]: 015 / 237 | [1]: 045 / 267
755 // non-turned inner tet order:
756 // [0]: 014 / 236 | [1]: 145 / 367
757 auto y_faces = faces_arr{resolution[0] - 1, resolution[1]};
758 auto update_y_faces = [&](std::size_t const ix, std::size_t const iy) {
759 auto const p0 = gv(ix, iy, iz);
760 auto const p1 = gv(ix + 1, iy, iz);
761 auto const p4 = gv(ix, iy, iz + 1);
762 auto const p5 = gv(ix + 1, iy, iz + 1);
763
764 decltype(auto) v0 = getv(ix, iy, iz, p0);
765 if (isnan(v0)) {
766 return;
767 }
768 decltype(auto) v1 = getv(ix + 1, iy, iz, p1);
769 if (isnan(v1)) {
770 return;
771 }
772 decltype(auto) v4 = getv(ix, iy, iz + 1, p4);
773 if (isnan(v4)) {
774 return;
775 }
776 decltype(auto) v5 = getv(ix + 1, iy, iz + 1, p5);
777 if (isnan(v5)) {
778 return;
779 }
780 decltype(auto) w0 = getw(ix, iy, iz, p0);
781 if (isnan(w0)) {
782 return;
783 }
784 decltype(auto) w1 = getw(ix + 1, iy, iz, p1);
785 if (isnan(w1)) {
786 return;
787 }
788 decltype(auto) w4 = getw(ix, iy, iz + 1, p4);
789 if (isnan(w4)) {
790 return;
791 }
792 decltype(auto) w5 = getw(ix + 1, iy, iz + 1, p5);
793 if (isnan(w5)) {
794 return;
795 }
796 if (turned(ix, iy, iz)) {
797 y_faces(ix, iy)[0] = // 015
798 detail::pv_on_tri(p0, v0, w0, p1, v1, w1, p5, v5, w5,
799 std::forward<Preds>(preds)...);
800 y_faces(ix, iy)[1] = // 045
801 detail::pv_on_tri(p0, v0, w0, p5, v5, w5, p4, v4, w4,
802 std::forward<Preds>(preds)...);
803 } else {
804 y_faces(ix, iy)[0] = // 014
805 detail::pv_on_tri(p0, v0, w0, p1, v1, w1, p4, v4, w4,
806 std::forward<Preds>(preds)...);
807 y_faces(ix, iy)[1] = // 145
808 detail::pv_on_tri(p1, v1, w1, p5, v5, w5, p4, v4, w4,
809 std::forward<Preds>(preds)...);
810 }
811 };
812 // turned inner tet order:
813 // [0]: 013 / 457 | [1]: 023 / 467
814 // non-turned inner tet order:
815 // [0]: 012 / 456 | [1]: 123 / 567
816 auto z_faces = faces_arr{2, resolution[0] - 1, resolution[1] - 1};
817 auto update_z = [&](std::size_t const ix, std::size_t const iy,
818 std::size_t const iz, std::size_t const write_iz) {
819 assert(write_iz == 0 || write_iz == 1);
820 auto const p0 = gv(ix, iy, iz);
821 auto const p1 = gv(ix + 1, iy, iz);
822 auto const p2 = gv(ix, iy + 1, iz);
823 auto const p3 = gv(ix + 1, iy + 1, iz);
824
825 decltype(auto) v0 = getv(ix, iy, iz, p0);
826 if (isnan(v0)) {
827 return;
828 }
829 decltype(auto) v1 = getv(ix + 1, iy, iz, p1);
830 if (isnan(v1)) {
831 return;
832 }
833 decltype(auto) v2 = getv(ix, iy + 1, iz, p2);
834 if (isnan(v2)) {
835 return;
836 }
837 decltype(auto) v3 = getv(ix + 1, iy + 1, iz, p3);
838 if (isnan(v3)) {
839 return;
840 }
841 decltype(auto) w0 = getw(ix, iy, iz, p0);
842 if (isnan(w0)) {
843 return;
844 }
845 decltype(auto) w1 = getw(ix + 1, iy, iz, p1);
846 if (isnan(w1)) {
847 return;
848 }
849 decltype(auto) w2 = getw(ix, iy + 1, iz, p2);
850 if (isnan(w2)) {
851 return;
852 }
853 decltype(auto) w3 = getw(ix + 1, iy + 1, iz, p3);
854 if (isnan(w3)) {
855 return;
856 }
857 if (turned(ix, iy, iz)) {
858 z_faces(write_iz, ix, iy)[0] = // 013
859 detail::pv_on_tri(p0, v0, w0, p1, v1, w1, p3, v3, w3,
860 std::forward<Preds>(preds)...);
861 z_faces(write_iz, ix, iy)[1] = // 023
862 detail::pv_on_tri(p0, v0, w0, p3, v3, w3, p2, v2, w2,
863 std::forward<Preds>(preds)...);
864 } else {
865 z_faces(write_iz, ix, iy)[0] = // 012
866 detail::pv_on_tri(p0, v0, w0, p1, v1, w1, p2, v2, w2,
867 std::forward<Preds>(preds)...);
868 z_faces(write_iz, ix, iy)[1] = // 123
869 detail::pv_on_tri(p1, v1, w1, p3, v3, w3, p2, v2, w2,
870 std::forward<Preds>(preds)...);
871 }
872 };
873 auto move_zs = [&]() {
875 [&](auto const... is) { z_faces(0, is...) = z_faces(1, is...); },
876 policy, resolution[0] - 1, resolution[1] - 1);
877 };
878 // initialize front constant-z-face
879 tatooine::for_loop([&](auto const... is) { update_z(is..., 0, 0); }, policy,
880 resolution[0] - 1, resolution[1] - 1);
881 auto update_z_faces = [&](std::size_t const ix, std::size_t const iy) {
882 update_z(ix, iy, iz + 1, 1);
883 };
884
885 // turned inner tet order:
886 // [0]: 035 | [1]: 036 | [2]: 356 | [3]: 056
887 // non-turned inner tet order:
888 // [0]: 124 | [1]: 127 | [2]: 147 | [3]: 247
889 auto inner_faces = inner_faces_arr{resolution[0] - 1, resolution[1] - 1};
890 auto update_inner_faces = [&](std::size_t ix, std::size_t iy) {
891 auto const gv = g.vertices();
892 if (turned(ix, iy, iz)) {
893 auto const p0 = gv(ix, iy, iz);
894 auto const p3 = gv(ix + 1, iy + 1, iz);
895 auto const p5 = gv(ix + 1, iy, iz + 1);
896 auto const p6 = gv(ix, iy + 1, iz + 1);
897
898 decltype(auto) v0 = getv(ix, iy, iz, p0);
899 if (isnan(v0)) {
900 return;
901 }
902 decltype(auto) v3 = getv(ix + 1, iy + 1, iz, p3);
903 if (isnan(v3)) {
904 return;
905 }
906 decltype(auto) v5 = getv(ix + 1, iy, iz + 1, p5);
907 if (isnan(v5)) {
908 return;
909 }
910 decltype(auto) v6 = getv(ix, iy + 1, iz + 1, p6);
911 if (isnan(v6)) {
912 return;
913 }
914 decltype(auto) w0 = getw(ix, iy, iz, p0);
915 if (isnan(w0)) {
916 return;
917 }
918 decltype(auto) w3 = getw(ix + 1, iy + 1, iz, p3);
919 if (isnan(w3)) {
920 return;
921 }
922 decltype(auto) w5 = getw(ix + 1, iy, iz + 1, p5);
923 if (isnan(w5)) {
924 return;
925 }
926 decltype(auto) w6 = getw(ix, iy + 1, iz + 1, p6);
927 if (isnan(w6)) {
928 return;
929 }
930 inner_faces(ix, iy)[0] = // 035
931 detail::pv_on_tri(p0, v0, w0, p5, v5, w5, p3, v3, w3,
932 std::forward<Preds>(preds)...);
933 inner_faces(ix, iy)[1] = // 036
934 detail::pv_on_tri(p0, v0, w0, p3, v3, w3, p6, v6, w6,
935 std::forward<Preds>(preds)...);
936 inner_faces(ix, iy)[2] = // 356
937 detail::pv_on_tri(p3, v3, w3, p5, v5, w5, p6, v6, w6,
938 std::forward<Preds>(preds)...);
939 inner_faces(ix, iy)[3] = // 056
940 detail::pv_on_tri(p0, v0, w0, p6, v6, w6, p5, v5, w5,
941 std::forward<Preds>(preds)...);
942 } else {
943 auto const p1 = gv(ix + 1, iy, iz);
944 auto const p2 = gv(ix, iy + 1, iz);
945 auto const p4 = gv(ix, iy, iz + 1);
946 auto const p7 = gv(ix + 1, iy + 1, iz + 1);
947
948 decltype(auto) v1 = getv(ix + 1, iy, iz, p1);
949 if (isnan(v1)) {
950 return;
951 }
952 decltype(auto) v2 = getv(ix, iy + 1, iz, p2);
953 if (isnan(v2)) {
954 return;
955 }
956 decltype(auto) v4 = getv(ix, iy, iz + 1, p4);
957 if (isnan(v4)) {
958 return;
959 }
960 decltype(auto) v7 = getv(ix + 1, iy + 1, iz + 1, p7);
961 if (isnan(v7)) {
962 return;
963 }
964 decltype(auto) w1 = getw(ix + 1, iy, iz, p1);
965 if (isnan(w1)) {
966 return;
967 }
968 decltype(auto) w2 = getw(ix, iy + 1, iz, p2);
969 if (isnan(w2)) {
970 return;
971 }
972 decltype(auto) w4 = getw(ix, iy, iz + 1, p4);
973 if (isnan(w4)) {
974 return;
975 }
976 decltype(auto) w7 = getw(ix + 1, iy + 1, iz + 1, p7);
977 if (isnan(w7)) {
978 return;
979 }
980 inner_faces(ix, iy)[0] = // 124
981 detail::pv_on_tri(p1, v1, w1, p4, v4, w4, p2, v2, w2,
982 std::forward<Preds>(preds)...);
983 inner_faces(ix, iy)[1] = // 127
984 detail::pv_on_tri(p1, v1, w1, p7, v7, w7, p2, v2, w2,
985 std::forward<Preds>(preds)...);
986 inner_faces(ix, iy)[2] = // 147
987 detail::pv_on_tri(p1, v1, w1, p4, v4, w4, p7, v7, w7,
988 std::forward<Preds>(preds)...);
989 inner_faces(ix, iy)[3] = // 247
990 detail::pv_on_tri(p2, v2, w2, p7, v7, w7, p4, v4, w4,
991 std::forward<Preds>(preds)...);
992 }
993 };
994 auto lines = std::vector<Line3<Real>>{};
995
996 auto compute_line_segments = [&](auto const... ixy) {
997 check_cube(x_faces, y_faces, z_faces, inner_faces, lines, ixy..., iz);
998 };
999 for (; iz < resolution[2] - 1; ++iz) {
1000 tatooine::for_loop(update_x_faces, policy, resolution[0],
1001 resolution[1] - 1);
1002 tatooine::for_loop(update_y_faces, policy, resolution[0] - 1,
1003 resolution[1]);
1004 tatooine::for_loop(update_z_faces, policy, resolution[0] - 1,
1005 resolution[1] - 1);
1006 tatooine::for_loop(update_inner_faces, policy, resolution[0] - 1,
1007 resolution[1] - 1);
1008 tatooine::for_loop(compute_line_segments, policy, resolution[0] - 1,
1009 resolution[1] - 1);
1010 if (iz < resolution[2] - 2) {
1011 move_zs();
1012 }
1013 }
1014 return lines;
1015}
1016//------------------------------------------------------------------------------
1020template <typename Real, typename GetV, typename GetW, typename XDomain,
1021 typename YDomain, typename ZDomain, invocable<Vec3<Real>>... Preds>
1023 GetV&& getv, GetW&& getw,
1025 execution_policy_tag auto const policy, Preds&&... preds) {
1026#if TATOOINE_PARALLEL_FOR_LOOPS_AVAILABLE
1027 return calc_parallel_vectors(
1028 std::forward<GetV>(getv), std::forward<GetW>(getw), g,
1029 execution_policy::sequential, std::forward<Preds>(preds)...);
1030#else
1031 return calc_parallel_vectors(
1032 std::forward<GetV>(getv), std::forward<GetW>(getw), g,
1033 execution_policy::parallel, std::forward<Preds>(preds)...);
1034#endif
1035}
1036//==============================================================================
1037} // namespace detail
1038//==============================================================================
1040template <typename VReal, typename WReal, typename XDomain, typename YDomain,
1041 typename ZDomain, arithmetic TReal,
1042 invocable<vec<common_type<VReal, WReal>, 3>>... Preds>
1046 TReal const t, execution_policy_tag auto const policy,
1047 Preds&&... preds) {
1048 return detail::calc_parallel_vectors<common_type<VReal, WReal>>(
1049 // get vf data by evaluating V field
1050 [&vf, t](auto const /*ix*/, auto const /*iy*/, auto const /*iz*/,
1051 auto const& p) { return vf(p, t); },
1052 // get wf data by evaluating W field
1053 [&wf, t](auto const /*ix*/, auto const /*iy*/, auto const /*iz*/,
1054 auto const& p) { return wf(p, t); },
1055 g, policy, std::forward<Preds>(preds)...);
1056}
1057//------------------------------------------------------------------------------
1059template <typename VReal, typename WReal, typename XDomain, typename YDomain,
1060 typename ZDomain, arithmetic TReal,
1061 invocable<vec<common_type<VReal, WReal>, 3>>... Preds>
1065 TReal const t, Preds&&... preds) {
1066#if TATOOINE_PARALLEL_FOR_LOOPS_AVAILABLE
1067 return parallel_vectors(vf, wf, g, t, execution_policy::parallel,
1068 std::forward<Preds>(preds)...);
1069#else
1071 std::forward<Preds>(preds)...);
1072#endif
1073}
1074//------------------------------------------------------------------------------
1076template <typename V, typename W, typename VReal, typename WReal,
1077 typename XDomain, typename YDomain, typename ZDomain,
1078 arithmetic TReal,
1079 invocable<vec<common_type<VReal, WReal>, 3>>... Preds>
1081 vectorfield<W, WReal, 3> const& wf,
1083 TReal const t, execution_policy_tag auto const policy,
1084 Preds&&... preds) {
1085 return detail::calc_parallel_vectors<common_type<VReal, WReal>>(
1086 // get vf data by evaluating V field
1087 [&vf, t](auto const /*ix*/, auto const /*iy*/, auto const /*iz*/,
1088 auto const& p) { return vf(p, t); },
1089 // get wf data by evaluating W field
1090 [&wf, t](auto const /*ix*/, auto const /*iy*/, auto const /*iz*/,
1091 auto const& p) { return wf(p, t); },
1092 g, policy, std::forward<Preds>(preds)...);
1093}
1094//------------------------------------------------------------------------------
1096template <typename V, typename W, typename VReal, typename WReal,
1097 typename XDomain, typename YDomain, typename ZDomain,
1098 arithmetic TReal,
1099 invocable<vec<common_type<VReal, WReal>, 3>>... Preds>
1101 vectorfield<W, WReal, 3> const& wf,
1103 TReal const t, Preds&&... preds) {
1104#if TATOOINE_PARALLEL_FOR_LOOPS_AVAILABLE
1105 return parallel_vectors(vf, wf, g, t, execution_policy::parallel,
1106 std::forward<Preds>(preds)...);
1107#else
1109 std::forward<Preds>(preds)...);
1110#endif
1111}
1112//------------------------------------------------------------------------------
1114template <typename V, typename W, typename VReal, typename WReal,
1115 typename XDomain, typename YDomain, typename ZDomain,
1116 invocable<vec<common_type<VReal, WReal>, 3>>... Preds>
1118 vectorfield<W, WReal, 3> const& wf,
1120 execution_policy_tag auto const policy,
1121 Preds&&... preds) {
1122 return parallel_vectors(vf, wf, g, 0, policy, std::forward<Preds>(preds)...);
1123}
1124//------------------------------------------------------------------------------
1126template <typename V, typename W, typename VReal, typename WReal,
1127 typename XDomain, typename YDomain, typename ZDomain,
1128 invocable<vec<common_type<VReal, WReal>, 3>>... Preds>
1130 vectorfield<W, WReal, 3> const& wf,
1132 Preds&&... preds) {
1133#if TATOOINE_PARALLEL_FOR_LOOPS_AVAILABLE
1135 std::forward<Preds>(preds)...);
1136#else
1138 std::forward<Preds>(preds)...);
1139#endif
1140}
1141//------------------------------------------------------------------------------
1143template <typename V, typename W, typename VReal, typename WReal,
1144 typename XReal, typename YReal, typename ZReal, arithmetic TReal,
1145 invocable<vec<common_type<VReal, WReal>, 3>>... Preds>
1147 vectorfield<W, WReal, 3> const& wf,
1148 linspace<XReal> const& x, linspace<YReal> const& y,
1149 linspace<ZReal> const& z, TReal const t,
1150 execution_policy_tag auto const policy,
1151 Preds&&... preds) {
1152 return parallel_vectors(vf, wf, rectilinear_grid{x, y, z}, t, policy,
1153 std::forward<Preds>(preds)...);
1154}
1155//------------------------------------------------------------------------------
1157template <typename V, typename W, typename VReal, typename WReal,
1158 typename XReal, typename YReal, typename ZReal, arithmetic TReal,
1159 invocable<vec<common_type<VReal, WReal>, 3>>... Preds>
1161 vectorfield<W, WReal, 3> const& wf,
1162 linspace<XReal> const& x, linspace<YReal> const& y,
1163 linspace<ZReal> const& z, TReal const t,
1164 Preds&&... preds) {
1165#if TATOOINE_PARALLEL_FOR_LOOPS_AVAILABLE
1166 return parallel_vectors(vf, wf, x, y, z, t, execution_policy::parallel,
1167 std::forward<Preds>(preds)...);
1168#else
1169 return parallel_vectors(vf, wf, x, y, z, t, execution_policy::sequential,
1170 std::forward<Preds>(preds)...);
1171#endif
1172}
1173//------------------------------------------------------------------------------
1175template <typename V, typename W, typename VReal, typename WReal,
1176 typename XReal, typename YReal, typename ZReal,
1177 invocable<vec<common_type<VReal, WReal>, 3>>... Preds>
1179 vectorfield<W, WReal, 3> const& wf,
1180 linspace<XReal> const& x, linspace<YReal> const& y,
1181 linspace<ZReal> const& z,
1182 execution_policy_tag auto const policy,
1183 Preds&&... preds) {
1184 return parallel_vectors(vf, wf, rectilinear_grid{x, y, z}, 0, policy,
1185 std::forward<Preds>(preds)...);
1186}
1187//------------------------------------------------------------------------------
1189template <typename V, typename W, typename VReal, typename WReal,
1190 typename XReal, typename YReal, typename ZReal,
1191 invocable<vec<common_type<VReal, WReal>, 3>>... Preds>
1193 vectorfield<W, WReal, 3> const& wf,
1194 linspace<XReal> const& x, linspace<YReal> const& y,
1195 linspace<ZReal> const& z, Preds&&... preds) {
1196#if TATOOINE_PARALLEL_FOR_LOOPS_AVAILABLE
1197 return parallel_vectors(vf, wf, x, y, z, execution_policy::parallel,
1198 std::forward<Preds>(preds)...);
1199#else
1200 return parallel_vectors(vf, wf, x, y, z, execution_policy::sequential,
1201 std::forward<Preds>(preds)...);
1202#endif
1203}
1204//------------------------------------------------------------------------------
1206template <typename VReal, typename VIndexing, typename WReal,
1207 typename WIndexing, typename AABBReal,
1208 invocable<vec<common_type<VReal, WReal>, 3>>... Preds>
1210 dynamic_multidim_array<vec<VReal, 3>, VIndexing> const& vf,
1211 dynamic_multidim_array<vec<WReal, 3>, WIndexing> const& wf,
1213 execution_policy_tag auto const policy, Preds&&... preds) {
1214 assert(vf.num_dimensions() == 3);
1215 assert(wf.num_dimensions() == 3);
1216 assert(vf.size(0) == wf.size(0));
1217 assert(vf.size(1) == wf.size(1));
1218 assert(vf.size(2) == wf.size(2));
1219
1220 return detail::calc_parallel_vectors<common_type<VReal, WReal>>(
1221 [&vf](auto ix, auto iy, auto iz, auto const& /*p*/) -> auto const& {
1222 return vf(ix, iy, iz);
1223 },
1224 [&wf](auto ix, auto iy, auto iz, auto const& /*p*/) -> auto const& {
1225 return wf(ix, iy, iz);
1226 },
1227 rectilinear_grid{linspace{bb.min(0), bb.max(0), vf.size(0)},
1228 linspace{bb.min(1), bb.max(1), vf.size(1)},
1229 linspace{bb.min(2), bb.max(2), vf.size(2)}},
1230 policy, std::forward<Preds>(preds)...);
1231}
1232//------------------------------------------------------------------------------
1234template <typename VReal, typename VIndexing, typename WReal,
1235 typename WIndexing, typename AABBReal,
1236 invocable<vec<common_type<VReal, WReal>, 3>>... Preds>
1238 dynamic_multidim_array<vec<VReal, 3>, VIndexing> const& vf,
1239 dynamic_multidim_array<vec<WReal, 3>, WIndexing> const& wf,
1240 axis_aligned_bounding_box<AABBReal, 3> const& bb, Preds&&... preds) {
1241#if TATOOINE_PARALLEL_FOR_LOOPS_AVAILABLE
1243 std::forward<Preds>(preds)...);
1244#else
1246 std::forward<Preds>(preds)...);
1247#endif
1248}
1250//==============================================================================
1251} // namespace tatooine
1252//==============================================================================
1253#endif
Definition: dynamic_multidim_array.h:18
Definition: rectilinear_grid.h:38
auto vertices() const
Definition: rectilinear_grid.h:637
constexpr auto size(std::index_sequence< Seq... >) const
Definition: rectilinear_grid.h:347
Definition: tags.h:72
Definition: concepts.h:21
Definition: concepts.h:121
auto parallel_vectors(polymorphic::vectorfield< VReal, 3 > const &vf, polymorphic::vectorfield< WReal, 3 > const &wf, rectilinear_grid< XDomain, YDomain, ZDomain > const &g, TReal const t, execution_policy_tag auto const policy, Preds &&... preds)
This is an implementation of .
Definition: parallel_vectors.h:1043
Definition: vtp_writer.h:3
auto constexpr turned(integral auto const ... is) -> bool
Definition: parallel_vectors.h:211
constexpr auto pv_on_tri(Vec3< Real > const &p0, Vec3< Real > const &v0, Vec3< Real > const &w0, Vec3< Real > const &p1, Vec3< Real > const &v1, Vec3< Real > const &w1, Vec3< Real > const &p2, Vec3< Real > const &v2, Vec3< Real > const &w2, Preds &&... preds) -> std::optional< Vec3< Real > >
Definition: parallel_vectors.h:103
auto check_unturned_cube(auto const &x_faces, auto const &y_faces, auto const &z_faces, auto const &inner_faces, auto &ls, auto const ix, auto const iy)
Definition: parallel_vectors.h:250
auto check_cube(auto const &x_faces, auto const &y_faces, auto const &z_faces, auto const &inner_faces, auto &ls, auto const ix, auto const iy, auto const iz)
Definition: parallel_vectors.h:285
auto calc_parallel_vectors(GetV &&getv, GetW &&getw, tatooine::rectilinear_grid< XDomain, YDomain, ZDomain > const &g, execution_policy::parallel_t const policy, Preds &&... preds) -> std::vector< Line3< Real > >
Definition: parallel_vectors.h:307
auto constexpr is_even(integral auto const i)
Definition: parallel_vectors.h:204
static auto check_tet(std::optional< Vec3< Real > > const &tri0, std::optional< Vec3< Real > > const &tri1, std::optional< Vec3< Real > > const &tri2, std::optional< Vec3< Real > > const &tri3, std::vector< Line3< Real > > &lines)
Definition: parallel_vectors.h:173
auto check_turned_cube(auto const &x_faces, auto const &y_faces, auto const &z_faces, auto const &inner_faces, auto &ls, auto const ix, auto const iy)
Definition: parallel_vectors.h:215
auto constexpr sign(bool pred) -> Int
Definition: parallel_vectors.h:207
static constexpr sequential_t sequential
Definition: tags.h:63
static constexpr parallel_t parallel
Definition: tags.h:60
Definition: algorithm.h:6
auto real(base_tensor< Tensor, std::complex< T >, Dims... > const &t)
Definition: complex_tensor_views.h:173
constexpr auto isnan(base_tensor< Tensor, Real, Dims... > const &t) -> bool
Definition: tensor_utility.h:25
auto solve(polynomial< Real, 1 > const &p) -> std::vector< Real >
solve a + b*x
Definition: polynomial.h:187
constexpr auto approx_equal(T0 const &lhs, T1 const &rhs, common_type< tatooine::value_type< T0 >, tatooine::value_type< T1 > > eps=1e-6)
for comparison
Definition: tensor_utility.h:11
auto merge(Lines const &unmerged_lines, Eps const eps=1e-13)
Merges a set of lines and combines lines with equal vertex endings.
Definition: merge.h:165
constexpr auto sum(base_tensor< Tensor, T, VecDim > const &v)
sum of all components of a vector
Definition: tensor_operations.h:110
auto imag(base_tensor< Tensor, std::complex< T >, Dims... > const &tensor)
Definition: complex_tensor_views.h:86
auto for_loop_num_parallel_threads()
Definition: for_loop.h:30
constexpr auto for_loop(Iteration &&iteration, execution_policy::sequential_t, Ranges(&&... ranges)[2]) -> void
Use this function for creating a sequential nested loop.
Definition: for_loop.h:336
constexpr auto det(base_tensor< Tensor, T, 2, 2 > const &A) -> T
Definition: determinant.h:7
auto eigenvectors(Mat &&B)
Definition: eigenvalues.h:123
Definition: axis_aligned_bounding_box.h:103
auto constexpr max() const -> auto const &
Definition: axis_aligned_bounding_box.h:156
auto constexpr min() const -> auto const &
Definition: axis_aligned_bounding_box.h:151
Definition: field.h:134
Definition: line.h:35
Definition: linspace.h:26
Definition: mat.h:14
auto constexpr col(std::size_t i)
Definition: mat.h:175
Definition: field.h:13
Definition: vec.h:12