5#include <hrleSparseIterator.hpp>
19using namespace viennacore;
31 static_assert(
D == 2 ||
D == 3);
32 constexpr unsigned bits =
D == 3 ? 21 : 32;
33 constexpr std::uint64_t mask = (std::uint64_t(1) << bits) - 1;
34 constexpr std::int64_t offset = std::int64_t(1) << (bits - 1);
35 std::uint64_t key = 0;
36 for (
unsigned i = 0; i < static_cast<unsigned>(
D); ++i)
37 key = (key << bits) | (
static_cast<std::uint64_t
>(
38 static_cast<std::int64_t
>(index[i]) + offset) &
40 return static_cast<std::size_t
>(key);
45 std::size_t
operator()(
const viennahrle::Index<D> &idx)
const {
50template <
class T>
inline Vec3D<T>
vecScaled(
const Vec3D<T> &source,
T factor) {
51 Vec3D<T> result{0., 0., 0.};
52 for (
unsigned i = 0; i < 3; ++i)
53 result[i] = source[i] * factor;
58inline Vec3D<T>
vecAdd(
const Vec3D<T> &a,
const Vec3D<T> &b) {
59 Vec3D<T> result{0., 0., 0.};
60 for (
unsigned i = 0; i < 3; ++i)
61 result[i] = a[i] + b[i];
66inline Vec3D<T>
vecSubtract(
const Vec3D<T> &a,
const Vec3D<T> &b) {
67 Vec3D<T> result{0., 0., 0.};
68 for (
unsigned i = 0; i < 3; ++i)
69 result[i] = a[i] - b[i];
74inline void vecAddTo(Vec3D<T> &target,
const Vec3D<T> &source) {
75 for (
unsigned i = 0; i < 3; ++i)
76 target[i] += source[i];
82 return v >
T(1) ?
T(1) : (v <
T(-1) ?
T(-1) : v);
88 const T denom = std::abs(insidePhi) + std::abs(outsidePhi);
89 if (denom <= std::numeric_limits<T>::epsilon())
91 return std::max(minBoundaryFraction *
gridDelta,
104 viennahrle::ConstSparseIterator<typename Domain<T, D>::DomainType>;
106 static constexpr std::size_t
noNode = std::numeric_limits<std::size_t>::max();
118 for (
unsigned i = 0; i <
D; ++i) {
119 const bool reflective = grid.getBoundaryConditions(i) ==
120 viennahrle::BoundaryType::REFLECTIVE_BOUNDARY;
132 neighbor[direction] += offset;
137 opposite[direction] -= offset;
138 return inBounds(opposite) ? -offset : offset;
151 constexpr T eps =
T(1e-9);
152 return (a <= eps && b >= -eps) || (a >= -eps && b <= eps);
156 it.goToIndices(index);
157 return it.getValue();
169 template <
class OnGr
id>
172 OnGrid onGrid)
const {
175 auto sample = [&](
const IndexType &idx,
T &value) {
178 it.goToIndices(ok ? q : index);
179 value = it.getValue();
180 return ok && it.isDefined() && std::isfinite(value);
183 const bool centreDefined = sample(index, centre);
184 Vec3D<T> gradient{
T(0),
T(0),
T(0)};
185 for (
unsigned d = 0; d <
D; ++d) {
189 T vp =
T(0), vm =
T(0);
190 const bool okP = sample(plus, vp), okM = sample(minus, vm);
192 gradient[d] =
T(0.5) * (vp - vm);
193 else if (centreDefined && okP)
194 gradient[d] = vp - centre;
195 else if (centreDefined && okM)
196 gradient[d] = centre - vm;
205 for (
unsigned i = 0; i <
D; ++i)
212 std::size_t total = 1;
213 for (
unsigned i = 0; i <
D; ++i)
226 return std::numeric_limits<std::size_t>::max();
227 std::size_t result = 0;
228 for (
unsigned i = 0; i <
D; ++i)
229 result +=
static_cast<std::size_t
>(index[i] -
minIndex[i]) *
strides[i];
234 for (
unsigned i = 0; i <
D; ++i) {
248 for (
int radius = 1; radius <= 4; ++radius) {
249 T bestDistance2 = std::numeric_limits<T>::max();
250 std::size_t bestNode = std::numeric_limits<std::size_t>::max();
253 offset.fill(-radius);
257 for (
unsigned i = 0; i <
D; ++i) {
258 candidate[i] += offset[i];
259 distance2 +=
static_cast<T>(offset[i] * offset[i]);
262 if (distance2 > 0 &&
inBounds(candidate)) {
264 if (foundId !=
noNode && distance2 < bestDistance2) {
265 bestDistance2 = distance2;
271 for (; dim <
D; ++dim) {
272 if (offset[dim] < radius) {
276 offset[dim] = -radius;
282 if (bestNode != std::numeric_limits<std::size_t>::max())
285 return std::numeric_limits<std::size_t>::max();
293 template <
class Accept>
295 Accept accept)
const {
296 std::vector<std::size_t> best;
297 for (
int radius = 1; radius <= 4 && best.empty(); ++radius) {
298 long bestDistance2 = std::numeric_limits<long>::max();
300 offset.fill(-radius);
304 for (
unsigned i = 0; i <
D; ++i) {
305 candidate[i] += offset[i];
306 distance2 +=
static_cast<long>(offset[i]) * offset[i];
308 if (distance2 > 0 && distance2 <= bestDistance2 &&
311 if (foundId !=
noNode && accept(foundId)) {
312 if (distance2 < bestDistance2) {
314 bestDistance2 = distance2;
316 best.push_back(foundId);
320 for (; dim <
D; ++dim) {
321 if (offset[dim] < radius) {
325 offset[dim] = -radius;
337 SmartPointer<
Domain<T, D>> maskInterface,
bool useRequestedBounds,
339 std::size_t maxGridPoints,
const std::string &solverName) {
340 auto &reactionGrid = reactionInterface->getGrid();
341 auto &ambientGrid = ambientInterface->getGrid();
344 if (std::abs(
gridDelta - ambientGrid.getGridDelta()) >
345 std::numeric_limits<T>::epsilon() ||
346 (maskInterface !=
nullptr &&
347 std::abs(
gridDelta - maskInterface->getGrid().getGridDelta()) >
348 std::numeric_limits<T>::epsilon())) {
349 Logger::getInstance()
350 .addError(solverName +
": Interface grid deltas must match.")
355 IndexType gridMin = reactionGrid.getMinGridPoint();
356 IndexType gridMax = reactionGrid.getMaxGridPoint();
357 for (
unsigned i = 0; i <
D; ++i) {
358 gridMin[i] = std::max(gridMin[i], ambientGrid.getMinGridPoint(i));
359 gridMax[i] = std::min(gridMax[i], ambientGrid.getMaxGridPoint(i));
360 if (maskInterface !=
nullptr) {
362 std::max(gridMin[i], maskInterface->getGrid().getMinGridPoint(i));
364 std::min(gridMax[i], maskInterface->getGrid().getMaxGridPoint(i));
368 auto bounds = definedPointBounds(reactionInterface);
369 mergeDefinedPointBounds(
bounds, ambientInterface);
370 if (maskInterface !=
nullptr)
371 mergeDefinedPointBounds(
bounds, maskInterface);
377 std::size_t numGridPoints = 1;
378 for (
unsigned i = 0; i <
D; ++i) {
379 if (useRequestedBounds) {
384 Logger::getInstance()
385 .addError(solverName +
": Cartesian solve region is empty.")
394 if (numGridPoints > maxGridPoints) {
395 Logger::getInstance()
396 .addError(solverName +
397 ": Cartesian solve region exceeds maxGridPoints.")
406 bool useRequestedBounds,
409 std::size_t maxGridPoints,
410 const std::string &solverName) {
411 auto &grid = maskInterface->getGrid();
414 auto bounds = definedPointBounds(maskInterface);
418 grid.getMaxGridPoint());
420 std::size_t numGridPoints = 1;
421 for (
unsigned i = 0; i <
D; ++i) {
422 if (useRequestedBounds) {
427 Logger::getInstance()
428 .addError(solverName +
": Cartesian solve region is empty.")
437 if (numGridPoints > maxGridPoints) {
438 Logger::getInstance()
439 .addError(solverName +
440 ": Cartesian solve region exceeds maxGridPoints.")
449 GridBounds definedPointBounds(SmartPointer<
Domain<T, D>> levelSet)
const {
452 for (; !it.isFinished(); ++it) {
456 const auto &index = it.getStartIndices();
457 if (!
bounds.foundDefinedPoints) {
460 bounds.foundDefinedPoints =
true;
462 for (
unsigned i = 0; i <
D; ++i) {
471 void mergeDefinedPointBounds(
GridBounds &target,
472 SmartPointer<Domain<T, D>> levelSet)
const {
473 const auto source = definedPointBounds(levelSet);
474 if (!source.foundDefinedPoints)
476 if (!target.foundDefinedPoints) {
480 for (
unsigned i = 0; i <
D; ++i) {
481 target.min[i] = std::min(target.min[i], source.min[i]);
482 target.max[i] = std::max(target.max[i], source.max[i]);
490 constexpr int padding = 4;
491 for (
unsigned i = 0; i <
D; ++i) {
500 std::max(gridMin[i], std::max(gridMin[i],
minIndex[i]) - padding);
502 std::min(gridMax[i], std::min(gridMax[i],
maxIndex[i]) + padding);
constexpr int D
Definition Epitaxy.cpp:12
double T
Definition Epitaxy.cpp:13
double bounds[2 *D]
Definition OxidationNitride.cpp:40
constexpr T gridDelta
Definition OxidationNitride.cpp:35
Common Cartesian-grid infrastructure shared by the oxidation solver classes (diffusion,...
Definition lsOxidationSolverBase.hpp:100
static constexpr std::size_t noNode
Definition lsOxidationSolverBase.hpp:106
bool crosses(T a, T b) const
Definition lsOxidationSolverBase.hpp:147
std::array< bool, D > mirrorHigh_
Definition lsOxidationSolverBase.hpp:115
void setMirrorSides(const GridType &grid)
Definition lsOxidationSolverBase.hpp:117
std::size_t lookupNode(const IndexType &index) const
Definition lsOxidationSolverBase.hpp:218
std::size_t linearIndex(const IndexType &index) const
Definition lsOxidationSolverBase.hpp:224
void initNodeLookup()
Definition lsOxidationSolverBase.hpp:211
bool inBounds(const IndexType &index) const
Definition lsOxidationSolverBase.hpp:204
std::array< std::size_t, D > strides
Definition lsOxidationSolverBase.hpp:111
T gridDelta
Definition lsOxidationSolverBase.hpp:112
bool initializeGridFromMask(SmartPointer< Domain< T, D > > maskInterface, bool useRequestedBounds, const IndexType &requestedMinIndex, const IndexType &requestedMaxIndex, std::size_t maxGridPoints, const std::string &solverName)
Definition lsOxidationSolverBase.hpp:405
std::vector< std::size_t > nodeLookupFlat
Definition lsOxidationSolverBase.hpp:107
std::array< bool, D > mirrorLow_
Definition lsOxidationSolverBase.hpp:115
bool initializeGridFromInterfaces(SmartPointer< Domain< T, D > > reactionInterface, SmartPointer< Domain< T, D > > ambientInterface, SmartPointer< Domain< T, D > > maskInterface, bool useRequestedBounds, const IndexType &requestedMinIndex, const IndexType &requestedMaxIndex, std::size_t maxGridPoints, const std::string &solverName)
Definition lsOxidationSolverBase.hpp:334
std::array< std::size_t, D > extents
Definition lsOxidationSolverBase.hpp:110
viennahrle::ConstSparseIterator< typename Domain< T, D >::DomainType > ConstSparseIterator
Definition lsOxidationSolverBase.hpp:103
std::vector< std::size_t > findNearbyNodes(const IndexType &index, Accept accept) const
Definition lsOxidationSolverBase.hpp:294
T valueAt(ConstSparseIterator &it, const IndexType &index) const
Definition lsOxidationSolverBase.hpp:155
bool increment(IndexType &index) const
Definition lsOxidationSolverBase.hpp:233
IndexType minIndex
Definition lsOxidationSolverBase.hpp:108
int stencilOffset(const IndexType &index, unsigned direction, int offset) const
Definition lsOxidationSolverBase.hpp:129
viennahrle::Index< D > IndexType
Definition lsOxidationSolverBase.hpp:102
std::size_t findNearbyNode(const IndexType &index) const
Definition lsOxidationSolverBase.hpp:247
Vec3D< T > definedLevelSetGradient(ConstSparseIterator &it, const IndexType &index, OnGrid onGrid) const
Definition lsOxidationSolverBase.hpp:170
IndexType maxIndex
Definition lsOxidationSolverBase.hpp:109
Definition lsOxidationSolverBase.hpp:21
Vec3D< T > vecAdd(const Vec3D< T > &a, const Vec3D< T > &b)
Definition lsOxidationSolverBase.hpp:58
T levelSetCrossingDistance(T insidePhi, T outsidePhi, T minBoundaryFraction, T gridDelta)
Definition lsOxidationSolverBase.hpp:86
Vec3D< T > vecSubtract(const Vec3D< T > &a, const Vec3D< T > &b)
Definition lsOxidationSolverBase.hpp:66
T clampLevelSetPhi(T v)
Clamp HRLE far-field sentinels (±DBL_MAX) to ±1 before differencing to prevent DBL_MAX² overflow that...
Definition lsOxidationSolverBase.hpp:81
Vec3D< T > vecScaled(const Vec3D< T > &source, T factor)
Definition lsOxidationSolverBase.hpp:50
std::size_t gridIndexHash(const viennahrle::Index< D > &index)
Definition lsOxidationSolverBase.hpp:30
void vecAddTo(Vec3D< T > &target, const Vec3D< T > &source)
Definition lsOxidationSolverBase.hpp:74
Definition lsAdvect.hpp:41
Definition lsOxidationSolverBase.hpp:141
IndexType max
Definition lsOxidationSolverBase.hpp:143
bool foundDefinedPoints
Definition lsOxidationSolverBase.hpp:144
IndexType min
Definition lsOxidationSolverBase.hpp:142
Definition lsOxidationSolverBase.hpp:44
std::size_t operator()(const viennahrle::Index< D > &idx) const
Definition lsOxidationSolverBase.hpp:45