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 for reduction(+ : addedPoints)
77 for (unsigned p = 0; p < newDomain.getNumberOfSegments(); ++p) {
78 auto &domainSegment = newDomain.getDomainSegment(p);
79
80 viennahrle::Index<D> const startVector =
81 (p == 0) ? grid.getMinGridPoint()
82 : newDomain.getSegmentation()[p - 1];
83
84 viennahrle::Index<D> const endVector =
85 (p != static_cast<int>(newDomain.getNumberOfSegments() - 1))
86 ? newDomain.getSegmentation()[p]
87 : grid.incrementIndices(grid.getMaxGridPoint());
88
89 // Per-thread guide iterator: advances in lock-step with main iterator.
90 using GuideIt =
91 viennahrle::ConstSparseIterator<typename Domain<T, D>::DomainType>;
92 std::unique_ptr<GuideIt> guideIt;
93 if (guide != nullptr)
94 guideIt = std::make_unique<GuideIt>(guide->getDomain(), startVector);
95
96 for (viennahrle::ConstSparseStarIterator<
97 typename Domain<T, D>::DomainType, 1>
98 neighborIt(domain, startVector);
99 neighborIt.getIndices() < endVector; neighborIt.next()) {
100
101 auto &centerIt = neighborIt.getCenter();
102
103 // If a guide is set, block activation for points inside it (φ < 0).
104 bool insideGuide = false;
105 if (guideIt) {
106 guideIt->goToIndicesSequential(neighborIt.getIndices());
107 insideGuide = (guideIt->getValue() < T(0));
108 }
109
110 if (centerIt.getValue() == Domain<T, D>::NEG_VALUE) {
111 // Interior/negative side. Track the best *defined* neighbor
112 // separately: undefined sentinels (POS_VALUE / NEG_VALUE) must
113 // not be used as pointData sources — getPointId() on an
114 // undefined run returns an invalid index.
115 T distance = Domain<T, D>::NEG_VALUE;
116 T definedDistance = Domain<T, D>::NEG_VALUE;
117 int definedNeighbor = -1;
118 for (int i = 0; i < 2 * D; i++) {
119 auto &nb = neighborIt.getNeighbor(i);
120 T newValue = nb.getValue() - T(1);
121 if (distance < newValue)
122 distance = newValue;
123 if (nb.isDefined() && definedDistance < newValue) {
124 definedDistance = newValue;
125 definedNeighbor = i;
126 }
127 }
128 // Only activate when a proper defined neighbor drives the fill
129 // and the point is not inside the guide (e.g. Si substrate).
130 if (!insideGuide && definedDistance >= -limit &&
131 definedNeighbor != -1) {
132 addedPoints++;
133 domainSegment.insertNextDefinedPoint(neighborIt.getIndices(),
134 definedDistance);
135 if (updateData)
136 newDataSourceIds[p].push_back(
137 neighborIt.getNeighbor(definedNeighbor).getPointId());
138 } else {
139 // insertNextUndefinedRunType
140 domainSegment.insertNextUndefinedPoint(neighborIt.getIndices(),
142 }
143 } else if (centerIt.getValue() == Domain<T, D>::POS_VALUE) {
144 // Ignore positive phi values (exterior region)
145 domainSegment.insertNextUndefinedPoint(neighborIt.getIndices(),
147 } else {
148 domainSegment.insertNextDefinedPoint(neighborIt.getIndices(),
149 centerIt.getValue());
150 if (updateData)
151 newDataSourceIds[p].push_back(centerIt.getPointId());
152 }
153 }
154 }
155
156 // now copy old data into new level set
157 if (updateData) {
158 newlsDomain->getPointData().translateFromMultiData(
159 levelSet->getPointData(), newDataSourceIds);
160 }
161
162 newDomain.finalize();
163 levelSet->deepCopy(newlsDomain);
164 if (addedPoints == 0)
165 break;
166 }
167 // segment() is intentionally skipped here. When the Interior fill
168 // produces a dense HRLE (many small runs from a deep fill), the
169 // balanced-partition boundaries computed by getNewSegmentation() land
170 // in the middle of existing runs. The SparseIterator inside segment()
171 // then starts at the run's true beginning (before the boundary), causing
172 // adjacent threads to overlap and producing a corrupt multi-segment domain
173 // that goToIndices later walks off. The single-segment domain left by
174 // the final finalize()+deepCopy() is valid for all downstream consumers:
175 // ConstSparseIterator in buildNodes(), writePersistentFields(), and
176 // lsAdvect (which re-segments its output internally).
177 }
178};
179
180// add all template specialisations for this class
182
183} // 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