ViennaLS
Toggle main menu visibility
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
>
32
#include <
lsPreCompileMacros.hpp
>
33
#include <
lsToSurfaceMesh.hpp
>
34
35
#include <algorithm>
36
#include <cmath>
37
38
namespace
viennals
{
39
40
using namespace
viennacore;
41
42
template
<
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
51
public
:
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
77
private
:
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
];
91
BoundaryConditionEnum
bcs[
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
131
PRECOMPILE_PRECISION_DIMENSION
(
Resample
)
132
133
}
// namespace viennals
D
constexpr int D
Definition
Epitaxy.cpp:12
bounds
double bounds[2 *D]
Definition
OxidationNitride.cpp:40
newDelta
constexpr T newDelta
Definition
Resample.cpp:20
oldDelta
constexpr T oldDelta
Definition
Resample.cpp:20
viennals::DomainType
viennals::Domain::New
static auto New(Args &&...args)
Definition
lsDomain.hpp:111
viennals::Domain::getGrid
const GridType & getGrid() const
get reference to the grid on which the levelset is defined
Definition
lsDomain.hpp:141
viennals::Expand::Expand
Expand()=default
viennals::FromSurfaceMesh::FromSurfaceMesh
FromSurfaceMesh()=default
viennals::Resample
Definition
lsResample.hpp:42
viennals::Resample::setExpandWidth
void setExpandWidth(int layers)
Definition
lsResample.hpp:58
viennals::Resample::Resample
Resample(DomainType input, double newDelta)
Definition
lsResample.hpp:53
viennals::Resample::apply
void apply()
Definition
lsResample.hpp:62
viennals::Resample::setNewGridDelta
void setNewGridDelta(double delta)
Definition
lsResample.hpp:57
viennals::Resample::Resample
Resample()=default
viennals::Resample::getResult
DomainType getResult() const
Definition
lsResample.hpp:60
viennals::Resample::setLevelSet
void setLevelSet(DomainType input)
Definition
lsResample.hpp:56
viennals::ToSurfaceMesh::ToSurfaceMesh
ToSurfaceMesh(double mnd=0.05, double eps=1e-12)
Definition
lsToSurfaceMesh.hpp:82
lsDomain.hpp
lsExpand.hpp
lsFromSurfaceMesh.hpp
lsMesh.hpp
lsPreCompileMacros.hpp
PRECOMPILE_PRECISION_DIMENSION
#define PRECOMPILE_PRECISION_DIMENSION(className)
Definition
lsPreCompileMacros.hpp:24
lsToSurfaceMesh.hpp
viennals
Definition
lsAdvect.hpp:41
viennals::BoundaryConditionEnum
viennahrle::BoundaryType BoundaryConditionEnum
Definition
lsDomain.hpp:23
include
viennals
lsResample.hpp
Generated by
1.18.0