ViennaLS
Loading...
Searching...
No Matches
lsResample.hpp
Go to the documentation of this file.
1#pragma once
2
3// Generic level-set resample engine.
4//
5// Produces a copy of a level set on a NEW grid spacing over the same physical
6// bounds and boundary conditions (a reflective edge moves inwards by less than
7// one new cell when the extent is not a multiple of the new spacing), by a
8// ToSurfaceMesh -> FromSurfaceMesh round trip.
9// Measured EXACT on analytic tests (plane and sphere, refine 2x and coarsen
10// 3x: max error <= 0.02 nm): the triangulation nodes are the sub-cell zero
11// crossings, so nothing is quantised away. (Multilinear interpolation of the
12// stored band values is not an alternative: values beyond the first band
13// layer are Expand-propagated approximations, not Euclidean distances --
14// ~60 nm max error on a r = 50 nm sphere.)
15//
16// Usage modes (policy lives with the caller, not here):
17// PERSISTENT regrid: resample the WHOLE level-set stack with one Resample
18// per LS onto the SAME newDelta, then replace the simulation state.
19// TRANSIENT solver refinement: resample only the subset of level sets a
20// field solver consumes; use the copies for the solve, discard them.
21// A solver's subset must share one newDelta so the cut-cell boundary
22// distances see consistent relative sub-cell interface positions.
23//
24// Field data is NOT carried: caches keyed by quantised physical coordinate
25// survive a resample by convention; grid-index-keyed data must be re-keyed
26// by the caller.
27
28#include <lsDomain.hpp>
29#include <lsExpand.hpp>
30#include <lsFromSurfaceMesh.hpp>
31#include <lsMesh.hpp>
33#include <lsToSurfaceMesh.hpp>
34
35#include <algorithm>
36#include <cmath>
37
38namespace viennals {
39
40using namespace viennacore;
41
42template <class T, int D> class Resample {
43 using DomainType = SmartPointer<Domain<T, D>>;
44
45 DomainType input_ = nullptr;
46 DomainType output_ = nullptr;
47 double newDelta_ = 0.;
48 // Width (in new-grid layers) of the produced narrow band.
49 int expandWidth_ = 3;
50
51public:
52 Resample() = default;
53 Resample(DomainType input, double newDelta)
54 : input_(input), newDelta_(newDelta) {}
55
56 void setLevelSet(DomainType input) { input_ = input; }
57 void setNewGridDelta(double delta) { newDelta_ = delta; }
58 void setExpandWidth(int layers) { expandWidth_ = std::max(2, layers); }
59
60 DomainType getResult() const { return output_; }
61
62 void apply() {
63 if (input_ == nullptr || newDelta_ <= 0.) {
64 Logger::getInstance()
65 .addError("Resample: input level set or newDelta not set.")
66 .print();
67 return;
68 }
69
70 output_ = makeEmptyTarget();
71 auto mesh = SmartPointer<Mesh<T>>::New();
72 ToSurfaceMesh<T, D>(input_, mesh).apply();
73 FromSurfaceMesh<T, D>(output_, mesh).apply();
74 Expand<T, D>(output_, 2 * expandWidth_ + 1).apply();
75 }
76
77private:
78 // The new grid covers the old one's extent. A reflective edge must lie
79 // INSIDE that extent: Domain rounds bounds outwards, and when the extent
80 // was not a multiple of the new spacing the edge column fell beyond the
81 // old grid, where the source has no surface. That column was filled with
82 // the undefined sentinel (+-1.8e308) as defined values, the Si normal there
83 // became NaN and the oxide diffusion matrix non-finite: a LOCOS run whose
84 // regrid left such a column aborted. The edge now moves inwards by less
85 // than one new cell. (A periodic extent must be a multiple of the new
86 // spacing; it is left as it was.)
87 DomainType makeEmptyTarget() const {
88 const auto &grid = input_->getGrid();
89 const double oldDelta = grid.getGridDelta();
90 double bounds[2 * D];
92 for (int i = 0; i < D; ++i) {
93 bcs[i] = grid.getBoundaryConditions(i);
94 double low = grid.getMinBounds(i) * oldDelta;
95 double high = grid.getMaxBounds(i) * oldDelta;
96 const bool lowReflective =
97 bcs[i] == BoundaryConditionEnum::REFLECTIVE_BOUNDARY ||
98 bcs[i] == BoundaryConditionEnum::POS_INFINITE_BOUNDARY;
99 const bool highReflective =
100 bcs[i] == BoundaryConditionEnum::REFLECTIVE_BOUNDARY ||
101 bcs[i] == BoundaryConditionEnum::NEG_INFINITE_BOUNDARY;
102 const double lowIndex = std::ceil(low / newDelta_ - 1e-9);
103 const double highIndex = std::floor(high / newDelta_ + 1e-9);
104 const bool moved =
105 (lowReflective &&
106 std::abs(lowIndex * newDelta_ - low) > 1e-9 * newDelta_) ||
107 (highReflective &&
108 std::abs(highIndex * newDelta_ - high) > 1e-9 * newDelta_);
109 if (moved)
110 Logger::getInstance()
111 .addWarning("Resample: the extent in direction " +
112 std::to_string(i) +
113 " is not a multiple of the new grid spacing; the "
114 "reflective boundaries move from " +
115 std::to_string(low) + " / " + std::to_string(high) +
116 " to " + std::to_string(lowIndex * newDelta_) + " / " +
117 std::to_string(highIndex * newDelta_) + ".")
118 .print();
119 // Domain floors the lower bound and ceils the upper one
120 if (lowReflective)
121 low = (lowIndex + 0.25) * newDelta_;
122 if (highReflective)
123 high = (highIndex - 0.25) * newDelta_;
124 bounds[2 * i] = low;
125 bounds[2 * i + 1] = high;
126 }
127 return Domain<T, D>::New(bounds, bcs, newDelta_);
128 }
129};
130
132
133} // namespace viennals
constexpr int D
Definition Epitaxy.cpp:12
double bounds[2 *D]
Definition OxidationNitride.cpp:40
constexpr T newDelta
Definition Resample.cpp:20
constexpr T oldDelta
Definition Resample.cpp:20
static auto New(Args &&...args)
Definition lsDomain.hpp:111
const GridType & getGrid() const
get reference to the grid on which the levelset is defined
Definition lsDomain.hpp:141
Expand()=default
Definition lsResample.hpp:42
void setExpandWidth(int layers)
Definition lsResample.hpp:58
Resample(DomainType input, double newDelta)
Definition lsResample.hpp:53
void apply()
Definition lsResample.hpp:62
void setNewGridDelta(double delta)
Definition lsResample.hpp:57
DomainType getResult() const
Definition lsResample.hpp:60
void setLevelSet(DomainType input)
Definition lsResample.hpp:56
ToSurfaceMesh(double mnd=0.05, double eps=1e-12)
Definition lsToSurfaceMesh.hpp:82
#define PRECOMPILE_PRECISION_DIMENSION(className)
Definition lsPreCompileMacros.hpp:24
Definition lsAdvect.hpp:41
viennahrle::BoundaryType BoundaryConditionEnum
Definition lsDomain.hpp:23