36 using hrleIndexType = viennahrle::IndexType;
38 SmartPointer<Domain<T, D>> levelSetTarget =
nullptr;
39 SmartPointer<Domain<T, D>> levelSetSample =
nullptr;
49 std::vector<RangeSpec> rangeSpecs;
52 struct CriticalDimensionResult {
63 std::vector<CriticalDimensionResult> results;
66 SmartPointer<Mesh<T>> outputMesh =
nullptr;
69 if (levelSetTarget ==
nullptr || levelSetSample ==
nullptr) {
70 VIENNACORE_LOG_WARNING(
"Missing level set in CompareCriticalDimensions.");
75 const auto &gridTarget = levelSetTarget->getGrid();
76 const auto &gridSample = levelSetSample->getGrid();
78 if (gridTarget.getGridDelta() != gridSample.getGridDelta()) {
79 VIENNACORE_LOG_WARNING(
80 "Grid delta mismatch in CompareCriticalDimensions. The "
81 "grid deltas of the two level sets must be equal.");
85 if (rangeSpecs.empty()) {
86 VIENNACORE_LOG_WARNING(
87 "No ranges specified in CompareCriticalDimensions.");
96 std::vector<T> findSurfaceCrossings(SmartPointer<
Mesh<T>> surfaceMesh,
97 bool isXRange,
T scanMin,
T scanMax,
98 T perpMin,
T perpMax) {
99 std::vector<T> crossings;
102 for (
const auto &node : surfaceMesh->nodes) {
107 bool inRange =
false;
110 inRange = (xCoord >= scanMin && xCoord <= scanMax);
113 inRange = (yCoord >= scanMin && yCoord <= scanMax);
118 T perpCoord = isXRange ? yCoord : xCoord;
121 if (perpCoord >= perpMin && perpCoord <= perpMax) {
122 crossings.push_back(perpCoord);
131 std::pair<bool, T> findCriticalDimension(
const std::vector<T> &crossings,
133 if (crossings.empty()) {
138 return {
true, *std::max_element(crossings.begin(), crossings.end())};
140 return {
true, *std::min_element(crossings.begin(), crossings.end())};
146 static_assert(
D == 2 &&
"CompareCriticalDimensions is currently only "
147 "implemented for 2D level sets.");
152 : levelSetTarget(passedLevelSetTarget),
153 levelSetSample(passedLevelSetSample) {
154 static_assert(
D == 2 &&
"CompareCriticalDimensions is currently only "
155 "implemented for 2D level sets.");
159 levelSetTarget = passedLevelSet;
163 levelSetSample = passedLevelSet;
169 spec.isXRange =
true;
170 spec.rangeMin = minX;
171 spec.rangeMax = maxX;
172 spec.findMaximum = findMaximum;
173 rangeSpecs.push_back(spec);
179 spec.isXRange =
false;
180 spec.rangeMin = minY;
181 spec.rangeMax = maxY;
182 spec.findMaximum = findMaximum;
183 rangeSpecs.push_back(spec);
191 outputMesh = passedMesh;
198 if (!checkInputs()) {
202 const auto &grid = levelSetTarget->getGrid();
203 const T gridDelta = grid.getGridDelta();
206 auto surfaceMeshRef = SmartPointer<Mesh<T>>::New();
207 auto surfaceMeshCmp = SmartPointer<Mesh<T>>::New();
215 T xMin = std::numeric_limits<T>::max();
216 T xMax = std::numeric_limits<T>::lowest();
217 T yMin = std::numeric_limits<T>::max();
218 T yMax = std::numeric_limits<T>::lowest();
220 for (
const auto &node : surfaceMeshRef->nodes) {
221 xMin = std::min(xMin, node[0]);
222 xMax = std::max(xMax, node[0]);
223 yMin = std::min(yMin, node[1]);
224 yMax = std::max(yMax, node[1]);
226 for (
const auto &node : surfaceMeshCmp->nodes) {
227 xMin = std::min(xMin, node[0]);
228 xMax = std::max(xMax, node[0]);
229 yMin = std::min(yMin, node[1]);
230 yMax = std::max(yMax, node[1]);
234 results.resize(rangeSpecs.size());
237#pragma omp parallel for
238 for (
size_t specIdx = 0; specIdx < rangeSpecs.size(); ++specIdx) {
239 const auto &spec = rangeSpecs[specIdx];
240 CriticalDimensionResult result;
241 result.isXRange = spec.isXRange;
242 result.rangeMin = spec.rangeMin;
243 result.rangeMax = spec.rangeMax;
244 result.findMaximum = spec.findMaximum;
245 result.valid =
false;
248 T scanMin, scanMax, perpMin, perpMax;
251 scanMin = spec.rangeMin;
252 scanMax = spec.rangeMax;
257 scanMin = spec.rangeMin;
258 scanMax = spec.rangeMax;
264 auto crossingsRef = findSurfaceCrossings(
265 surfaceMeshRef, spec.isXRange, scanMin, scanMax, perpMin, perpMax);
266 auto crossingsCmp = findSurfaceCrossings(
267 surfaceMeshCmp, spec.isXRange, scanMin, scanMax, perpMin, perpMax);
270 auto [validRef, cdRef] =
271 findCriticalDimension(crossingsRef, spec.findMaximum);
272 auto [validCmp, cdCmp] =
273 findCriticalDimension(crossingsCmp, spec.findMaximum);
275 if (validRef && validCmp) {
277 result.positionTarget = cdRef;
278 result.positionSample = cdCmp;
279 result.difference = std::abs(cdRef - cdCmp);
283 results[specIdx] = result;
287 if (outputMesh !=
nullptr) {
297 T &positionSample,
T &difference)
const {
298 if (index >= results.size() || !results[index].valid) {
301 positionTarget = results[index].positionTarget;
302 positionSample = results[index].positionSample;
303 difference = results[index].difference;
311 for (
const auto &result : results) {
313 sum += result.difference;
317 return count > 0 ? sum / count : std::numeric_limits<T>::quiet_NaN();
323 for (
const auto &result : results) {
325 maxDiff = std::max(maxDiff, result.difference);
335 for (
const auto &result : results) {
337 sumSquared += result.difference * result.difference;
341 return count > 0 ? std::sqrt(sumSquared / count)
342 : std::numeric_limits<T>::quiet_NaN();
347 std::vector<T> differences;
348 for (
const auto &result : results) {
350 differences.push_back(result.difference);
357 void generateMesh() {
360 std::vector<Vec3D<T>> nodeCoordinates;
361 std::vector<std::array<unsigned, 1>> vertexIndices;
362 std::vector<T> differenceValues;
363 std::vector<T> targetValues;
364 std::vector<T> sampleValues;
366 for (
unsigned i = 0; i <
D; ++i) {
367 outputMesh->minimumExtent[i] = std::numeric_limits<T>::max();
368 outputMesh->maximumExtent[i] = std::numeric_limits<T>::lowest();
371 unsigned pointId = 0;
372 for (
const auto &result : results) {
377 Vec3D<T> coordTarget, coordSample;
379 if (result.isXRange) {
381 T xMid = (result.rangeMin + result.rangeMax) / 2.0;
382 coordTarget = {xMid, result.positionTarget, 0.0};
383 coordSample = {xMid, result.positionSample, 0.0};
386 T yMid = (result.rangeMin + result.rangeMax) / 2.0;
387 coordTarget = {result.positionTarget, yMid, 0.0};
388 coordSample = {result.positionSample, yMid, 0.0};
392 nodeCoordinates.push_back(coordTarget);
393 vertexIndices.push_back({pointId++});
394 differenceValues.push_back(result.difference);
395 targetValues.push_back(result.positionTarget);
396 sampleValues.push_back(result.positionSample);
399 nodeCoordinates.push_back(coordSample);
400 vertexIndices.push_back({pointId++});
401 differenceValues.push_back(result.difference);
402 targetValues.push_back(result.positionTarget);
403 sampleValues.push_back(result.positionSample);
406 for (
unsigned i = 0; i <
D; ++i) {
407 outputMesh->minimumExtent[i] = std::min(
408 {outputMesh->minimumExtent[i], coordTarget[i], coordSample[i]});
409 outputMesh->maximumExtent[i] = std::max(
410 {outputMesh->maximumExtent[i], coordTarget[i], coordSample[i]});
414 if (!nodeCoordinates.empty()) {
415 outputMesh->nodes = std::move(nodeCoordinates);
416 outputMesh->vertices = std::move(vertexIndices);
417 outputMesh->pointData.insertNextScalarData(std::move(differenceValues),
419 outputMesh->pointData.insertNextScalarData(std::move(targetValues),
421 outputMesh->pointData.insertNextScalarData(std::move(sampleValues),
Class containing all information about the level set, including the dimensions of the domain,...
Definition lsDomain.hpp:27