-
-
Notifications
You must be signed in to change notification settings - Fork 252
Add equidistribution marking #4187
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
e84da5d
6945e6f
c4a2bdb
a5ff0dd
e997738
b9831ba
6e9b9c4
59af09c
de0b6a0
96ae33e
4a63e73
b4690b8
573e125
10575df
77d35fe
425a642
63ace3f
8d2ae29
c588fb7
f56fae3
b768685
3d3be2a
aa60ca1
d3b4a9b
73ea789
10ced01
6b2cca2
625957b
d9656db
cf0121f
9b48e05
8dd7c9f
a65c3c1
08bb596
cb56b7a
6f3733c
477c05c
a498c3b
e533aed
5fd1a96
5455f00
f17e463
ddc3eb4
15e0438
fa679a2
c475ca0
43b5203
ffc96ab
5dbcea4
86f9765
4936a94
254c711
7c5f5a6
6caed8d
bcc5bcd
3b464e1
573b8da
e5e0564
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,34 @@ | |
| namespace dolfinx::refinement | ||
| { | ||
|
|
||
| namespace impl | ||
| { | ||
|
|
||
| /// @brief Threshold marking helper | ||
|
schnellerhase marked this conversation as resolved.
Outdated
|
||
| /// | ||
| /// @param[in] marker Input marker | ||
| /// @param[in] threshold Lower bound for values to mark | ||
|
schnellerhase marked this conversation as resolved.
Outdated
|
||
| /// | ||
| /// @returns indices i which satisfy e_i > threshold. | ||
| template <std::floating_point T> | ||
| std::vector<std::int32_t> mark_threshold(std::span<const T> marker, T threshold) | ||
| { | ||
| auto mark = [=](T e) { return e > threshold; }; | ||
|
schnellerhase marked this conversation as resolved.
Outdated
|
||
|
|
||
| std::vector<std::int32_t> indices; | ||
| indices.reserve(std::ranges::count_if(marker, mark)); | ||
|
|
||
| for (std::int32_t i = 0; i < static_cast<std::int32_t>(marker.size()); ++i) | ||
| { | ||
| if (mark(marker[i])) | ||
| indices.push_back(i); | ||
| } | ||
|
|
||
| return indices; | ||
| } | ||
|
|
||
| } // namespace impl | ||
|
|
||
| /// @brief Maximum marking of a marker. | ||
|
schnellerhase marked this conversation as resolved.
Outdated
|
||
| /// | ||
| /// @param[in] marker Input marker (local) - usually an error indicator per | ||
|
|
@@ -39,18 +67,45 @@ std::vector<std::int32_t> mark_maximum(std::span<const T> marker, T theta, | |
| : std::ranges::max(marker); | ||
| MPI_Allreduce(MPI_IN_PLACE, &max, 1, dolfinx::MPI::mpi_t<T>, MPI_MAX, comm); | ||
|
|
||
| auto mark = [=](T e) { return e > theta * max; }; | ||
| auto indices = impl::mark_threshold<T>(marker, theta * max); | ||
|
|
||
| std::vector<std::int32_t> indices; | ||
| indices.reserve(std::ranges::count_if(marker, mark)); | ||
| spdlog::info("Marking (max) {} / {} (local) entities.", indices.size(), | ||
|
schnellerhase marked this conversation as resolved.
Outdated
|
||
| marker.size()); | ||
|
|
||
| for (std::int32_t i = 0; i < static_cast<std::int32_t>(marker.size()); ++i) | ||
| { | ||
| if (mark(marker[i])) | ||
| indices.push_back(i); | ||
| } | ||
| return indices; | ||
| } | ||
|
|
||
| spdlog::info("Marking (max) {} / {} (local) entities.", indices.size(), | ||
| /// @brief Equidistribution marking of a marker. | ||
|
schnellerhase marked this conversation as resolved.
Outdated
|
||
| /// | ||
|
schnellerhase marked this conversation as resolved.
|
||
| /// @param[in] marker Input marker (local) - usually an error indicator per | ||
|
schnellerhase marked this conversation as resolved.
Outdated
|
||
| /// entity | ||
| /// @param[in] theta Parameter, 0 < θ < 1 | ||
| /// @param[in] comm Communicator over which the total marker is computed. | ||
|
schnellerhase marked this conversation as resolved.
Outdated
|
||
| /// @return Indices (local) of marker elements, which satisfy: marker_i ≥ θ | ||
|
schnellerhase marked this conversation as resolved.
Outdated
|
||
| /// (sum_i marker_i^2)^1/2 / N^1/2. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please correct me if I'm wrong, but there is probably no need to do so many square root operations - assuming markers/indicators and theta are always positive, you can square both sides: marker_i^2 ≥ θ^2 (sum_i marker_i^2) / N.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's true but we would sacrifice the shared code path of
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not really - in the vast majority of cases I'm familiar with, one naturally assembles the square of the entity estimator, so your approach effectively requires the user to do many square roots outside this function.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See e.g. https://doi.org/10.1016/j.camwa.2022.11.009 eq A.1, A.4, 3.15 (which should really be squared on both sides).
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That would require changing the input to be interpreted as squared already which complicates the interface: the equidistribution property is based on
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree, but they are valid indicators for selecting a region of interest. That's why we should not have an interface which requires squared quantities as input, right?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then why are you squaring them on the inside? Both my design and your design imply the suitability of the l^2 norm - in the proper AFEM setting this suitability is entirely justified. For your 'indicators' it is a completely unjustified imposition.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That would be a users responsibility to ensure that this checks out (if there is any theory on that). The maximum marking is also not assuming an underlying l2 structure and gets heavily used in AFEM schemes (for noisy indicators, I think). The interface should not assume structure on the input data. Any other norm based, or not norm based, measure could be supported. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if we added something like a marker_is_squared flag? While this would have no effect for maximum marking or Dörfler marking, where it is the user’s responsibility to provide either squared or non-squared markers, as well as the correct marking parameter, this could solve the issue with the equidistribution strategy.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like the idea - feels like a practical resolution to the problem honouring that the l2 case is the 95% use case and allowing for general interface usage in the meantime. Only I would prefer to provide the additional argument to all functions if we enable it (so also for max marking for now), for a consistent user interface - even though it is not strictly functionally required. What do you think @jhale? |
||
| template <std::floating_point T> | ||
| std::vector<std::int32_t> mark_equidistribution(std::span<const T> marker, | ||
| T theta, MPI_Comm comm) | ||
| { | ||
| if ((theta <= 0) || (theta >= 1)) | ||
| throw std::invalid_argument("Theta needs to fullfill 0 < θ < 1."); | ||
|
|
||
| T norm{0}; | ||
|
schnellerhase marked this conversation as resolved.
Outdated
|
||
| for (T e : marker) | ||
| norm += std::pow(e, 2); | ||
|
|
||
| MPI_Allreduce(MPI_IN_PLACE, &norm, 1, dolfinx::MPI::mpi_t<T>, MPI_SUM, comm); | ||
|
|
||
| norm = std::sqrt(norm); | ||
|
|
||
| std::int32_t count = marker.size(); | ||
| MPI_Allreduce(MPI_IN_PLACE, &count, 1, dolfinx::MPI::mpi_t<std::int32_t>, | ||
| MPI_SUM, comm); | ||
|
|
||
| auto indices | ||
| = impl::mark_threshold<T>(marker, theta * norm / std::sqrt(count)); | ||
|
|
||
| spdlog::info("Marking (equi) {} / {} (local) entities.", indices.size(), | ||
|
schnellerhase marked this conversation as resolved.
Outdated
|
||
| marker.size()); | ||
|
|
||
| return indices; | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.