ViennaLS
Loading...
Searching...
No Matches
lsCompareArea.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <limits>
4#include <unordered_map>
5
6#include <hrleDenseCellIterator.hpp>
7#include <lsDomain.hpp>
8#include <lsMesh.hpp>
10
11namespace viennals {
12
13using namespace viennacore;
14
23template <class T, int D = 2> class CompareArea {
24 using hrleDomainType = typename Domain<T, D>::DomainType;
25 using hrleIndexType = viennahrle::IndexType;
26
27 SmartPointer<Domain<T, D>> levelSetTarget = nullptr;
28 SmartPointer<Domain<T, D>> levelSetSample = nullptr;
29 viennahrle::Index<D> minIndex, maxIndex;
30
31 unsigned long int differentCellsCount = 0;
32 unsigned long int customDifferentCellCount = 0;
33
34 hrleIndexType xRangeMin = std::numeric_limits<hrleIndexType>::lowest();
35 hrleIndexType xRangeMax = std::numeric_limits<hrleIndexType>::max();
36 hrleIndexType yRangeMin = std::numeric_limits<hrleIndexType>::lowest();
37 hrleIndexType yRangeMax = std::numeric_limits<hrleIndexType>::max();
38 bool useCustomXIncrement = false;
39 bool useCustomYIncrement = false;
40
41 unsigned short int customXIncrement = 0;
42 unsigned short int customYIncrement = 0;
43 unsigned short int defaultIncrement = 1;
44
45 double gridDelta = 0.0;
46
47 // Mesh output related members
48 SmartPointer<Mesh<T>> outputMesh = nullptr;
49
50 bool checkAndCalculateBounds() {
51 if (levelSetTarget == nullptr || levelSetSample == nullptr) {
52 Logger::getInstance()
53 .addError("Missing level set in CompareArea.")
54 .print();
55 return false;
56 }
57
58 // Check if the grids are compatible
59 const auto &gridTarget = levelSetTarget->getGrid();
60 const auto &gridSample = levelSetSample->getGrid();
61
62 if (gridTarget.getGridDelta() != gridSample.getGridDelta()) {
63 Logger::getInstance()
64 .addError("Grid delta mismatch in CompareArea. The grid deltas of "
65 "the two level sets must be equal.")
66 .print();
67 return false;
68 } else {
69 gridDelta = gridTarget.getGridDelta();
70 }
71
72 // Initialize min and max indices
73 for (unsigned i = 0; i < D; ++i) {
74 minIndex[i] = std::numeric_limits<hrleIndexType>::max();
75 maxIndex[i] = std::numeric_limits<hrleIndexType>::lowest();
76 }
77
78 // Get the boundaries of the two level sets
79 auto &domainTarget = levelSetTarget->getDomain();
80 auto &domainSample = levelSetSample->getDomain();
81
82 // Calculate actual bounds
83 for (unsigned i = 0; i < D; ++i) {
84 minIndex[i] = std::min({minIndex[i],
85 (gridTarget.isNegBoundaryInfinite(i))
86 ? domainTarget.getMinRunBreak(i)
87 : gridTarget.getMinBounds(i),
88 (gridSample.isNegBoundaryInfinite(i))
89 ? domainSample.getMinRunBreak(i)
90 : gridSample.getMinBounds(i)});
91
92 maxIndex[i] = std::max({maxIndex[i],
93 (gridTarget.isPosBoundaryInfinite(i))
94 ? domainTarget.getMaxRunBreak(i)
95 : gridTarget.getMaxBounds(i),
96 (gridSample.isPosBoundaryInfinite(i))
97 ? domainSample.getMaxRunBreak(i)
98 : gridSample.getMaxBounds(i)});
99 }
100
101 return true;
102 }
103
104public:
106 assert(D == 2 &&
107 "CompareArea is currently only implemented for 2D level sets.");
108 }
109
110 CompareArea(SmartPointer<Domain<T, D>> passedLevelSetTarget,
111 SmartPointer<Domain<T, D>> passedLevelSetSample)
112 : levelSetTarget(passedLevelSetTarget),
113 levelSetSample(passedLevelSetSample) {
114 assert(D == 2 &&
115 "CompareArea is currently only implemented for 2D level sets.");
116 }
117
119 void setLevelSetTarget(SmartPointer<Domain<T, D>> passedLevelSet) {
120 levelSetTarget = passedLevelSet;
121 }
122
124 void setLevelSetSample(SmartPointer<Domain<T, D>> passedLevelSet) {
125 levelSetSample = passedLevelSet;
126 }
127
129 void setDefaultIncrement(unsigned short int increment) {
130 defaultIncrement = increment;
131 }
132
134 void setXRangeAndIncrement(hrleIndexType minXRange, hrleIndexType maxXRange,
135 unsigned short int Xincrement) {
136 xRangeMin = minXRange;
137 xRangeMax = maxXRange;
138 customXIncrement = Xincrement;
139 useCustomXIncrement = true;
140 }
141
143 void setYRangeAndIncrement(hrleIndexType minYRange, hrleIndexType maxYRange,
144 unsigned short int Yincrement) {
145 yRangeMin = minYRange;
146 yRangeMax = maxYRange;
147 customYIncrement = Yincrement;
148 useCustomYIncrement = true;
149 }
150
155 void setOutputMesh(SmartPointer<Mesh<T>> passedMesh) {
156 outputMesh = passedMesh;
157 }
158
160 double getAreaMismatch() const {
161 return static_cast<double>(differentCellsCount) * gridDelta * gridDelta;
162 }
163
165 double getCustomAreaMismatch() const {
166 return static_cast<double>(customDifferentCellCount) * gridDelta *
167 gridDelta;
168 }
169
171 unsigned long int getCellCount() const { return differentCellsCount; }
172
175 unsigned long int getCustomCellCount() const {
176 return customDifferentCellCount;
177 }
178
180 void apply() {
181 // Calculate the bounds for iteration
182 if (!checkAndCalculateBounds()) {
183 differentCellsCount =
184 std::numeric_limits<unsigned long int>::max(); // Error indicator
185 customDifferentCellCount =
186 std::numeric_limits<unsigned long int>::max(); // Error indicator
187 return;
188 }
189
190 // Set up dense cell iterators for both level sets
191 viennahrle::ConstDenseCellIterator<hrleDomainType> itTarget(
192 levelSetTarget->getDomain(), minIndex);
193 viennahrle::ConstDenseCellIterator<hrleDomainType> itSample(
194 levelSetSample->getDomain(), minIndex);
195
196 differentCellsCount = 0;
197 customDifferentCellCount = 0;
198
199 // Initialize mesh-related variables if generating a mesh
200 const bool generateMesh = outputMesh != nullptr;
201 if (generateMesh) {
202 // Save the extent of the resulting mesh
203 outputMesh->clear();
204 for (unsigned i = 0; i < D; ++i) {
205 outputMesh->minimumExtent[i] = std::numeric_limits<T>::max();
206 outputMesh->maximumExtent[i] = std::numeric_limits<T>::lowest();
207 }
208 }
209
210 // Vector for cell differences and increment values to be inserted in the
211 // mesh
212 std::vector<T> cellDifference;
213 std::vector<T> incrementValues;
214 size_t currentPointId = 0;
215 std::unordered_map<viennahrle::Index<D>, size_t,
216 typename viennahrle::Index<D>::hash>
217 pointIdMapping;
218
219 // Iterate through the domain defined by the bounding box
220 for (; itTarget.getIndices() < maxIndex; itTarget.next()) {
221 itSample.goToIndicesSequential(itTarget.getIndices());
222
223 // Compare cell values at the current position
224 T centerValueTarget = 0.;
225 T centerValueSample = 0.;
226
227 // Calculate the average value of the corners for both level sets
228 for (int i = 0; i < (1 << D); ++i) {
229 centerValueTarget += itTarget.getCorner(i).getValue();
230 centerValueSample += itSample.getCorner(i).getValue();
231 }
232 centerValueTarget /= (1 << D);
233 centerValueSample /= (1 << D);
234
235 // Determine if cell is inside for each level set
236 bool insideTarget = (centerValueTarget <= 0.);
237 bool insideSample = (centerValueSample <= 0.);
238 bool isDifferent = insideTarget != insideSample;
239
240 // Calculate range checks once per cell
241 bool inXRange = useCustomXIncrement &&
242 (itTarget.getIndices()[0] * gridDelta >= xRangeMin &&
243 itTarget.getIndices()[0] * gridDelta <= xRangeMax);
244 bool inYRange = useCustomYIncrement &&
245 (itTarget.getIndices()[1] * gridDelta >= yRangeMin &&
246 itTarget.getIndices()[1] * gridDelta <= yRangeMax);
247
248 // Calculate increment to add based on ranges
249 unsigned short int incrementToAdd = defaultIncrement;
250 if (inXRange && inYRange) {
251 // Apply both increments
252 incrementToAdd = customXIncrement + customYIncrement;
253 } else if (inXRange) {
254 incrementToAdd = customXIncrement;
255 } else if (inYRange) {
256 incrementToAdd = customYIncrement;
257 }
258
259 // If cells differ, update the counters
260 if (isDifferent) {
261 // Always increment simple cell count by 1
262 differentCellsCount += 1;
263
264 // For custom cell count, apply the calculated increment
265 customDifferentCellCount += incrementToAdd;
266 }
267
268 // For mesh generation, process all cells where at least one level set is
269 // inside
270 if (generateMesh && (insideTarget || insideSample)) {
271 // Material ID: 0 for matching inside, 1 for mismatched
272 int difference = isDifferent ? 1 : 0;
273
274 std::array<unsigned, 1 << D> voxel;
275 bool addVoxel = true;
276 // TODO: I think this check whether Voxel is added or not can be removed
277
278 // Insert all points of voxel into pointList
279 for (unsigned i = 0; i < (1 << D); ++i) {
280 viennahrle::Index<D> index;
281 for (unsigned j = 0; j < D; ++j) {
282 index[j] =
283 itTarget.getIndices(j) + itTarget.getCorner(i).getOffset()[j];
284 if (index[j] > maxIndex[j]) {
285 addVoxel = false;
286 break;
287 }
288 }
289 if (addVoxel) {
290 auto pointIdValue = std::make_pair(index, currentPointId);
291 auto pointIdPair = pointIdMapping.insert(pointIdValue);
292 voxel[i] = pointIdPair.first->second;
293 if (pointIdPair.second) {
294 ++currentPointId;
295 }
296 } else {
297 break;
298 }
299 }
300
301 if (addVoxel) {
302 if constexpr (D == 3) {
303 std::array<unsigned, 8> hexa{voxel[0], voxel[1], voxel[3],
304 voxel[2], voxel[4], voxel[5],
305 voxel[7], voxel[6]};
306 outputMesh->hexas.push_back(hexa);
307 } else if constexpr (D == 2) {
308 std::array<unsigned, 4> quad{voxel[0], voxel[1], voxel[3],
309 voxel[2]};
310 outputMesh->tetras.push_back(quad);
311 }
312
313 cellDifference.push_back(difference);
314
315 // Store increment value (0 if not different)
316 incrementValues.push_back(isDifferent ? static_cast<T>(incrementToAdd)
317 : 0);
318 }
319 }
320 }
321
322 // Finalize mesh if generating one
323 if (generateMesh && !pointIdMapping.empty()) {
324 // Insert points into the mesh
325 outputMesh->nodes.resize(pointIdMapping.size());
326 for (auto it = pointIdMapping.begin(); it != pointIdMapping.end(); ++it) {
327 Vec3D<T> coords;
328 for (unsigned i = 0; i < D; ++i) {
329 coords[i] = gridDelta * it->first[i];
330
331 if (coords[i] < outputMesh->minimumExtent[i]) {
332 outputMesh->minimumExtent[i] = coords[i];
333 } else if (coords[i] > outputMesh->maximumExtent[i]) {
334 outputMesh->maximumExtent[i] = coords[i];
335 }
336 }
337 outputMesh->nodes[it->second] = coords;
338 }
339
340 // Add cell data to the mesh
341 assert(cellDifference.size() == incrementValues.size());
342 assert(incrementValues.size() ==
343 outputMesh->template getElements<1 << D>().size());
344 outputMesh->cellData.insertNextScalarData(cellDifference, "Difference");
345 outputMesh->cellData.insertNextScalarData(incrementValues,
346 "CustomIncrement");
347 }
348 }
349};
350
351// Precompile for common precision and dimensions
353
354} // namespace viennals
constexpr int D
Definition Epitaxy.cpp:9
double T
Definition Epitaxy.cpp:10
CompareArea(SmartPointer< Domain< T, D > > passedLevelSetTarget, SmartPointer< Domain< T, D > > passedLevelSetSample)
Definition lsCompareArea.hpp:110
unsigned long int getCustomCellCount() const
Returns the number of cells where the level sets differ, with custom increments applied.
Definition lsCompareArea.hpp:175
void setXRangeAndIncrement(hrleIndexType minXRange, hrleIndexType maxXRange, unsigned short int Xincrement)
Sets the x-range and custom increment value.
Definition lsCompareArea.hpp:134
void setLevelSetTarget(SmartPointer< Domain< T, D > > passedLevelSet)
Sets the target level set.
Definition lsCompareArea.hpp:119
unsigned long int getCellCount() const
Returns the number of cells where the level sets differ.
Definition lsCompareArea.hpp:171
double getCustomAreaMismatch() const
Returns the computed area mismatch, with custom increments applied.
Definition lsCompareArea.hpp:165
void setLevelSetSample(SmartPointer< Domain< T, D > > passedLevelSet)
Sets the sample level set.
Definition lsCompareArea.hpp:124
void apply()
Computes the area difference between the two level sets.
Definition lsCompareArea.hpp:180
void setOutputMesh(SmartPointer< Mesh< T > > passedMesh)
Set the output mesh where difference areas will be stored for visualization. Each cell in the mesh wi...
Definition lsCompareArea.hpp:155
void setDefaultIncrement(unsigned short int increment)
Set default increment value.
Definition lsCompareArea.hpp:129
void setYRangeAndIncrement(hrleIndexType minYRange, hrleIndexType maxYRange, unsigned short int Yincrement)
Sets the y-range and custom increment value.
Definition lsCompareArea.hpp:143
double getAreaMismatch() const
Returns the computed area mismatch.
Definition lsCompareArea.hpp:160
CompareArea()
Definition lsCompareArea.hpp:105
Class containing all information about the level set, including the dimensions of the domain,...
Definition lsDomain.hpp:27
viennahrle::Domain< T, D > DomainType
Definition lsDomain.hpp:32
This class holds an explicit mesh, which is always given in 3 dimensions. If it describes a 2D mesh,...
Definition lsMesh.hpp:22
#define PRECOMPILE_PRECISION_DIMENSION(className)
Definition lsPreCompileMacros.hpp:24
Definition lsAdvect.hpp:36