116 typename dealii::DoFHandler<1>::cell_iterator &EoM_cell,
const VectorType &sol,
117 const dealii::DoFHandler<1> &dof_handler,
const dealii::Mapping<1> &mapping,
const EoMFUN &get_EoM,
118 const EoMPFUN &EoM_postprocess = [](
const auto &p,
const auto &values) {
return p; },
119 const double EoM_abs_tol = 1e-8,
const uint max_iter = 100)
121 constexpr uint dim = 1;
123 using namespace dealii;
124 using CellIterator =
typename dealii::DoFHandler<dim>::cell_iterator;
125 using EoMType = std::array<double, dim>;
127 auto EoM = Point<dim>();
128 Vector<typename VectorType::value_type> values(dof_handler.get_fe().n_components());
129 Functions::FEFieldFunction<dim, VectorType> fe_function(dof_handler, sol, mapping);
133 fe_function.set_active_cell(EoM_cell);
134 fe_function.vector_value(origin, values);
135 const auto origin_val = get_EoM(origin, values);
137 const auto secondary_point = (origin + EoM_cell->center()) / 2.;
138 fe_function.vector_value(secondary_point, values);
139 const auto secondary_val = get_EoM(secondary_point, values);
141 bool origin_EoM =
true;
142 bool secondary_EoM =
true;
143 for (
uint d = 0; d < dim; ++d) {
144 origin_EoM = origin_EoM && (origin_val[d] > EoM_abs_tol);
145 secondary_EoM = secondary_EoM && (secondary_val[d] > 0);
148 if (origin_EoM && secondary_EoM) {
153 auto check_cell = [&](
const CellIterator &cell) {
155 std::array<double, GeometryInfo<dim>::vertices_per_cell> EoM_vals;
156 std::array<Point<dim>, GeometryInfo<dim>::vertices_per_cell> vertices;
160 fe_function.set_active_cell(cell);
161 for (
uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i) {
162 vertices[i] = cell->vertex(i);
163 fe_function.vector_value(vertices[i], values);
164 EoM_vals[i] = get_EoM(vertices[i], values)[0];
167 bool cell_has_EoM =
false;
169 for (
uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
170 for (
uint j = 0; j < i; ++j)
171 if (EoM_vals[i] * EoM_vals[j] < 0.) {
173 i = GeometryInfo<dim>::vertices_per_cell;
180 auto find_EoM = [&](
const CellIterator &cell, CellIterator &m_EoM_cell, Point<dim> &m_EoM,
181 double &EoM_val) ->
bool {
182 std::array<Point<dim>, GeometryInfo<dim>::vertices_per_cell> vertices;
183 for (
uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
184 vertices[i] = cell->vertex(i);
185 fe_function.set_active_cell(cell);
187 auto p1 = vertices[0];
188 auto p2 = vertices[1];
189 if (p2[0] < p1[0]) std::swap(p1, p2);
190 auto p = m_EoM[0] <= p2[0] && m_EoM[0] >= p1[0] ? m_EoM : (p1 + p2) / 2.;
192 fe_function.vector_value(p, values);
193 EoM_val = get_EoM(p, values)[0];
197 while (err > EoM_abs_tol) {
204 fe_function.vector_value(p, values);
205 EoM_val = get_EoM(p, values)[0];
206 err = std::abs(EoM_val);
208 if (iter > max_iter) {
209 m_EoM = EoM_postprocess(p, values);
216 m_EoM = EoM_postprocess(p, values);
222 std::vector<typename dealii::DoFHandler<dim>::cell_iterator> cell_candidates;
223 std::vector<double> value_candidates;
224 std::vector<Point<dim>> EoM_candidates;
226 CellIterator t_EoM_cell;
228 double t_EoM_value = 0.;
231 if (EoM_cell != dof_handler.active_cell_iterators().end())
232 if (check_cell(EoM_cell)) {
233 if (find_EoM(EoM_cell, t_EoM_cell, t_EoM, t_EoM_value)) {
234 EoM_cell = t_EoM_cell;
238 cell_candidates.push_back(t_EoM_cell);
239 value_candidates.push_back(std::abs(t_EoM_value));
240 EoM_candidates.push_back(t_EoM);
243 for (
const auto &cell : dof_handler.active_cell_iterators())
244 if (check_cell(cell)) {
245 if (find_EoM(cell, t_EoM_cell, t_EoM, t_EoM_value)) {
246 EoM_cell = t_EoM_cell;
250 cell_candidates.push_back(t_EoM_cell);
251 value_candidates.push_back(std::abs(t_EoM_value));
252 EoM_candidates.push_back(t_EoM);
255 if (cell_candidates.size() == 1) {
256 EoM_cell = cell_candidates[0];
257 EoM = EoM_candidates[0];
259 }
else if (cell_candidates.size() == 0) {
260 EoM_cell = GridTools::find_active_cell_around_point(dof_handler, origin);
262 }
else if (cell_candidates.size() > 1) {
264 auto min_it = std::min_element(value_candidates.begin(), value_candidates.end());
265 auto min_idx = std::distance(value_candidates.begin(), min_it);
266 EoM_cell = cell_candidates[min_idx];
267 EoM = EoM_candidates[min_idx];
271 find_EoM(cell_candidates[0], EoM_cell, EoM, t_EoM_value);
295 typename dealii::DoFHandler<dim>::cell_iterator &EoM_cell,
const VectorType &sol,
296 const dealii::DoFHandler<dim> &dof_handler,
const dealii::Mapping<dim> &mapping,
const EoMFUN &get_EoM,
297 const EoMPFUN &EoM_postprocess = [](
const auto &p,
const auto &values) {
return p; },
298 const double EoM_abs_tol = 1e-8,
const uint max_iter = 100)
300 using namespace dealii;
301 using CellIterator =
typename dealii::DoFHandler<dim>::cell_iterator;
302 using EoMType = std::array<double, dim>;
304 Vector<typename VectorType::value_type> values(dof_handler.get_fe().n_components());
305 Functions::FEFieldFunction<dim, VectorType> fe_function(dof_handler, sol, mapping);
309 fe_function.set_active_cell(EoM_cell);
310 fe_function.vector_value(origin, values);
311 const auto origin_val = get_EoM(origin, values);
313 const auto secondary_point = (origin + EoM_cell->center()) / 2.;
314 fe_function.vector_value(secondary_point, values);
315 const auto secondary_val = get_EoM(secondary_point, values);
319 std::array<bool, dim> axis_restrictions{{}};
320 for (
uint d = 0; d < dim; ++d)
321 axis_restrictions[d] = (origin_val[d] >= 0) && (secondary_val[d] >= 0);
323 const bool any_axis_restricted =
324 std::any_of(std::begin(axis_restrictions), std::end(axis_restrictions), [](
bool i) {
return i; });
325 const bool all_axis_restricted =
326 std::all_of(std::begin(axis_restrictions), std::end(axis_restrictions), [](
bool i) {
return i; });
329 EoM_cell = GridTools::find_active_cell_around_point(dof_handler, EoM);
330 if (all_axis_restricted) {
332 std::cout <<
"All axis restricted" << std::endl;
336 std::cout <<
"Restrictions: ";
337 for (
uint d = 0; d < dim; ++d)
338 std::cout << axis_restrictions[d] <<
" ";
339 std::cout << std::endl;
341 auto check_cell = [&](
const CellIterator &cell) ->
bool {
342 if (any_axis_restricted && !cell->has_boundary_lines())
return false;
345 std::array<EoMType, GeometryInfo<dim>::vertices_per_cell> EoM_vals;
346 std::array<Point<dim>, GeometryInfo<dim>::vertices_per_cell> vertices;
347 Vector<typename VectorType::value_type> values(dof_handler.get_fe().n_components());
348 Functions::FEFieldFunction<dim, VectorType> fe_function(dof_handler, sol, mapping);
350 fe_function.set_active_cell(cell);
351 for (
uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i) {
352 vertices[i] = cell->vertex(i);
353 fe_function.vector_value(vertices[i], values);
354 EoM_vals[i] = get_EoM(vertices[i], values);
357 if (any_axis_restricted)
358 for (
uint d = 0; d < dim; ++d)
359 if (axis_restrictions[d]) {
360 bool has_zero_boundary =
false;
361 for (
uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
362 if (
is_close(origin[d], vertices[i][d], 1e-12)) {
363 has_zero_boundary =
true;
366 if (!has_zero_boundary) {
367 std::cout <<
"No zero boundary for cell with vertices: ";
368 for (
uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i) {
369 std::cout <<
"vertex " << i <<
": ";
370 for (
uint d = 0; d < dim; ++d)
371 std::cout << vertices[i][d] <<
" ";
372 std::cout << std::endl;
379 std::array<bool, dim> cell_has_EoM{{}};
381 if (!any_axis_restricted) {
382 for (
uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
383 for (
uint j = 0; j < i; ++j)
384 for (
uint d = 0; d < dim; ++d)
385 cell_has_EoM[d] = cell_has_EoM[d] || (EoM_vals[i][d] * EoM_vals[j][d] < 0.);
387 std::vector<bool> valid_vertices(GeometryInfo<dim>::vertices_per_cell,
true);
389 for (
uint d = 0; d < dim; ++d)
390 if (axis_restrictions[d])
391 for (
uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
393 for (
uint j = 0; j < i; ++j) {
394 if (vertices[i][d] > vertices[j][d]) {
395 valid_vertices[i] =
false;
400 for (
uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i)
401 if (valid_vertices[i])
402 for (
uint j = 0; j < i; ++j)
403 if (valid_vertices[j])
404 for (
uint d = 0; d < dim; ++d)
405 cell_has_EoM[d] = cell_has_EoM[d] || (EoM_vals[i][d] * EoM_vals[j][d] < 0.);
409 for (
uint d = 0; d < dim; ++d)
410 if (!axis_restrictions[d]) has_EoM = has_EoM && cell_has_EoM[d];
415 gsl_set_error_handler_off();
417 auto find_EoM = [&](
const CellIterator &cell, CellIterator &m_EoM_cell, Point<dim> &m_EoM,
418 double &EoM_val) ->
bool {
419 Functions::FEFieldFunction<dim, VectorType> fe_function(dof_handler, sol, mapping);
420 Vector<typename VectorType::value_type> values(dof_handler.get_fe().n_components());
421 fe_function.set_active_cell(cell);
424 std::array<std::array<double, 2>, dim> cell_boundaries{{}};
425 for (
uint d = 0; d < dim; ++d) {
426 cell_boundaries[d][0] = cell->center()[d];
427 cell_boundaries[d][1] = cell->center()[d];
429 for (
uint d = 0; d < dim; ++d) {
430 for (
uint i = 0; i < GeometryInfo<dim>::vertices_per_cell; ++i) {
431 cell_boundaries[d][0] = std::min(cell_boundaries[d][0], cell->vertex(i)[d]);
432 cell_boundaries[d][1] = std::max(cell_boundaries[d][1], cell->vertex(i)[d]);
436 std::cout <<
"Cell boundaries: ";
437 for (
uint d = 0; d < dim; ++d)
438 std::cout <<
"[" << cell_boundaries[d][0] <<
", " << cell_boundaries[d][1] <<
"] ";
439 std::cout << std::endl;
442 for (
uint d = 0; d < dim; ++d)
443 if (axis_restrictions[d]) subdim--;
447 for (
uint d = 0; d < dim; ++d)
448 if (!axis_restrictions[d]) dir = d;
453 for (
uint d = 0; d < dim; ++d) {
454 p1[d] = cell_boundaries[d][0];
455 p2[d] = cell_boundaries[d][0];
457 p2[dir] = cell_boundaries[dir][1];
458 auto p = (p1 + p2) / 2.;
460 std::cout <<
"SUBDIM TRYING AT p = " << p << std::endl;
462 fe_function.vector_value(p, values);
463 EoM_val = get_EoM(p, values)[dir];
467 while (err > EoM_abs_tol) {
474 fe_function.vector_value(p, values);
475 EoM_val = get_EoM(p, values)[dir];
476 err = std::abs(EoM_val);
478 if (iter > max_iter) {
479 m_EoM = EoM_postprocess(p, values);
486 m_EoM = EoM_postprocess(p, values);
492 std::function<std::array<double, dim>(
const dealii::Point<dim> &)> eval_on_point =
493 [&](
const Point<dim> &p) -> std::array<double, dim> {
494 Point<dim> p_proj = p;
495 for (
uint d = 0, i = 0; d < dim; ++d)
496 p_proj[d] = axis_restrictions[d] ? origin[d] : p[i++];
499 std::array<double, dim> out_distance{{}};
500 for (
uint d = 0; d < dim; ++d) {
501 if (p_proj[d] < cell_boundaries[d][0]) {
502 out_distance[d] = std::abs(p_proj[d] - cell_boundaries[d][0]);
503 p_proj[d] = cell_boundaries[d][0];
504 std::cout <<
"Point outside cell" << std::endl;
505 std::cout <<
"Point: " << p << std::endl;
506 }
else if (p_proj[d] > cell_boundaries[d][1]) {
507 out_distance[d] = std::abs(p_proj[d] - cell_boundaries[d][1]);
508 p_proj[d] = cell_boundaries[d][1];
509 std::cout <<
"Point outside cell" << std::endl;
510 std::cout <<
"Point: " << p << std::endl;
515 fe_function.vector_value(p_proj, values);
516 }
catch (
const std::exception &e) {
518 std::cerr <<
"Warning: EoM evaluation failed at point " << p_proj <<
": " << e.what() << std::endl;
519 return std::array<double, dim>{{
520 std::numeric_limits<double>::quiet_NaN(),
523 std::cerr <<
"Warning: EoM evaluation failed at point " << p_proj <<
" with unknown exception" << std::endl;
524 return std::array<double, dim>{{
525 std::numeric_limits<double>::quiet_NaN(),
529 auto EoM = get_EoM(p, values);
532 for (
uint d = 0; d < dim; ++d)
533 if (out_distance[d] > 0) {
534 std::cout <<
"Extrapolating value from " << EoM[d];
535 EoM[d] =
is_close(EoM[d], 0.) ? out_distance[d] : EoM[d] * (1 + out_distance[d]);
536 std::cout <<
" to " << EoM[d] << std::endl;
540 std::array<double, dim> EoM_out{{}};
541 for (
uint d = 0, i = 0; d < dim; ++d)
542 if (!axis_restrictions[d]) EoM_out[d] = EoM[i++];
547 const auto cell_center = cell->center();
548 std::vector<double> subdim_center(subdim);
549 for (
uint d = 0, i = 0; d < dim; ++d)
550 if (!axis_restrictions[d]) subdim_center[i++] = cell_center[d];
553 const gsl_multiroot_fsolver_type *T = gsl_multiroot_fsolver_hybrids;
554 gsl_multiroot_fsolver *s = gsl_multiroot_fsolver_alloc(T, subdim);
560 gsl_vector *x = gsl_vector_alloc(subdim);
561 for (
int d = 0; d < subdim; ++d)
562 gsl_vector_set(x, d, subdim_center[d]);
565 gsl_multiroot_fsolver_set(s, &f, x);
572 status = gsl_multiroot_fsolver_iterate(s);
576 status = gsl_multiroot_test_residual(s->f, EoM_abs_tol);
578 }
while (status == GSL_CONTINUE && iter < max_iter);
581 for (
uint d = 0, sd = 0; d < dim; ++d)
582 m_EoM[d] = axis_restrictions[d] ? origin[d] : gsl_vector_get(s->x, sd++);
585 gsl_multiroot_fsolver_free(s);
588 if (status != GSL_SUCCESS)
return false;
590 m_EoM = EoM_postprocess(m_EoM, values);
593 : GridTools::find_active_cell_around_point(dof_handler, m_EoM);
598 std::vector<typename dealii::DoFHandler<dim>::cell_iterator> cell_candidates;
599 std::vector<double> value_candidates;
600 std::vector<Point<dim>> EoM_candidates;
605 const uint n_active_cells = dof_handler.get_triangulation().n_active_cells();
609 for (
uint index = 0; index < n_active_cells; ++index) {
610 auto cell = dof_handler.begin_active();
611 std::advance(cell, index);
612 if (check_cell(cell)) {
613 Point<dim> t_EoM = cell->center();
614 CellIterator t_EoM_cell = cell;
615 double t_EoM_value = 0.;
620 if (find_EoM(cell, t_EoM_cell, t_EoM, t_EoM_value)) {
621 std::cout <<
"Found EoM point in cell " << index << std::endl;
622 std::cout <<
"EoM: " << t_EoM << std::endl;
623 for (
uint d = 0; d < dim; ++d)
624 if (t_EoM[d] < origin[d]) t_EoM[d] = origin[d];
626 EoM_cell = dealii::GridTools::find_active_cell_around_point(dof_handler, EoM);
630 cell_candidates.push_back(t_EoM_cell);
631 EoM_candidates.push_back(t_EoM);
632 value_candidates.push_back(std::abs(t_EoM_value));
636 std::cout <<
"Found " << cell_candidates.size() <<
" candidates." << std::endl;
638 double EoM_value = 0.;
640 if (cell_candidates.size() == 1) {
641 if (find_EoM(cell_candidates[0], EoM_cell, EoM, EoM_value))
return EoM;
642 }
else if (cell_candidates.size() == 0) {
643 EoM_cell = GridTools::find_active_cell_around_point(dof_handler, origin);
645 }
else if (cell_candidates.size() > 1) {
647 auto min_it = std::min_element(value_candidates.begin(), value_candidates.end());
648 auto min_idx = std::distance(value_candidates.begin(), min_it);
649 EoM_cell = cell_candidates[min_idx];
650 EoM = EoM_candidates[min_idx];