ViennaLS
Loading...
Searching...
No Matches
lsCompareSparseField.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <hrleSparseIterator.hpp>
4#include <lsDomain.hpp>
5#include <lsExpand.hpp>
6#include <lsMesh.hpp>
8#include <lsReduce.hpp>
9
10#include <cmath>
11#include <limits>
12
13namespace viennals {
14
15using namespace viennacore;
16
33
34template <class T, int D = 2> class CompareSparseField {
35 using hrleIndexType = viennahrle::IndexType;
36
37 SmartPointer<Domain<T, D>> levelSetExpanded = nullptr;
38 SmartPointer<Domain<T, D>> levelSetIterated = nullptr;
39
40 // Variables for x and y range restrictions
41 T xRangeMin = std::numeric_limits<T>::lowest();
42 T xRangeMax = std::numeric_limits<T>::max();
43 T yRangeMin = std::numeric_limits<T>::lowest();
44 T yRangeMax = std::numeric_limits<T>::max();
45 T zRangeMin = std::numeric_limits<T>::lowest();
46 T zRangeMax = std::numeric_limits<T>::max();
47 bool useXRange = false;
48 bool useYRange = false;
49 bool useZRange = false;
50
51 // Fields to store the calculation results
52 T sumSquaredDifferences = 0.0;
53 T sumDifferences = 0.0;
54 unsigned numPoints = 0;
55 unsigned numSkippedPoints = 0;
56
57 // Add mesh output capability
58 SmartPointer<Mesh<T>> outputMesh = nullptr;
59
60 // Add bool for filling the iterated level set with distances
61 bool fillIteratedWithDistances = false;
62
63 // Expansion width for the expanded level set
64 int expandedLevelSetWidth = 50;
65
66 bool checkAndCalculateBounds() {
67 if (levelSetExpanded == nullptr || levelSetIterated == nullptr) {
68 Logger::getInstance()
69 .addError("Missing level set in CompareSparseField.")
70 .print();
71 return false;
72 }
73
74 // Check if the grids are compatible
75 const auto &gridExpanded = levelSetExpanded->getGrid();
76 const auto &gridIterated = levelSetIterated->getGrid();
77
78 if (gridExpanded.getGridDelta() != gridIterated.getGridDelta()) {
79 Logger::getInstance()
80 .addError("Grid delta mismatch in CompareSparseField. The grid "
81 "deltas of the two level sets must be equal.")
82 .print();
83 return false;
84 }
85
86 // // Check if the x extents of both level sets are equal
87 // const auto &domainExpanded = levelSetExpanded->getDomain();
88 // const auto &domainIterated = levelSetIterated->getDomain();
89
90 // hrleIndexType expandedMinX = gridExpanded.isNegBoundaryInfinite(0)
91 // ? domainExpanded.getMinRunBreak(0)
92 // : gridExpanded.getMinIndex(0);
93 // hrleIndexType expandedMaxX = gridExpanded.isPosBoundaryInfinite(0)
94 // ? domainExpanded.getMaxRunBreak(0)
95 // : gridExpanded.getMaxIndex(0);
96 // hrleIndexType iteratedMinX = gridIterated.isNegBoundaryInfinite(0)
97 // ? domainIterated.getMinRunBreak(0)
98 // : gridIterated.getMinIndex(0);
99 // hrleIndexType iteratedMaxX = gridIterated.isPosBoundaryInfinite(0)
100 // ? domainIterated.getMaxRunBreak(0)
101 // : gridIterated.getMaxIndex(0);
102
103 // if (expandedMinX != iteratedMinX || expandedMaxX != iteratedMaxX) {
104 // Logger::getInstance()
105 // .addWarning("X extent mismatch in CompareSparseField. The x extents
106 // "
107 // "of both level sets must be equal.")
108 // .print();
109 // return false;
110 // }
111
112 // Check if expanded level set width is sufficient
113 if (levelSetExpanded->getLevelSetWidth() < expandedLevelSetWidth) {
114 VIENNACORE_LOG_WARNING(
115 "Expanded level set width is insufficient. It must have a width of "
116 "at least " +
117 std::to_string(expandedLevelSetWidth) + ". \n" +
118 " CORRECTION: The expansion was performed. \n"
119 "ALTERNATIVE: Alternatively, please expand the expanded yourself "
120 "using lsExpand before passing it to this function. \n");
121 Expand<T, D>(levelSetExpanded, expandedLevelSetWidth).apply();
122 }
123
124 // Reduce the iterated level set to a sparse field if necessary
125 if (levelSetIterated->getLevelSetWidth() > 1) {
126 VIENNACORE_LOG_WARNING(
127 "Iterated level set width is too large. It must be reduced to a "
128 "sparse field. \n"
129 " CORRECTION: The reduction was performed. \n"
130 "ALTERNATIVE: Alternatively, please reduce the iterated yourself "
131 "using lsReduce before passing it to this function. \n");
132 Reduce<T, D>(levelSetIterated, 1).apply();
133 }
134
135 return true;
136 }
137
138public:
140
141 CompareSparseField(SmartPointer<Domain<T, D>> passedLevelSetExpanded,
142 SmartPointer<Domain<T, D>> passedLevelSetIterated)
143 : levelSetExpanded(passedLevelSetExpanded),
144 levelSetIterated(passedLevelSetIterated) {}
145
146 void setLevelSetExpanded(SmartPointer<Domain<T, D>> passedLevelSet) {
147 levelSetExpanded = passedLevelSet;
148 }
149
150 void setLevelSetIterated(SmartPointer<Domain<T, D>> passedLevelSet) {
151 levelSetIterated = passedLevelSet;
152 }
153
155 void setXRange(T minXRange, T maxXRange) {
156 xRangeMin = minXRange;
157 xRangeMax = maxXRange;
158 useXRange = true;
159 }
160
162 void setYRange(T minYRange, T maxYRange) {
163 yRangeMin = minYRange;
164 yRangeMax = maxYRange;
165 useYRange = true;
166 }
167
169 void clearXRange() {
170 useXRange = false;
171 xRangeMin = std::numeric_limits<T>::lowest();
172 xRangeMax = std::numeric_limits<T>::max();
173 }
174
176 void clearYRange() {
177 useYRange = false;
178 yRangeMin = std::numeric_limits<T>::lowest();
179 yRangeMax = std::numeric_limits<T>::max();
180 }
181
183 void setZRange(T minZRange, T maxZRange) {
184 zRangeMin = minZRange;
185 zRangeMax = maxZRange;
186 useZRange = true;
187 }
188
190 void clearZRange() {
191 useZRange = false;
192 zRangeMin = std::numeric_limits<T>::lowest();
193 zRangeMax = std::numeric_limits<T>::max();
194 }
195
197 void setOutputMesh(SmartPointer<Mesh<T>> passedMesh) {
198 outputMesh = passedMesh;
199 }
200
203 fillIteratedWithDistances = fill;
204 }
205
209 void setExpandedLevelSetWidth(int width) {
210 if (width <= 0) {
211 VIENNACORE_LOG_WARNING(
212 "Expansion width must be positive. Using default value of 50.");
213 expandedLevelSetWidth = 50;
214 } else {
215 expandedLevelSetWidth = width;
216 }
217 }
218
220 void apply() {
221 // Perform compatibility checks
222 if (!checkAndCalculateBounds()) {
223 // If checks fail, return NaN
224 sumSquaredDifferences = std::numeric_limits<T>::quiet_NaN();
225 sumDifferences = std::numeric_limits<T>::quiet_NaN();
226 numPoints = 0;
227 numSkippedPoints = 0;
228 return;
229 }
230
231 const auto &gridExpanded = levelSetExpanded->getGrid();
232 const auto gridDelta = gridExpanded.getGridDelta();
233
234 sumSquaredDifferences = 0.0;
235 sumDifferences = 0.0;
236 numPoints = 0;
237 numSkippedPoints = 0;
238
239 // Direct storage for points and differences
240 std::vector<Vec3D<T>> nodeCoordinates; // 3D necessary for lsMesh
241 std::vector<std::array<unsigned, 1>> vertexIndices;
242 std::vector<T> differenceValues;
243 std::vector<T> squaredDifferenceValues;
244
245 // Prepare mesh output if needed
246 const bool generateMesh = outputMesh != nullptr;
247 if (generateMesh) {
248 outputMesh->clear();
249
250 // Initialize mesh extent
251 for (unsigned i = 0; i < 3; ++i) {
252 outputMesh->minimumExtent[i] =
253 (i < D) ? std::numeric_limits<T>::max() : 0.0;
254 outputMesh->maximumExtent[i] =
255 (i < D) ? std::numeric_limits<T>::lowest() : 0.0;
256 }
257
258 // Reserve space for mesh data
259 nodeCoordinates.reserve(levelSetIterated->getNumberOfPoints());
260 vertexIndices.reserve(levelSetIterated->getNumberOfPoints());
261 differenceValues.reserve(levelSetIterated->getNumberOfPoints());
262 squaredDifferenceValues.reserve(levelSetIterated->getNumberOfPoints());
263 }
264
265 // Prepare for point data filling if needed
266 auto &iteratedPointData = levelSetIterated->getPointData();
267 std::vector<T> pointDataDistances;
268 if (fillIteratedWithDistances) {
269 pointDataDistances.reserve(levelSetIterated->getNumberOfPoints());
270 }
271
272 // Create sparse iterators for the level sets
273 viennahrle::ConstSparseIterator<typename Domain<T, D>::DomainType>
274 itIterated(levelSetIterated->getDomain());
275 viennahrle::ConstSparseIterator<typename Domain<T, D>::DomainType>
276 itExpanded(levelSetExpanded->getDomain());
277
278 // Iterate over all defined points in the iterated level set
279 while (!itIterated.isFinished()) {
280 if (!itIterated.isDefined()) {
281 // this block is necessary to skip undefined points, I tested it:
282 // std::cout << "Skipping undefined point" << std::endl;
283 itIterated.next();
284 continue;
285 }
286
287 auto indices = itIterated.getStartIndices();
288
289 // Calculate coordinates
290 T xCoord = indices[0] * gridDelta;
291 T yCoord = indices[1] * gridDelta;
292 T zCoord = (D == 3) ? indices[2] * gridDelta
293 : 0.0; // Always use 0 for z-coordinate in 2D
294
295 // Skip if outside the specified x-range
296 if (useXRange && (xCoord < xRangeMin || xCoord > xRangeMax)) {
297 itIterated.next();
298 continue;
299 }
300
301 // Skip if outside the specified y-range
302 if (useYRange && (yCoord < yRangeMin || yCoord > yRangeMax)) {
303 itIterated.next();
304 continue;
305 }
306
307 // Skip if outside the specified z-range
308 if (D == 3 && useZRange && (zCoord < zRangeMin || zCoord > zRangeMax)) {
309 itIterated.next();
310 continue;
311 }
312
313 // Get iterated value
314 T valueIterated = itIterated.getValue();
315
316 itExpanded.goToIndicesSequential(indices);
317 T valueExpanded = itExpanded.getValue();
318
319 // Check for infinite or extreme values that might cause numerical
320 // issues
321 if (!itExpanded.isDefined() || std::isinf(valueExpanded) ||
322 std::isinf(valueIterated)) {
323 numSkippedPoints++;
324 itIterated.next();
325 continue;
326 }
327
328 // Calculate difference and add to sum
329 T diff = std::abs(valueExpanded - valueIterated) * gridDelta;
330 T diffSquared = diff * diff;
331 sumDifferences += diff;
332 sumSquaredDifferences += diffSquared;
333 numPoints++;
334
335 // Store difference in mesh if required
336 if (generateMesh) {
337 // Create a new point with the coordinates of the iterated level set
338 // point
339 Vec3D<T> coords{xCoord, yCoord, zCoord}; // lsMesh needs 3D
340
341 // Store the coordinates
342 nodeCoordinates.push_back(coords);
343
344 // Store the difference value (squared and absolute)
345 differenceValues.push_back(diff);
346 squaredDifferenceValues.push_back(diffSquared);
347
348 // Create a vertex for this point
349 std::array<unsigned, 1> vertex = {
350 static_cast<unsigned>(nodeCoordinates.size() - 1)};
351 vertexIndices.push_back(vertex);
352
353 // Update the mesh extent
354 for (unsigned i = 0; i < D; ++i) {
355 outputMesh->minimumExtent[i] =
356 std::min(outputMesh->minimumExtent[i], coords[i]);
357 outputMesh->maximumExtent[i] =
358 std::max(outputMesh->maximumExtent[i], coords[i]);
359 }
360 }
361
362 if (fillIteratedWithDistances) {
363 // Store the distance value in the point data
364 pointDataDistances.push_back(diff);
365 }
366 // Move to next point
367 itIterated.next();
368 }
369
370 // Finalize mesh output
371 if (generateMesh && !nodeCoordinates.empty()) {
372 // Store the node coordinates directly
373 outputMesh->nodes = std::move(nodeCoordinates);
374
375 // Store the vertices for point visualization
376 outputMesh->vertices = std::move(vertexIndices);
377
378 // Store the difference values as point data
379 outputMesh->pointData.insertNextScalarData(std::move(differenceValues),
380 "Absolute differences");
381 outputMesh->pointData.insertNextScalarData(
382 std::move(squaredDifferenceValues), "Squared differences");
383 }
384
385 if (fillIteratedWithDistances) {
386 iteratedPointData.insertNextScalarData(std::move(pointDataDistances),
387 "DistanceToExpanded");
388 }
389 }
390
392 T getSumSquaredDifferences() const { return sumSquaredDifferences; }
393
395 T getSumDifferences() const { return sumDifferences; }
396
398 unsigned getNumPoints() const { return numPoints; }
399
401 unsigned getNumSkippedPoints() const { return numSkippedPoints; }
402
404 T getRMSE() const {
405 return (numPoints > 0) ? std::sqrt(sumSquaredDifferences / numPoints)
406 : std::numeric_limits<T>::infinity();
407 }
408};
409
410// Add template specializations for this class
411PRECOMPILE_PRECISION_DIMENSION(CompareSparseField)
412
413} // namespace viennals
constexpr int D
Definition Epitaxy.cpp:11
double T
Definition Epitaxy.cpp:12
unsigned getNumPoints() const
Return the number of points used in the comparison.
Definition lsCompareSparseField.hpp:398
T getRMSE() const
Calculate the root mean square error from previously computed values.
Definition lsCompareSparseField.hpp:404
CompareSparseField()
Definition lsCompareSparseField.hpp:139
CompareSparseField(SmartPointer< Domain< T, D > > passedLevelSetExpanded, SmartPointer< Domain< T, D > > passedLevelSetIterated)
Definition lsCompareSparseField.hpp:141
void setXRange(T minXRange, T maxXRange)
Set the x-coordinate range to restrict the comparison area.
Definition lsCompareSparseField.hpp:155
void setExpandedLevelSetWidth(int width)
Set the expansion width for the expanded level set This value will be used if the expanded level set ...
Definition lsCompareSparseField.hpp:209
void setOutputMesh(SmartPointer< Mesh< T > > passedMesh)
Set the output mesh where difference values will be stored.
Definition lsCompareSparseField.hpp:197
void setLevelSetIterated(SmartPointer< Domain< T, D > > passedLevelSet)
Definition lsCompareSparseField.hpp:150
unsigned getNumSkippedPoints() const
Return the number of skipped points during the comparison.
Definition lsCompareSparseField.hpp:401
void setYRange(T minYRange, T maxYRange)
Set the y-coordinate range to restrict the comparison area.
Definition lsCompareSparseField.hpp:162
void setLevelSetExpanded(SmartPointer< Domain< T, D > > passedLevelSet)
Definition lsCompareSparseField.hpp:146
void setFillIteratedWithDistances(bool fill)
Set whether to fill the iterated level set with distances.
Definition lsCompareSparseField.hpp:202
T getSumSquaredDifferences() const
Return the sum of squared differences calculated by apply().
Definition lsCompareSparseField.hpp:392
T getSumDifferences() const
Return the sum of differences calculated by apply().
Definition lsCompareSparseField.hpp:395
void clearZRange()
Clear the z-range restriction.
Definition lsCompareSparseField.hpp:190
void clearYRange()
Clear the y-range restriction.
Definition lsCompareSparseField.hpp:176
void apply()
Apply the comparison and calculate the sum of squared differences.
Definition lsCompareSparseField.hpp:220
void clearXRange()
Clear the x-range restriction.
Definition lsCompareSparseField.hpp:169
void setZRange(T minZRange, T maxZRange)
Set the z-coordinate range to restrict the comparison area.
Definition lsCompareSparseField.hpp:183
Class containing all information about the level set, including the dimensions of the domain,...
Definition lsDomain.hpp:28
Expands the levelSet to the specified number of layers. The largest value in the levelset is thus wid...
Definition lsExpand.hpp:17
void apply()
Apply the expansion to the specified width.
Definition lsExpand.hpp:44
This class holds an explicit mesh, which is always given in 3 dimensions. If it describes a 2D mesh,...
Definition lsMesh.hpp:22
Reduce the level set size to the specified width. This means all level set points with value <= 0....
Definition lsReduce.hpp:14
void apply()
Reduces the leveleSet to the specified number of layers. The largest value in the levelset is thus wi...
Definition lsReduce.hpp:55
#define PRECOMPILE_PRECISION_DIMENSION(className)
Definition lsPreCompileMacros.hpp:24
Definition lsAdvect.hpp:41