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)
124 constexpr uint dim = 1;
126 using namespace dealii;
127 using CellIterator =
typename dealii::DoFHandler<dim>::cell_iterator;
128 using EoMType = std::array<double, dim>;
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);
136 fe_function.set_active_cell(EoM_cell);
137 fe_function.vector_value(origin, values);
138 const auto origin_val = get_EoM(origin, values);
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);
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);
151 if (origin_EoM && secondary_EoM) {
156 auto check_cell = [&](
const CellIterator &cell) {
158 std::array<double, GeometryInfo<dim>::vertices_per_cell> EoM_vals;
159 std::array<Point<dim>, GeometryInfo<dim>::vertices_per_cell> vertices;
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];
170 bool cell_has_EoM =
false;
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.) {
176 i = GeometryInfo<dim>::vertices_per_cell;
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);
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.;
195 fe_function.vector_value(p, values);
196 EoM_val = get_EoM(p, values)[0];
200 while (err > EoM_abs_tol) {
207 fe_function.vector_value(p, values);
208 EoM_val = get_EoM(p, values)[0];
209 err = std::abs(EoM_val);
211 if (iter > max_iter) {
212 m_EoM = EoM_postprocess(p, values);
219 m_EoM = EoM_postprocess(p, values);
225 std::vector<typename dealii::DoFHandler<dim>::cell_iterator> cell_candidates;
226 std::vector<double> value_candidates;
227 std::vector<Point<dim>> EoM_candidates;
229 CellIterator t_EoM_cell;
231 double t_EoM_value = 0.;
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;
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);
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;
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);
258 if (cell_candidates.size() == 1) {
259 EoM_cell = cell_candidates[0];
260 EoM = EoM_candidates[0];
262 }
else if (cell_candidates.size() == 0) {
263 EoM_cell = GridTools::find_active_cell_around_point(dof_handler, origin);
265 }
else if (cell_candidates.size() > 1) {
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];
274 find_EoM(cell_candidates[0], EoM_cell, EoM, t_EoM_value);
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)
303 using namespace dealii;
304 using CellIterator =
typename dealii::DoFHandler<dim>::cell_iterator;
305 using EoMType = std::array<double, dim>;
307 Vector<typename VectorType::value_type> values(dof_handler.get_fe().n_components());
308 Functions::FEFieldFunction<dim, VectorType> fe_function(dof_handler, sol, mapping);
312 fe_function.set_active_cell(EoM_cell);
313 fe_function.vector_value(origin, values);
314 const auto origin_val = get_EoM(origin, values);
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);
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);
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; });
332 EoM_cell = GridTools::find_active_cell_around_point(dof_handler, EoM);
333 if (all_axis_restricted) {
344 auto check_cell = [&](
const CellIterator &cell) ->
bool {
345 if (any_axis_restricted && !cell->has_boundary_lines())
return false;
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);
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);
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;
369 if (!has_zero_boundary) {
382 std::array<bool, dim> cell_has_EoM{{}};
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.);
390 std::vector<bool> valid_vertices(GeometryInfo<dim>::vertices_per_cell,
true);
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)
396 for (
uint j = 0; j < i; ++j) {
397 if (vertices[i][d] > vertices[j][d]) {
398 valid_vertices[i] =
false;
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.);
412 for (
uint d = 0; d < dim; ++d)
413 if (!axis_restrictions[d]) has_EoM = has_EoM && cell_has_EoM[d];
418 gsl_set_error_handler_off();
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);
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];
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]);
440 for (
uint d = 0; d < dim; ++d)
441 if (axis_restrictions[d]) subdim--;
445 for (
uint d = 0; d < dim; ++d)
446 if (!axis_restrictions[d]) dir = d;
451 for (
uint d = 0; d < dim; ++d) {
452 p1[d] = cell_boundaries[d][0];
453 p2[d] = cell_boundaries[d][0];
455 p2[dir] = cell_boundaries[dir][1];
456 auto p = (p1 + p2) / 2.;
458 fe_function.vector_value(p, values);
459 EoM_val = get_EoM(p, values)[dir];
463 while (err > EoM_abs_tol) {
470 fe_function.vector_value(p, values);
471 EoM_val = get_EoM(p, values)[dir];
472 err = std::abs(EoM_val);
474 if (iter > max_iter) {
475 m_EoM = EoM_postprocess(p, values);
482 m_EoM = EoM_postprocess(p, values);
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++];
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];
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];
511 fe_function.vector_value(p_proj, values);
514 return std::array<double, dim>{{
515 std::numeric_limits<double>::quiet_NaN(),
519 auto EoM = get_EoM(p, values);
522 for (
uint d = 0; d < dim; ++d)
523 if (out_distance[d] > 0) {
525 EoM[d] =
is_close(EoM[d], 0.) ? out_distance[d] : EoM[d] * (1 + out_distance[d]);
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++];
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];
543 const gsl_multiroot_fsolver_type *T = gsl_multiroot_fsolver_hybrids;
544 gsl_multiroot_fsolver *s = gsl_multiroot_fsolver_alloc(T, subdim);
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]);
555 gsl_multiroot_fsolver_set(s, &f, x);
562 status = gsl_multiroot_fsolver_iterate(s);
566 status = gsl_multiroot_test_residual(s->f, EoM_abs_tol);
568 }
while (status == GSL_CONTINUE && iter < max_iter);
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++);
575 gsl_multiroot_fsolver_free(s);
578 if (status != GSL_SUCCESS)
return false;
580 m_EoM = EoM_postprocess(m_EoM, values);
583 : GridTools::find_active_cell_around_point(dof_handler, m_EoM);
588 std::vector<typename dealii::DoFHandler<dim>::cell_iterator> cell_candidates;
589 std::vector<double> value_candidates;
590 std::vector<Point<dim>> EoM_candidates;
595 const uint n_active_cells = dof_handler.get_triangulation().n_active_cells();
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.;
610 if (find_EoM(cell, t_EoM_cell, t_EoM, t_EoM_value)) {
614 EoM_cell = dealii::GridTools::find_active_cell_around_point(dof_handler, EoM);
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));
626 double EoM_value = 0.;
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);
633 }
else if (cell_candidates.size() > 1) {
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];