ViennaLS
Loading...
Searching...
No Matches
lsInterior.hpp
Go to the documentation of this file.
1#pragma once
2
4
5#include <hrleSparseIterator.hpp>
6#include <hrleSparseStarIterator.hpp>
7#include <lsDomain.hpp>
8
9#include <vcVectorType.hpp>
10
11namespace viennals {
12
13using namespace viennacore;
14
18template <class T, int D> class Interior {
19 SmartPointer<Domain<T, D>> levelSet = nullptr;
20 SmartPointer<Domain<T, D>> guide = nullptr;
21 int width = 0;
22 bool updatePointData = true;
23
24public:
25 Interior() = default;
26
27 Interior(SmartPointer<Domain<T, D>> passedlsDomain)
28 : levelSet(passedlsDomain) {}
29
30 void setLevelSet(SmartPointer<Domain<T, D>> passedlsDomain) {
31 levelSet = passedlsDomain;
32 }
33
37 void setGuide(SmartPointer<Domain<T, D>> g) { guide = g; }
38
41 void setUpdatePointData(bool update) { updatePointData = update; }
42
44 void apply() {
45 if (levelSet == nullptr) {
46 Logger::getInstance()
47 .addError("No level set passed to Interior. Not activating.")
48 .print();
49 return;
50 }
51
52 if (levelSet->getNumberOfPoints() == 0)
53 return;
54
55 const int startWidth = levelSet->getLevelSetWidth();
56
57 for (int currentCycle = 0; currentCycle < 100; ++currentCycle) {
58 int addedPoints = 0;
59
60 const T limit = (startWidth + currentCycle + 1);
61
62 auto &grid = levelSet->getGrid();
63 auto newlsDomain = SmartPointer<Domain<T, D>>::New(grid);
64 auto &newDomain = newlsDomain->getDomain();
65 auto &domain = levelSet->getDomain();
66
67 newDomain.initialize(domain.getNewSegmentation(), domain.getAllocation());
68
69 const bool updateData = updatePointData;
70 // save how data should be transferred to new level set
71 // list of indices into the old pointData vector
72 std::vector<std::vector<unsigned>> newDataSourceIds;
73 if (updateData)
74 newDataSourceIds.resize(newDomain.getNumberOfSegments());
75
76#pragma omp parallel num_threads(newDomain.getNumberOfSegments()) \
77 reduction(+ : addedPoints)
78 {
79 int p = 0;
80#ifdef _OPENMP
81 p = omp_get_thread_num();
82#endif
83
84 auto &domainSegment = newDomain.getDomainSegment(p);
85
86 viennahrle::Index<D> const startVector =
87 (p == 0) ? grid.getMinGridPoint()
88 : newDomain.getSegmentation()[p - 1];
89
90 viennahrle::Index<D> const endVector =
91 (p != static_cast<int>(newDomain.getNumberOfSegments() - 1))
92 ? newDomain.getSegmentation()[p]
93 : grid.incrementIndices(grid.getMaxGridPoint());
94
95 // Per-thread guide iterator: advances in lock-step with main iterator.
96 using GuideIt =
97 viennahrle::ConstSparseIterator<typename Domain<T, D>::DomainType>;
98 std::unique_ptr<GuideIt> guideIt;
99 if (guide != nullptr)
100 guideIt = std::make_unique<GuideIt>(guide->getDomain(), startVector);
101
102 for (viennahrle::ConstSparseStarIterator<
103 typename Domain<T, D>::DomainType, 1>
104 neighborIt(domain, startVector);
105 neighborIt.getIndices() < endVector; neighborIt.next()) {
106
107 auto &centerIt = neighborIt.getCenter();
108
109 // If a guide is set, block activation for points inside it (φ < 0).
110 bool insideGuide = false;
111 if (guideIt) {
112 guideIt->goToIndicesSequential(neighborIt.getIndices());
113 insideGuide = (guideIt->getValue() < T(0));
114 }
115
116 if (centerIt.getValue() == Domain<T, D>::NEG_VALUE) {
117 // Interior/negative side. Track the best *defined* neighbor
118 // separately: undefined sentinels (POS_VALUE / NEG_VALUE) must
119 // not be used as pointData sources — getPointId() on an
120 // undefined run returns an invalid index.
121 T distance = Domain<T, D>::NEG_VALUE;
122 T definedDistance = Domain<T, D>::NEG_VALUE;
123 int definedNeighbor = -1;
124 for (int i = 0; i < 2 * D; i++) {
125 auto &nb = neighborIt.getNeighbor(i);
126 T newValue = nb.getValue() - T(1);
127 if (distance < newValue)
128 distance = newValue;
129 if (nb.isDefined() && definedDistance < newValue) {
130 definedDistance = newValue;
131 definedNeighbor = i;
132 }
133 }
134 // Only activate when a proper defined neighbor drives the fill
135 // and the point is not inside the guide (e.g. Si substrate).
136 if (!insideGuide && definedDistance >= -limit &&
137 definedNeighbor != -1) {
138 addedPoints++;
139 domainSegment.insertNextDefinedPoint(neighborIt.getIndices(),
140 definedDistance);
141 if (updateData)
142 newDataSourceIds[p].push_back(
143 neighborIt.getNeighbor(definedNeighbor).getPointId());
144 } else {
145 // insertNextUndefinedRunType
146 domainSegment.insertNextUndefinedPoint(neighborIt.getIndices(),
148 }
149 } else if (centerIt.getValue() == Domain<T, D>::POS_VALUE) {
150 // Ignore positive phi values (exterior region)
151 domainSegment.insertNextUndefinedPoint(neighborIt.getIndices(),
153 } else {
154 domainSegment.insertNextDefinedPoint(neighborIt.getIndices(),
155 centerIt.getValue());
156 if (updateData)
157 newDataSourceIds[p].push_back(centerIt.getPointId());
158 }
159 }
160 }
161
162 // now copy old data into new level set
163 if (updateData) {
164 newlsDomain->getPointData().translateFromMultiData(
165 levelSet->getPointData(), newDataSourceIds);
166 }
167
168 newDomain.finalize();
169 levelSet->deepCopy(newlsDomain);
170 if (addedPoints == 0)
171 break;
172 }
173 // segment() is intentionally skipped here. When the Interior fill
174 // produces a dense HRLE (many small runs from a deep fill), the
175 // balanced-partition boundaries computed by getNewSegmentation() land
176 // in the middle of existing runs. The SparseIterator inside segment()
177 // then starts at the run's true beginning (before the boundary), causing
178 // adjacent threads to overlap and producing a corrupt multi-segment domain
179 // that goToIndices later walks off. The single-segment domain left by
180 // the final finalize()+deepCopy() is valid for all downstream consumers:
181 // ConstSparseIterator in buildNodes(), writePersistentFields(), and
182 // lsAdvect (which re-segments its output internally).
183 }
184};
185
186// add all template specialisations for this class
188
189} // namespace viennals
constexpr int D
Definition Epitaxy.cpp:12
double T
Definition Epitaxy.cpp:13
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
static constexpr T NEG_VALUE
Definition lsDomain.hpp:52
static constexpr T POS_VALUE
Definition lsDomain.hpp:51
void setLevelSet(SmartPointer< Domain< T, D > > passedlsDomain)
Definition lsInterior.hpp:30
void setGuide(SmartPointer< Domain< T, D > > g)
Set a guide level set: the fill will not activate points that are inside the guide (φ_guide < 0)....
Definition lsInterior.hpp:37
void apply()
Apply the interior definition until no more points can be added.
Definition lsInterior.hpp:44
void setUpdatePointData(bool update)
Set whether to update the point data stored in the LS during this algorithm. Defaults to true.
Definition lsInterior.hpp:41
Interior(SmartPointer< Domain< T, D > > passedlsDomain)
Definition lsInterior.hpp:27
#define PRECOMPILE_PRECISION_DIMENSION(className)
Definition lsPreCompileMacros.hpp:24
Definition lsAdvect.hpp:41