DiFfRG
Loading...
Searching...
No Matches
EoM.hh
Go to the documentation of this file.
1#pragma once
2
3// external libraries
4#include <deal.II/base/point.h>
5#include <deal.II/dofs/dof_handler.h>
6#include <deal.II/grid/grid_tools.h>
7#include <deal.II/numerics/fe_field_function.h>
8#include <gsl/gsl_multiroots.h>
9#include <gsl/gsl_vector.h>
10#include <gsl/gsl_vector_double.h>
11#include <iostream>
12#include <sys/types.h>
13#include <tbb/parallel_for.h>
14
15// standard library
16#include <algorithm>
17#include <iterator>
18#include <mutex>
19
20namespace DiFfRG
21{
22 namespace internal
23 {
24 template <int dim> int gsl_unwrap(const gsl_vector *gsl_x, void *params, gsl_vector *gsl_f)
25 {
26 const int subdim = gsl_x->size;
27
28 dealii::Point<dim> x{};
29 for (int i = 0; i < subdim; ++i)
30 x[i] = gsl_vector_get(gsl_x, i);
31
32 auto fp = static_cast<std::function<std::array<double, dim>(const dealii::Point<dim> &)> *>(params);
33 const auto f = (*fp)(x);
34
35 for (int i = 0; i < subdim; ++i)
36 gsl_vector_set(gsl_f, i, f[i]);
37
38 return GSL_SUCCESS;
39 }
40
41 using namespace dealii;
42 template <int dim, typename Cell>
43 bool is_in_cell(const Cell &cell, const Point<dim> &point, const Mapping<dim> &mapping)
44 {
45 try {
46 Point<dim> qp = mapping.transform_real_to_unit_cell(cell, point);
47 if (GeometryInfo<dim>::is_inside_unit_cell(qp))
48 return true;
49 else
50 return false;
51 } catch (const typename Mapping<dim>::ExcTransformationFailed &) {
52 // transformation failed, so assume the point is outside
53 return false;
54 }
55 }
56
57 template <int dim>
58 dealii::Point<dim> get_origin(const dealii::DoFHandler<dim> &dof_handler,
59 typename dealii::DoFHandler<dim>::cell_iterator &EoM_cell)
60 {
61 using namespace dealii;
62 using CellIterator = typename dealii::DoFHandler<dim>::cell_iterator;
63
64 auto l1_norm = [](const Point<dim> &p) {
65 double norm = 0.;
66 for (uint d = 0; d < dim; ++d)
67 norm += std::abs(p[d]);
68 return norm;
69 };
70
71 std::vector<Point<dim>> candidates;
72
73 auto iterate_cell = [&](const CellIterator &cell) {
74 std::array<Point<dim>, GeometryInfo<dim>::vertices_per_cell> vertices;
75 for (uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i) {
76 vertices[i] = cell->vertex(i);
77 }
78 // choose the one with the smallest l1 norm
79 auto min_it = std::min_element(vertices.begin(), vertices.end(),
80 [&](const auto &p1, const auto &p2) { return l1_norm(p1) < l1_norm(p2); });
81 // add the point to the candidates
82 candidates.push_back(*min_it);
83 };
84
85 for (const auto &cell : dof_handler.active_cell_iterators())
86 iterate_cell(cell);
87
88 // find the candidate with the smallest l1 norm
89 auto min_it = std::min_element(candidates.begin(), candidates.end(),
90 [&](const auto &p1, const auto &p2) { return l1_norm(p1) < l1_norm(p2); });
91
92 Point<dim> origin = *min_it;
93 EoM_cell = GridTools::find_active_cell_around_point(dof_handler, origin);
94
95 return origin;
96 }
97
98 } // namespace internal
99
117 template <typename VectorType, typename EoMFUN, typename EoMPFUN>
118 dealii::Point<1> get_EoM_point_1D(
119 typename dealii::DoFHandler<1>::cell_iterator &EoM_cell, const VectorType &sol,
120 const dealii::DoFHandler<1> &dof_handler, const dealii::Mapping<1> &mapping, const EoMFUN &get_EoM,
121 const EoMPFUN &EoM_postprocess = [](const auto &p, const auto &values) { return p; },
122 const double EoM_abs_tol = 1e-8, const uint max_iter = 100)
123 {
124 constexpr uint dim = 1;
125
126 using namespace dealii;
127 using CellIterator = typename dealii::DoFHandler<dim>::cell_iterator;
128 using EoMType = std::array<double, dim>;
129
130 auto EoM = Point<dim>();
131 Vector<typename VectorType::value_type> values(dof_handler.get_fe().n_components());
132 Functions::FEFieldFunction<dim, VectorType> fe_function(dof_handler, sol, mapping);
133
134 // We start by investigating the origin.
135 const auto origin = internal::get_origin(dof_handler, EoM_cell);
136 fe_function.set_active_cell(EoM_cell);
137 fe_function.vector_value(origin, values);
138 const auto origin_val = get_EoM(origin, values);
139
140 const auto secondary_point = (origin + EoM_cell->center()) / 2.;
141 fe_function.vector_value(secondary_point, values);
142 const auto secondary_val = get_EoM(secondary_point, values);
143
144 bool origin_EoM = true;
145 bool secondary_EoM = true;
146 for (uint d = 0; d < dim; ++d) {
147 origin_EoM = origin_EoM && (origin_val[d] > EoM_abs_tol);
148 secondary_EoM = secondary_EoM && (secondary_val[d] > 0);
149 }
150
151 if (origin_EoM && secondary_EoM) {
152 EoM = origin;
153 return EoM;
154 }
155
156 auto check_cell = [&](const CellIterator &cell) {
157 // Obtain the values at the vertices of the cell.
158 std::array<double, GeometryInfo<dim>::vertices_per_cell> EoM_vals;
159 std::array<Point<dim>, GeometryInfo<dim>::vertices_per_cell> vertices;
160 // Vector<typename VectorType::value_type> values(dof_handler.get_fe().n_components());
161 // Functions::FEFieldFunction<dim, VectorType> fe_function(dof_handler, sol, mapping);
162
163 fe_function.set_active_cell(cell);
164 for (uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i) {
165 vertices[i] = cell->vertex(i);
166 fe_function.vector_value(vertices[i], values);
167 EoM_vals[i] = get_EoM(vertices[i], values)[0];
168 }
169
170 bool cell_has_EoM = false;
171 // Find if the cell has an EoM point, i.e. if the values at some vertices have different signs.
172 for (uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
173 for (uint j = 0; j < i; ++j)
174 if (EoM_vals[i] * EoM_vals[j] < 0.) {
175 cell_has_EoM = true;
176 i = GeometryInfo<dim>::vertices_per_cell;
177 break;
178 }
179
180 return cell_has_EoM;
181 };
182
183 auto find_EoM = [&](const CellIterator &cell, CellIterator &m_EoM_cell, Point<dim> &m_EoM,
184 double &EoM_val) -> bool {
185 std::array<Point<dim>, GeometryInfo<dim>::vertices_per_cell> vertices;
186 for (uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
187 vertices[i] = cell->vertex(i);
188 fe_function.set_active_cell(cell);
189
190 auto p1 = vertices[0];
191 auto p2 = vertices[1];
192 if (p2[0] < p1[0]) std::swap(p1, p2);
193 auto p = m_EoM[0] <= p2[0] && m_EoM[0] >= p1[0] ? m_EoM : (p1 + p2) / 2.;
194
195 fe_function.vector_value(p, values);
196 EoM_val = get_EoM(p, values)[0];
197 double err = 1e100;
198 uint iter = 0;
199
200 while (err > EoM_abs_tol) {
201 if (EoM_val < 0.)
202 p1 = p;
203 else
204 p2 = p;
205 p = (p1 + p2) / 2.;
206
207 fe_function.vector_value(p, values);
208 EoM_val = get_EoM(p, values)[0];
209 err = std::abs(EoM_val);
210
211 if (iter > max_iter) {
212 m_EoM = EoM_postprocess(p, values);
213 m_EoM_cell = cell;
214 return false;
215 }
216 iter++;
217 }
218
219 m_EoM = EoM_postprocess(p, values);
220 m_EoM_cell = cell;
221
222 return true;
223 };
224
225 std::vector<typename dealii::DoFHandler<dim>::cell_iterator> cell_candidates;
226 std::vector<double> value_candidates;
227 std::vector<Point<dim>> EoM_candidates;
228
229 CellIterator t_EoM_cell;
230 Point<dim> t_EoM;
231 double t_EoM_value = 0.;
232
233 // Check the cell from the previous iteration first
234 if (EoM_cell != dof_handler.active_cell_iterators().end())
235 if (check_cell(EoM_cell)) {
236 if (find_EoM(EoM_cell, t_EoM_cell, t_EoM, t_EoM_value)) {
237 EoM_cell = t_EoM_cell;
238 EoM = t_EoM;
239 return EoM;
240 }
241 cell_candidates.push_back(t_EoM_cell);
242 value_candidates.push_back(std::abs(t_EoM_value));
243 EoM_candidates.push_back(t_EoM);
244 }
245
246 for (const auto &cell : dof_handler.active_cell_iterators())
247 if (check_cell(cell)) {
248 if (find_EoM(cell, t_EoM_cell, t_EoM, t_EoM_value)) {
249 EoM_cell = t_EoM_cell;
250 EoM = t_EoM;
251 return EoM;
252 }
253 cell_candidates.push_back(t_EoM_cell);
254 value_candidates.push_back(std::abs(t_EoM_value));
255 EoM_candidates.push_back(t_EoM);
256 }
257
258 if (cell_candidates.size() == 1) {
259 EoM_cell = cell_candidates[0];
260 EoM = EoM_candidates[0];
261 return EoM;
262 } else if (cell_candidates.size() == 0) {
263 EoM_cell = GridTools::find_active_cell_around_point(dof_handler, origin);
264 return origin;
265 } else if (cell_candidates.size() > 1) {
266 // If we have more than one candidate, we choose the one with the smallest EoM value.
267 auto min_it = std::min_element(value_candidates.begin(), value_candidates.end());
268 auto min_idx = std::distance(value_candidates.begin(), min_it);
269 EoM_cell = cell_candidates[min_idx];
270 EoM = EoM_candidates[min_idx];
271 return EoM;
272 }
273
274 find_EoM(cell_candidates[0], EoM_cell, EoM, t_EoM_value);
275
276 return EoM;
277 }
278
296 template <int dim, typename VectorType, typename EoMFUN, typename EoMPFUN>
297 dealii::Point<dim> get_EoM_point_ND(
298 typename dealii::DoFHandler<dim>::cell_iterator &EoM_cell, const VectorType &sol,
299 const dealii::DoFHandler<dim> &dof_handler, const dealii::Mapping<dim> &mapping, const EoMFUN &get_EoM,
300 const EoMPFUN &EoM_postprocess = [](const auto &p, const auto &values) { return p; },
301 const double EoM_abs_tol = 1e-8, const uint max_iter = 100)
302 {
303 using namespace dealii;
304 using CellIterator = typename dealii::DoFHandler<dim>::cell_iterator;
305 using EoMType = std::array<double, dim>;
306
307 Vector<typename VectorType::value_type> values(dof_handler.get_fe().n_components());
308 Functions::FEFieldFunction<dim, VectorType> fe_function(dof_handler, sol, mapping);
309
310 // We start by investigating the origin.
311 const auto origin = internal::get_origin(dof_handler, EoM_cell);
312 fe_function.set_active_cell(EoM_cell);
313 fe_function.vector_value(origin, values);
314 const auto origin_val = get_EoM(origin, values);
315
316 const auto secondary_point = (origin + EoM_cell->center()) / 2.;
317 fe_function.vector_value(secondary_point, values);
318 const auto secondary_val = get_EoM(secondary_point, values);
319
320 // this actually constrains the EoM to one axis, possibly.
321 // in a future version, we should exploit this to reduce the dimensionality of the problem.
322 std::array<bool, dim> axis_restrictions{{}};
323 for (uint d = 0; d < dim; ++d)
324 axis_restrictions[d] = (origin_val[d] >= 0) && (secondary_val[d] >= 0);
325
326 const bool any_axis_restricted =
327 std::any_of(std::begin(axis_restrictions), std::end(axis_restrictions), [](bool i) { return i; });
328 const bool all_axis_restricted =
329 std::all_of(std::begin(axis_restrictions), std::end(axis_restrictions), [](bool i) { return i; });
330
331 auto EoM = origin;
332 EoM_cell = GridTools::find_active_cell_around_point(dof_handler, EoM);
333 if (all_axis_restricted) {
334 EoM = origin;
335 // std::cout << "All axis restricted" << std::endl;
336 return EoM;
337 }
338
339 // std::cout << "Restrictions: ";
340 // for (uint d = 0; d < dim; ++d)
341 // std::cout << axis_restrictions[d] << " ";
342 // std::cout << std::endl;
343
344 auto check_cell = [&](const CellIterator &cell) -> bool {
345 if (any_axis_restricted && !cell->has_boundary_lines()) return false;
346
347 // Obtain the values at the vertices of the cell.
348 std::array<EoMType, GeometryInfo<dim>::vertices_per_cell> EoM_vals;
349 std::array<Point<dim>, GeometryInfo<dim>::vertices_per_cell> vertices;
350 Vector<typename VectorType::value_type> values(dof_handler.get_fe().n_components());
351 Functions::FEFieldFunction<dim, VectorType> fe_function(dof_handler, sol, mapping);
352
353 fe_function.set_active_cell(cell);
354 for (uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i) {
355 vertices[i] = cell->vertex(i);
356 fe_function.vector_value(vertices[i], values);
357 EoM_vals[i] = get_EoM(vertices[i], values);
358 }
359
360 if (any_axis_restricted)
361 for (uint d = 0; d < dim; ++d)
362 if (axis_restrictions[d]) {
363 bool has_zero_boundary = false;
364 for (uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
365 if (is_close(origin[d], vertices[i][d], 1e-12)) {
366 has_zero_boundary = true;
367 break;
368 }
369 if (!has_zero_boundary) {
370 // std::cout << "No zero boundary for cell with vertices: ";
371 // for (uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i) {
372 // std::cout << "vertex " << i << ": ";
373 // for (uint d = 0; d < dim; ++d)
374 // std::cout << vertices[i][d] << " ";
375 // std::cout << std::endl;
376 // }
377
378 return false;
379 }
380 }
381
382 std::array<bool, dim> cell_has_EoM{{}};
383 // Find if the cell has an EoM point, i.e. if the values at some vertices have different signs.
384 if (!any_axis_restricted) {
385 for (uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
386 for (uint j = 0; j < i; ++j)
387 for (uint d = 0; d < dim; ++d)
388 cell_has_EoM[d] = cell_has_EoM[d] || (EoM_vals[i][d] * EoM_vals[j][d] < 0.);
389 } else {
390 std::vector<bool> valid_vertices(GeometryInfo<dim>::vertices_per_cell, true);
391
392 for (uint d = 0; d < dim; ++d)
393 if (axis_restrictions[d])
394 for (uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
395 // if there is a vertex with smaller coordinate in direction d, we set the vertex to invalid
396 for (uint j = 0; j < i; ++j) {
397 if (vertices[i][d] > vertices[j][d]) {
398 valid_vertices[i] = false;
399 break;
400 }
401 }
402
403 for (uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
404 if (valid_vertices[i])
405 for (uint j = 0; j < i; ++j)
406 if (valid_vertices[j])
407 for (uint d = 0; d < dim; ++d)
408 cell_has_EoM[d] = cell_has_EoM[d] || (EoM_vals[i][d] * EoM_vals[j][d] < 0.);
409 }
410
411 bool has_EoM = true;
412 for (uint d = 0; d < dim; ++d)
413 if (!axis_restrictions[d]) has_EoM = has_EoM && cell_has_EoM[d];
414 // if all components have a potential crossing, we return true
415 return has_EoM;
416 };
417
418 gsl_set_error_handler_off();
419
420 auto find_EoM = [&](const CellIterator &cell, CellIterator &m_EoM_cell, Point<dim> &m_EoM,
421 double &EoM_val) -> bool {
422 Functions::FEFieldFunction<dim, VectorType> fe_function(dof_handler, sol, mapping);
423 Vector<typename VectorType::value_type> values(dof_handler.get_fe().n_components());
424 fe_function.set_active_cell(cell);
425
426 // find the cell boundaries
427 std::array<std::array<double, 2>, dim> cell_boundaries{{}};
428 for (uint d = 0; d < dim; ++d) {
429 cell_boundaries[d][0] = cell->center()[d];
430 cell_boundaries[d][1] = cell->center()[d];
431 }
432 for (uint d = 0; d < dim; ++d) {
433 for (uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i) {
434 cell_boundaries[d][0] = std::min(cell_boundaries[d][0], cell->vertex(i)[d]);
435 cell_boundaries[d][1] = std::max(cell_boundaries[d][1], cell->vertex(i)[d]);
436 }
437 }
438
439 int subdim = dim;
440 for (uint d = 0; d < dim; ++d)
441 if (axis_restrictions[d]) subdim--;
442
443 if (subdim == 1) {
444 uint dir = 0;
445 for (uint d = 0; d < dim; ++d)
446 if (!axis_restrictions[d]) dir = d;
447
448 // utlize the fact that we have a 1D problem and we can just do a bisection
449 Point<dim> p1{};
450 Point<dim> p2{};
451 for (uint d = 0; d < dim; ++d) {
452 p1[d] = cell_boundaries[d][0];
453 p2[d] = cell_boundaries[d][0];
454 }
455 p2[dir] = cell_boundaries[dir][1];
456 auto p = (p1 + p2) / 2.;
457
458 fe_function.vector_value(p, values);
459 EoM_val = get_EoM(p, values)[dir];
460 double err = 1e100;
461 uint iter = 0;
462
463 while (err > EoM_abs_tol) {
464 if (EoM_val < 0.)
465 p1 = p;
466 else
467 p2 = p;
468 p = (p1 + p2) / 2.;
469
470 fe_function.vector_value(p, values);
471 EoM_val = get_EoM(p, values)[dir];
472 err = std::abs(EoM_val);
473
474 if (iter > max_iter) {
475 m_EoM = EoM_postprocess(p, values);
476 m_EoM_cell = cell;
477 return false;
478 }
479 iter++;
480 }
481
482 m_EoM = EoM_postprocess(p, values);
483 m_EoM_cell = cell;
484
485 return true;
486 }
487
488 std::function<std::array<double, dim>(const dealii::Point<dim> &)> eval_on_point =
489 [&](const Point<dim> &p) -> std::array<double, dim> {
490 Point<dim> p_proj = p;
491 for (uint d = 0, i = 0; d < dim; ++d)
492 p_proj[d] = axis_restrictions[d] ? origin[d] : p[i++];
493
494 // check if the point is inside the cell
495 std::array<double, dim> out_distance{{}};
496 for (uint d = 0; d < dim; ++d) {
497 if (p_proj[d] < cell_boundaries[d][0]) {
498 out_distance[d] = std::abs(p_proj[d] - cell_boundaries[d][0]);
499 p_proj[d] = cell_boundaries[d][0];
500 // std::cout << "Point outside cell" << std::endl;
501 // std::cout << "Point: " << p << std::endl;
502 } else if (p_proj[d] > cell_boundaries[d][1]) {
503 out_distance[d] = std::abs(p_proj[d] - cell_boundaries[d][1]);
504 p_proj[d] = cell_boundaries[d][1];
505 // std::cout << "Point outside cell" << std::endl;
506 // std::cout << "Point: " << p << std::endl;
507 }
508 }
509
510 try {
511 fe_function.vector_value(p_proj, values);
512 } catch (...) {
513 // if p is outside the triangulation, give a default value
514 return std::array<double, dim>{{
515 std::numeric_limits<double>::quiet_NaN(),
516 }};
517 }
518
519 auto EoM = get_EoM(p, values);
520
521 // if (out_distance[d] > 0), linearly extrapolate the value
522 for (uint d = 0; d < dim; ++d)
523 if (out_distance[d] > 0) {
524 // std::cout << "Extrapolating value from " << EoM[d];
525 EoM[d] = is_close(EoM[d], 0.) ? out_distance[d] : EoM[d] * (1 + out_distance[d]);
526 // std::cout << " to " << EoM[d] << std::endl;
527 }
528
529 // reshuflle the values to the correct order
530 std::array<double, dim> EoM_out{{}};
531 for (uint d = 0, i = 0; d < dim; ++d)
532 if (!axis_restrictions[d]) EoM_out[d] = EoM[i++];
533
534 return EoM_out;
535 };
536
537 const auto cell_center = cell->center();
538 std::vector<double> subdim_center(subdim);
539 for (uint d = 0, i = 0; d < dim; ++d)
540 if (!axis_restrictions[d]) subdim_center[i++] = cell_center[d];
541
542 // Create GSL multiroot solver
543 const gsl_multiroot_fsolver_type *T = gsl_multiroot_fsolver_hybrids;
544 gsl_multiroot_fsolver *s = gsl_multiroot_fsolver_alloc(T, subdim);
545
546 // Create GSL function
547 gsl_multiroot_function f = {&internal::gsl_unwrap<dim>, (size_t)subdim, &eval_on_point};
548
549 // Create initial guess
550 gsl_vector *x = gsl_vector_alloc(subdim);
551 for (int d = 0; d < subdim; ++d)
552 gsl_vector_set(x, d, subdim_center[d]);
553
554 // Set the solver with the function and initial guess
555 gsl_multiroot_fsolver_set(s, &f, x);
556
557 // start the iteration
558 uint iter = 0;
559 int status;
560 do {
561 iter++;
562 status = gsl_multiroot_fsolver_iterate(s);
563
564 if (status) break;
565
566 status = gsl_multiroot_test_residual(s->f, EoM_abs_tol);
567
568 } while (status == GSL_CONTINUE && iter < max_iter);
569
570 EoM_val = 0.;
571 for (uint d = 0, sd = 0; d < dim; ++d)
572 m_EoM[d] = axis_restrictions[d] ? origin[d] : gsl_vector_get(s->x, sd++);
573
574 // don't leak memory. Stupid C
575 gsl_multiroot_fsolver_free(s);
576 gsl_vector_free(x);
577
578 if (status != GSL_SUCCESS) return false;
579
580 m_EoM = EoM_postprocess(m_EoM, values);
581 m_EoM_cell = internal::is_in_cell(cell, m_EoM, mapping)
582 ? cell
583 : GridTools::find_active_cell_around_point(dof_handler, m_EoM);
584
585 return true;
586 };
587
588 std::vector<typename dealii::DoFHandler<dim>::cell_iterator> cell_candidates;
589 std::vector<double> value_candidates;
590 std::vector<Point<dim>> EoM_candidates;
591
592 // mutex for the EoM cell
593 // std::mutex EoM_cell_mutex;
594
595 const uint n_active_cells = dof_handler.get_triangulation().n_active_cells();
596
597 // this needs to be done smarter, but for now we just iterate over all cells
598 // preferrably, we would divide the full domain into smaller subdomains and then traverse a kind of tree.
599 for (uint index = 0; index < n_active_cells; ++index) {
600 auto cell = dof_handler.begin_active();
601 std::advance(cell, index);
602 if (check_cell(cell)) {
603 Point<dim> t_EoM = cell->center();
604 CellIterator t_EoM_cell = cell;
605 double t_EoM_value = 0.;
606
607 // lock the mutex
608 // std::lock_guard<std::mutex> lock(EoM_cell_mutex);
609
610 if (find_EoM(cell, t_EoM_cell, t_EoM, t_EoM_value)) {
611 // std::cout << "Found EoM point in cell " << index << std::endl;
612 // std::cout << "EoM: " << t_EoM << std::endl;
613 EoM = t_EoM;
614 EoM_cell = dealii::GridTools::find_active_cell_around_point(dof_handler, EoM);
615 return EoM;
616 }
617
618 cell_candidates.push_back(t_EoM_cell);
619 EoM_candidates.push_back(t_EoM);
620 value_candidates.push_back(std::abs(t_EoM_value));
621 }
622 }
623
624 // std::cout << "Found " << cell_candidates.size() << " candidates." << std::endl;
625
626 double EoM_value = 0.;
627
628 if (cell_candidates.size() == 1) {
629 if (find_EoM(cell_candidates[0], EoM_cell, EoM, EoM_value)) return EoM;
630 } else if (cell_candidates.size() == 0) {
631 EoM_cell = GridTools::find_active_cell_around_point(dof_handler, origin);
632 return origin;
633 } else if (cell_candidates.size() > 1) {
634 // If we have more than one candidate, we choose the one with the smallest EoM value.
635 auto min_it = std::min_element(value_candidates.begin(), value_candidates.end());
636 auto min_idx = std::distance(value_candidates.begin(), min_it);
637 EoM_cell = cell_candidates[min_idx];
638 EoM = EoM_candidates[min_idx];
639 return EoM;
640 }
641
642 return EoM;
643 }
644
661 template <int dim, typename VectorType, typename EoMFUN, typename EoMPFUN>
662 dealii::Point<dim> get_EoM_point(
663 typename dealii::DoFHandler<dim>::cell_iterator &EoM_cell, const VectorType &sol,
664 const dealii::DoFHandler<dim> &dof_handler, const dealii::Mapping<dim> &mapping, const EoMFUN &get_EoM,
665 const EoMPFUN &EoM_postprocess = [](const auto &p, const auto &values) { return p; },
666 const double EoM_abs_tol = 1e-5, const uint max_iter = 100)
667 {
668 if (max_iter == 0) return internal::get_origin(dof_handler, EoM_cell);
669
670 if constexpr (dim == 1) {
671 return get_EoM_point_1D(EoM_cell, sol, dof_handler, mapping, get_EoM, EoM_postprocess, EoM_abs_tol, max_iter);
672 } else if constexpr (dim > 1) {
673 return get_EoM_point_ND(EoM_cell, sol, dof_handler, mapping, get_EoM, EoM_postprocess, EoM_abs_tol, max_iter);
674 } else
675 throw std::runtime_error("get_EoM_point is not yet implemented for dim > 1. Please set EoM_max_iter = 0.");
676 }
677} // namespace DiFfRG
dealii::Point< dim > get_origin(const dealii::DoFHandler< dim > &dof_handler, typename dealii::DoFHandler< dim >::cell_iterator &EoM_cell)
Definition EoM.hh:58
int gsl_unwrap(const gsl_vector *gsl_x, void *params, gsl_vector *gsl_f)
Definition EoM.hh:24
bool is_in_cell(const Cell &cell, const Point< dim > &point, const Mapping< dim > &mapping)
Definition EoM.hh:43
Definition complex_math.hh:14
dealii::Point< 1 > get_EoM_point_1D(typename dealii::DoFHandler< 1 >::cell_iterator &EoM_cell, const VectorType &sol, const dealii::DoFHandler< 1 > &dof_handler, const dealii::Mapping< 1 > &mapping, const EoMFUN &get_EoM, const EoMPFUN &EoM_postprocess=[](const auto &p, const auto &values) { return p;}, const double EoM_abs_tol=1e-8, const uint max_iter=100)
Get the EoM point for a given solution and model in 1D. This is done by first checking the origin,...
Definition EoM.hh:118
dealii::Point< dim > get_EoM_point(typename dealii::DoFHandler< dim >::cell_iterator &EoM_cell, const VectorType &sol, const dealii::DoFHandler< dim > &dof_handler, const dealii::Mapping< dim > &mapping, const EoMFUN &get_EoM, const EoMPFUN &EoM_postprocess=[](const auto &p, const auto &values) { return p;}, const double EoM_abs_tol=1e-5, const uint max_iter=100)
Get the EoM point for a given solution and model.
Definition EoM.hh:662
bool __forceinline__ __host__ __device__ is_close(T1 a, T2 b, T3 eps_)
Function to evaluate whether two floats are equal to numerical precision. Tests for both relative and...
Definition math.hh:160
unsigned int uint
Definition utils.hh:22
dealii::Point< dim > get_EoM_point_ND(typename dealii::DoFHandler< dim >::cell_iterator &EoM_cell, const VectorType &sol, const dealii::DoFHandler< dim > &dof_handler, const dealii::Mapping< dim > &mapping, const EoMFUN &get_EoM, const EoMPFUN &EoM_postprocess=[](const auto &p, const auto &values) { return p;}, const double EoM_abs_tol=1e-8, const uint max_iter=100)
Get the EoM point for a given solution and model in 2D. This is done by first checking the origin,...
Definition EoM.hh:297