34 using hrleIndexType = viennahrle::IndexType;
36 SmartPointer<Domain<T, D>> levelSetTarget =
nullptr;
37 SmartPointer<Domain<T, D>> levelSetSample =
nullptr;
42 std::array<T, D> minBounds;
43 std::array<T, D> maxBounds;
47 std::vector<RangeSpec> rangeSpecs;
50 struct CriticalDimensionResult {
52 std::array<T, D> minBounds;
53 std::array<T, D> maxBounds;
61 std::vector<CriticalDimensionResult> results;
64 SmartPointer<Mesh<T>> outputMesh =
nullptr;
67 if (levelSetTarget ==
nullptr || levelSetSample ==
nullptr) {
68 VIENNACORE_LOG_WARNING(
"Missing level set in CompareCriticalDimensions.");
73 const auto &gridTarget = levelSetTarget->getGrid();
74 const auto &gridSample = levelSetSample->getGrid();
76 if (gridTarget.getGridDelta() != gridSample.getGridDelta()) {
77 VIENNACORE_LOG_WARNING(
78 "Grid delta mismatch in CompareCriticalDimensions. The "
79 "grid deltas of the two level sets must be equal.");
83 if (rangeSpecs.empty()) {
84 VIENNACORE_LOG_WARNING(
85 "No ranges specified in CompareCriticalDimensions.");
94 std::vector<T> findSurfaceCrossings(SmartPointer<
Mesh<T>> surfaceMesh,
95 const RangeSpec &spec) {
96 std::vector<T> crossings;
99 for (
const auto &node : surfaceMesh->nodes) {
102 for (
int i = 0; i <
D; ++i) {
103 if (i == spec.measureDimension)
105 if (node[i] < spec.minBounds[i] || node[i] > spec.maxBounds[i]) {
112 T val = node[spec.measureDimension];
113 if (val >= spec.minBounds[spec.measureDimension] &&
114 val <= spec.maxBounds[spec.measureDimension]) {
115 crossings.push_back(val);
124 std::pair<bool, T> findCriticalDimension(
const std::vector<T> &crossings,
126 if (crossings.empty()) {
131 return {
true, *std::max_element(crossings.begin(), crossings.end())};
133 return {
true, *std::min_element(crossings.begin(), crossings.end())};
142 : levelSetTarget(passedLevelSetTarget),
143 levelSetSample(passedLevelSetSample) {}
146 levelSetTarget = passedLevelSet;
150 levelSetSample = passedLevelSet;
154 void addRange(
int measureDimension,
const std::array<T, D> &minBounds,
155 const std::array<T, D> &maxBounds,
bool findMaximum =
true) {
157 spec.measureDimension = measureDimension;
158 spec.minBounds = minBounds;
159 spec.maxBounds = maxBounds;
160 spec.findMaximum = findMaximum;
161 rangeSpecs.push_back(spec);
166 if constexpr (
D == 2) {
167 std::array<T, D> minBounds = {minX, std::numeric_limits<T>::lowest()};
168 std::array<T, D> maxBounds = {maxX, std::numeric_limits<T>::max()};
169 addRange(1, minBounds, maxBounds, findMaximum);
171 VIENNACORE_LOG_WARNING(
172 "addXRange is only supported for 2D. Use addRange for 3D.");
178 if constexpr (
D == 2) {
179 std::array<T, D> minBounds = {std::numeric_limits<T>::lowest(), minY};
180 std::array<T, D> maxBounds = {std::numeric_limits<T>::max(), maxY};
181 addRange(0, minBounds, maxBounds, findMaximum);
183 VIENNACORE_LOG_WARNING(
184 "addYRange is only supported for 2D. Use addRange for 3D.");
193 outputMesh = passedMesh;
200 if (!checkInputs()) {
204 const auto &grid = levelSetTarget->getGrid();
205 const T gridDelta = grid.getGridDelta();
208 auto surfaceMeshRef = SmartPointer<Mesh<T>>::New();
209 auto surfaceMeshCmp = SmartPointer<Mesh<T>>::New();
215 results.resize(rangeSpecs.size());
218#pragma omp parallel for
219 for (
size_t specIdx = 0; specIdx < rangeSpecs.size(); ++specIdx) {
220 const auto &spec = rangeSpecs[specIdx];
221 CriticalDimensionResult result;
222 result.measureDimension = spec.measureDimension;
223 result.minBounds = spec.minBounds;
224 result.maxBounds = spec.maxBounds;
225 result.findMaximum = spec.findMaximum;
226 result.valid =
false;
229 auto crossingsRef = findSurfaceCrossings(surfaceMeshRef, spec);
230 auto crossingsCmp = findSurfaceCrossings(surfaceMeshCmp, spec);
233 auto [validRef, cdRef] =
234 findCriticalDimension(crossingsRef, spec.findMaximum);
235 auto [validCmp, cdCmp] =
236 findCriticalDimension(crossingsCmp, spec.findMaximum);
238 if (validRef && validCmp) {
240 result.positionTarget = cdRef;
241 result.positionSample = cdCmp;
242 result.difference = std::abs(cdRef - cdCmp);
246 results[specIdx] = result;
250 if (outputMesh !=
nullptr) {
260 T &positionSample,
T &difference)
const {
261 if (index >= results.size() || !results[index].valid) {
264 positionTarget = results[index].positionTarget;
265 positionSample = results[index].positionSample;
266 difference = results[index].difference;
274 for (
const auto &result : results) {
276 sum += result.difference;
280 return count > 0 ? sum / count : std::numeric_limits<T>::quiet_NaN();
286 for (
const auto &result : results) {
288 maxDiff = std::max(maxDiff, result.difference);
298 for (
const auto &result : results) {
300 sumSquared += result.difference * result.difference;
304 return count > 0 ? std::sqrt(sumSquared / count)
305 : std::numeric_limits<T>::quiet_NaN();
310 std::vector<T> differences;
311 for (
const auto &result : results) {
313 differences.push_back(result.difference);
320 void generateMesh() {
323 std::vector<Vec3D<T>> nodeCoordinates;
324 std::vector<std::array<unsigned, 1>> vertexIndices;
325 std::vector<T> differenceValues;
326 std::vector<T> targetValues;
327 std::vector<T> sampleValues;
329 for (
unsigned i = 0; i < 3; ++i) {
330 outputMesh->minimumExtent[i] =
331 (i < D) ? std::numeric_limits<T>::max() : 0.0;
332 outputMesh->maximumExtent[i] =
333 (i < D) ? std::numeric_limits<T>::lowest() : 0.0;
336 unsigned pointId = 0;
337 for (
const auto &result : results) {
342 Vec3D<T> coordTarget{};
343 Vec3D<T> coordSample{};
345 for (
int i = 0; i <
D; ++i) {
346 if (i == result.measureDimension) {
347 coordTarget[i] = result.positionTarget;
348 coordSample[i] = result.positionSample;
351 T mid = (result.minBounds[i] + result.maxBounds[i]) / 2.0;
353 if (std::abs(mid) > std::numeric_limits<T>::max() / 2.0)
355 coordTarget[i] = mid;
356 coordSample[i] = mid;
361 nodeCoordinates.push_back(coordTarget);
362 vertexIndices.push_back({pointId++});
363 differenceValues.push_back(result.difference);
364 targetValues.push_back(result.positionTarget);
365 sampleValues.push_back(result.positionSample);
368 nodeCoordinates.push_back(coordSample);
369 vertexIndices.push_back({pointId++});
370 differenceValues.push_back(result.difference);
371 targetValues.push_back(result.positionTarget);
372 sampleValues.push_back(result.positionSample);
375 for (
unsigned i = 0; i <
D; ++i) {
376 outputMesh->minimumExtent[i] = std::min(
377 {outputMesh->minimumExtent[i], coordTarget[i], coordSample[i]});
378 outputMesh->maximumExtent[i] = std::max(
379 {outputMesh->maximumExtent[i], coordTarget[i], coordSample[i]});
383 if (!nodeCoordinates.empty()) {
384 outputMesh->nodes = std::move(nodeCoordinates);
385 outputMesh->vertices = std::move(vertexIndices);
386 outputMesh->pointData.insertNextScalarData(std::move(differenceValues),
388 outputMesh->pointData.insertNextScalarData(std::move(targetValues),
390 outputMesh->pointData.insertNextScalarData(std::move(sampleValues),
Class containing all information about the level set, including the dimensions of the domain,...
Definition lsDomain.hpp:28