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