ViennaLS
Loading...
Searching...
No Matches
lsOxidationMask.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <lsInterior.hpp>
5
6#include <cmath>
7#include <unordered_map>
8#include <vector>
9
10namespace viennals {
11
19 // Young's modulus (Pa) and Poisson ratio of the nitride.
20 // Si₃N₄ at 1000 °C: ~250–270 GPa.
21 double youngModulus = 270e9;
22 double poissonRatio = 0.27;
23 // Creep of the deviatoric stress (Maxwell): viscosity in Pa hr (0 =
24 // linear-elastic mask) and its Eyring activation volume in m^3 (0 =
25 // linear viscosity). Si3N4: OxidationPresets::siliconNitrideMask.
26 double viscosity = 0.;
28};
29
51template <class T, int D>
52class OxidationMaskCarry final : public VelocityField<T> {
53 using IndexType = viennahrle::Index<D>;
54 using ConstSparseIterator =
55 viennahrle::ConstSparseIterator<typename Domain<T, D>::DomainType>;
56
57 std::unordered_map<std::size_t, Vec3D<T>> velocity_;
58 // The oxide MECHANICS field. The carry reads only its resolved Stokes
59 // velocity (getResolvedVectorVelocity) — never the generic VelocityField
60 // interface, whose fallback derives a speed from oxidant concentration,
61 // which has nothing to do with mask motion.
62 SmartPointer<OxidationDeformation<T, D>> oxideMechanics_ = nullptr;
63 T gridDelta_ = 1.;
64
65public:
66 OxidationMaskCarry() = default;
67
68 OxidationMaskCarry(SmartPointer<OxidationDeformation<T, D>> oxideMechanics,
69 SmartPointer<Domain<T, D>> maskInterface)
70 : oxideMechanics_(oxideMechanics) {
71 if (oxideMechanics == nullptr || maskInterface == nullptr)
72 return;
73 gridDelta_ = maskInterface->getGrid().getGridDelta();
74
75 // Own Interior-filled copy: the caller's mask may be a bare narrow band at
76 // this point, and the sweep needs the whole body defined.
77 auto body = Domain<T, D>::New(maskInterface);
78 Interior<T, D>(body).apply();
79
80 std::vector<IndexType> index;
81 std::vector<Vec3D<T>> value;
82 std::vector<uint8_t> known;
83 std::unordered_map<std::size_t, std::size_t> lookup;
84 const T eps = std::numeric_limits<T>::epsilon();
85
86 // Seed: a mask point that sees a non-zero RESOLVED Stokes velocity is on
87 // (or within extension range of) the oxide contact.
88 for (ConstSparseIterator it(body->getDomain()); !it.isFinished(); ++it) {
89 if (!it.isDefined())
90 continue;
91 const auto idx = it.getStartIndices();
92 Vec3D<T> coordinate{};
93 for (unsigned d = 0; d < D; ++d)
94 coordinate[d] = static_cast<T>(idx[d]) * gridDelta_;
95 auto sampled = oxideMechanics->getResolvedVectorVelocity(coordinate);
96 T magnitude = T(0);
97 for (unsigned d = 0; d < D; ++d)
98 magnitude += sampled[d] * sampled[d];
99 const bool onOxide = magnitude > eps;
100 lookup[detail::gridIndexHash<D>(idx)] = index.size();
101 index.push_back(idx);
102 value.push_back(onOxide ? sampled : Vec3D<T>{T(0), T(0), T(0)});
103 known.push_back(onOxide ? uint8_t(1) : uint8_t(0));
104 }
105
106 // Relaxation sweeps until the whole body has a velocity.
107 for (bool changed = true; changed;) {
108 changed = false;
109 auto nextValue = value;
110 auto nextKnown = known;
111 for (std::size_t i = 0; i < index.size(); ++i) {
112 if (known[i])
113 continue;
114 Vec3D<T> sum{T(0), T(0), T(0)};
115 unsigned count = 0;
116 for (unsigned d = 0; d < D; ++d) {
117 for (int offset = -1; offset <= 1; offset += 2) {
118 auto neighbor = index[i];
119 neighbor[d] += offset;
120 const auto found = lookup.find(detail::gridIndexHash<D>(neighbor));
121 if (found == lookup.end() || !known[found->second])
122 continue;
123 for (unsigned k = 0; k < D; ++k)
124 sum[k] += value[found->second][k];
125 ++count;
126 }
127 }
128 if (count == 0)
129 continue;
130 for (unsigned k = 0; k < D; ++k)
131 nextValue[i][k] = sum[k] / static_cast<T>(count);
132 nextKnown[i] = 1;
133 changed = true;
134 }
135 value.swap(nextValue);
136 known.swap(nextKnown);
137 }
138
139 for (std::size_t i = 0; i < index.size(); ++i)
140 if (known[i])
141 velocity_[detail::gridIndexHash<D>(index[i])] = value[i];
142 }
143
144 template <class... Args> static auto New(Args &&...args) {
145 return SmartPointer<OxidationMaskCarry>::New(std::forward<Args>(args)...);
146 }
147
148 Vec3D<T> getVectorVelocity(const Vec3D<T> &coordinate, int material,
149 const Vec3D<T> &normalVector,
150 unsigned long pointId) final {
151 // On the contact, return EXACTLY what the oxide's own free surface gets.
152 //
153 // This is the kinematic tie that keeps the two surfaces together: the
154 // shared surface advects on a single value. Returning the grid-snapped
155 // cached value here instead would advect the mask with a slightly
156 // different velocity than the oxide at the same place; the contact then
157 // slips by a fraction of a cell every substep and the mask peels away.
158 if (oxideMechanics_ != nullptr) {
159 const auto onOxide =
160 oxideMechanics_->getResolvedVectorVelocity(coordinate);
161 T magnitude = T(0);
162 for (unsigned d = 0; d < D; ++d)
163 magnitude += onOxide[d] * onOxide[d];
164 if (magnitude > std::numeric_limits<T>::epsilon())
165 return onOxide;
166 }
167
168 // Off the oxide (mask interior and outer surface): use the extended value.
169 IndexType index;
170 for (unsigned d = 0; d < D; ++d)
171 index[d] = std::llround(coordinate[d] / gridDelta_);
172 const auto found = velocity_.find(detail::gridIndexHash<D>(index));
173 if (found == velocity_.end())
174 return {0., 0., 0.};
175 return found->second;
176 }
177
178 T getScalarVelocity(const Vec3D<T> &, int, const Vec3D<T> &,
179 unsigned long) final {
180 // Carried, not grown: a normal growth term would change mask thickness.
181 return 0.;
182 }
183};
184
185} // 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
static auto New(Args &&...args)
Definition lsDomain.hpp:111
Propagates the volume expansion generated at the Si/SiO2 interface through the oxide as a Cartesian-g...
Definition lsOxidationDeformation.hpp:112
T getScalarVelocity(const Vec3D< T > &, int, const Vec3D< T > &, unsigned long) final
Should return a scalar value for the velocity at coordinate for a point of material with the given no...
Definition lsOxidationMask.hpp:178
OxidationMaskCarry(SmartPointer< OxidationDeformation< T, D > > oxideMechanics, SmartPointer< Domain< T, D > > maskInterface)
Definition lsOxidationMask.hpp:68
static auto New(Args &&...args)
Definition lsOxidationMask.hpp:144
Vec3D< T > getVectorVelocity(const Vec3D< T > &coordinate, int material, const Vec3D< T > &normalVector, unsigned long pointId) final
Like getScalarVelocity, but returns a velocity value for each cartesian direction.
Definition lsOxidationMask.hpp:148
std::size_t gridIndexHash(const viennahrle::Index< D > &index)
Definition lsOxidationSolverBase.hpp:30
Definition lsAdvect.hpp:41
Nitride (Si₃N₄) mask of the LOCOS process. The grid points inside the mask join the oxide mechanics s...
Definition lsOxidationMask.hpp:18
double poissonRatio
Definition lsOxidationMask.hpp:22
double shearActivationVolume
Definition lsOxidationMask.hpp:27
double viscosity
Definition lsOxidationMask.hpp:26
double youngModulus
Definition lsOxidationMask.hpp:21