ViennaLS
Loading...
Searching...
No Matches
lsOxidationModel.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <lsOxidationMask.hpp>
4
5#include <algorithm>
6#include <string>
7#include <vector>
8
9#include <vcTimer.hpp>
10
11namespace viennals {
12
14 unsigned maxIterations = 10;
15 double tolerance = 1e-6;
16 double relaxation = 1.;
17};
18
21template <class T, int D> class OxidationModel {
22 using IndexType = viennahrle::Index<D>;
23
24 SmartPointer<OxidationDiffusion<T, D>> diffusionField = nullptr;
25 SmartPointer<OxidationDeformation<T, D>> deformationField = nullptr;
27 IndexType minIndex{};
28 IndexType maxIndex{};
29 bool useRequestedBounds = false;
30 unsigned iterations = 0;
31 T residual = std::numeric_limits<T>::max();
32 bool converged_ = false;
33 std::string failureReason_;
34
35public:
36 OxidationModel() = default;
37
39 SmartPointer<OxidationDiffusion<T, D>> passedDiffusionField,
40 SmartPointer<OxidationDeformation<T, D>> passedDeformationField,
41 OxidationCouplingParameters passedParameters = {})
42 : diffusionField(passedDiffusionField),
43 deformationField(passedDeformationField), parameters(passedParameters) {
44 }
45
46 template <class... Args> static auto New(Args &&...args) {
47 return SmartPointer<OxidationModel>::New(std::forward<Args>(args)...);
48 }
49
51 SmartPointer<OxidationDiffusion<T, D>> passedDiffusionField) {
52 diffusionField = passedDiffusionField;
53 }
54
56 SmartPointer<OxidationDeformation<T, D>> passedDeformationField) {
57 deformationField = passedDeformationField;
58 }
59
61 parameters = passedParameters;
62 }
63
64 void setSolveBounds(const IndexType &passedMinIndex,
65 const IndexType &passedMaxIndex) {
66 minIndex = passedMinIndex;
67 maxIndex = passedMaxIndex;
68 useRequestedBounds = true;
69 }
70
71 void clearSolveBounds() { useRequestedBounds = false; }
72
73 void apply() {
74 iterations = 0;
75 residual = 0.;
76 converged_ = false;
77 failureReason_.clear();
78 if (diffusionField == nullptr || deformationField == nullptr) {
79 Logger::getInstance()
80 .addError("OxidationModel: Missing diffusion or deformation "
81 "field.")
82 .print();
83 return;
84 }
85
86 if (useRequestedBounds) {
87 diffusionField->setSolveBounds(minIndex, maxIndex);
88 deformationField->setSolveBounds(minIndex, maxIndex);
89 } else {
90 diffusionField->clearSolveBounds();
91 deformationField->clearSolveBounds();
92 }
93
94 // forEachSolutionNode order is deterministic on a fixed grid, so
95 // nodeIndices is collected once and p_raw is refilled in-place on
96 // subsequent iterations.
97 std::vector<IndexType> nodeIndices;
98 std::vector<T> p_raw;
99 std::vector<T> p_km1, p_k; // Aitken Δ² history
100
101 for (; iterations < parameters.maxIterations; ++iterations) {
102 VIENNACORE_LOG_DEBUG("OxidationModel: coupling iteration " +
103 std::to_string(iterations + 1) + "/" +
104 std::to_string(parameters.maxIterations) +
105 " starting diffusion solve");
106 diffusionField->apply();
107 VIENNACORE_LOG_DEBUG(
108 "OxidationModel: diffusion solve complete, nodes=" +
109 std::to_string(diffusionField->getNumberOfSolutionNodes()) +
110 ", iterations=" + std::to_string(diffusionField->getIterations()) +
111 ", residual=" + std::to_string(diffusionField->getResidual()));
112 if (!diffusionField->lastSolveConverged() ||
113 !diffusionField->hasFiniteConcentrationField()) {
114 residual = std::numeric_limits<T>::infinity();
115 failureReason_ =
116 "diffusion solve failed (residual=" +
117 std::to_string(diffusionField->getNormalizedResidual()) +
118 ", tolerance=" +
119 std::to_string(diffusionField->getParameters().tolerance) + ")";
120 Logger::getInstance()
121 .addWarning("OxidationModel: " + failureReason_ + ".")
122 .print();
123 return;
124 }
125
126 VIENNACORE_LOG_DEBUG("OxidationModel: coupling iteration " +
127 std::to_string(iterations + 1) + "/" +
128 std::to_string(parameters.maxIterations) +
129 " starting deformation solve");
130 Timer<> tDeform;
131 tDeform.start();
132 deformationField->apply();
133 tDeform.finish();
134 VIENNACORE_LOG_DEBUG(
135 "OxidationModel: deformation solve complete, nodes=" +
136 std::to_string(deformationField->getNumberOfSolutionNodes()) +
137 ", iterations=" + std::to_string(deformationField->getIterations()) +
138 ", residual=" + std::to_string(deformationField->getResidual()));
139 if (!deformationField->lastSolveConverged() ||
140 !deformationField->hasFiniteSolution()) {
141 residual = std::numeric_limits<T>::infinity();
142 failureReason_ =
143 "deformation solve failed (mechanics=" +
144 std::to_string(deformationField->getResidual()) + ", pressure=" +
145 std::to_string(deformationField->getLastPressureResidual()) +
146 ", stokes=" +
147 std::to_string(deformationField->getLastStokesResidual()) + ")";
148 VIENNACORE_LOG_WARNING("OxidationModel: " + failureReason_ + ".");
149 return;
150 }
151 if (Logger::hasTiming())
152 Logger::getInstance()
153 .addTiming(" deformation(couplingIter=" +
154 std::to_string(iterations + 1) + ")",
155 tDeform)
156 .print();
157
158 // Collect raw pressures G(x_k) from deformation.
159 if (iterations == 0) {
160 nodeIndices.clear();
161 p_raw.clear();
162 deformationField->forEachSolutionNode([&](const IndexType &idx, T p) {
163 nodeIndices.push_back(idx);
164 p_raw.push_back(p);
165 });
166 } else {
167 std::size_t ii = 0;
168 deformationField->forEachSolutionNode(
169 [&](const IndexType &, T p) { p_raw[ii++] = p; });
170 }
171 const std::size_t n = p_raw.size();
172 if (!std::all_of(p_raw.begin(), p_raw.end(),
173 [](T value) { return std::isfinite(value); })) {
174 residual = std::numeric_limits<T>::infinity();
175 failureReason_ =
176 "deformation pressure feedback produced non-finite values";
177 VIENNACORE_LOG_WARNING("OxidationModel: " + failureReason_ + ".");
178 return;
179 }
180
181 // Aitken Δ²: find θ minimising ||(1-θ)F_{k-1} + θF_k||².
182 // Clamped to [0.1, 1.0]: no extrapolation (θ>1) because the
183 // pressure→concentration feedback is nonlinear (exponential kinetics)
184 // and overshooting the pressure causes oscillatory divergence.
185 T aitkenTheta = T(1);
186 if (p_k.size() == n && p_km1.size() == n) {
187 T dot_Fkm1_dF = T(0), dot_dF_dF = T(0);
188 for (std::size_t i = 0; i < n; ++i) {
189 const T Fkm1 = p_k[i] - p_km1[i];
190 const T Fk = p_raw[i] - p_k[i];
191 const T dF = Fk - Fkm1;
192 dot_Fkm1_dF += Fkm1 * dF;
193 dot_dF_dF += dF * dF;
194 }
195 if (dot_dF_dF > T(1e-100))
196 aitkenTheta =
197 std::max(T(0.1), std::min(T(1.0), -dot_Fkm1_dF / dot_dF_dF));
198 }
199
200 // Compute blended pressure and relative-change residual.
201 std::vector<T> p_blended(n);
202 T maxChange = T(0), maxPressure = T(0);
203 for (std::size_t i = 0; i < n; ++i) {
204 const T oldP = p_k.empty() ? T(0) : p_k[i];
205 p_blended[i] = (T(1) - aitkenTheta) * oldP + aitkenTheta * p_raw[i];
206 maxChange = std::max(maxChange, std::abs(p_blended[i] - oldP));
207 maxPressure = std::max(maxPressure, std::abs(p_blended[i]));
208 }
209 residual = (maxPressure > std::numeric_limits<T>::epsilon())
210 ? maxChange / maxPressure
211 : maxChange;
212
213 // Feed blended pressures to diffusion.
214 for (std::size_t i = 0; i < n; ++i)
215 diffusionField->setPressure(nodeIndices[i], p_blended[i]);
216
217 // Shift Aitken history; seed p_km1 with zeros on the first iteration.
218 p_km1 = p_k.empty() ? std::vector<T>(n, T(0)) : std::move(p_k);
219 p_k = p_blended;
220
221 VIENNACORE_LOG_DEBUG(
222 "OxidationModel: coupling iteration " +
223 std::to_string(iterations + 1) +
224 " pressure-feedback residual=" + std::to_string(residual));
225 if (residual < parameters.tolerance)
226 break;
227 }
228 const unsigned completedIterations =
229 std::min(iterations + 1, parameters.maxIterations);
230 VIENNACORE_LOG_DEBUG("OxidationModel: coupled solve complete, iterations=" +
231 std::to_string(completedIterations) +
232 ", residual=" + std::to_string(residual));
233 converged_ = std::isfinite(residual) && residual <= parameters.tolerance;
234 if (!converged_)
235 VIENNACORE_LOG_WARNING(
236 "OxidationModel: pressure-concentration coupling did not "
237 "converge after " +
238 std::to_string(completedIterations) +
239 " iterations (residual=" + std::to_string(residual) +
240 ", tolerance=" + std::to_string(parameters.tolerance) +
241 "). Consider increasing maxIterations or relaxation.");
242 }
243
244 unsigned getIterations() const { return iterations; }
245 T getResidual() const { return residual; }
246 bool hasConverged() const { return converged_; }
247 std::string getFailureReason() const { return failureReason_; }
248};
249
250} // namespace viennals
double T
Definition Epitaxy.cpp:13
Propagates the volume expansion generated at the Si/SiO2 interface through the oxide as a Cartesian-g...
Definition lsOxidationDeformation.hpp:60
Solves the oxidant diffusion step of the Suvorov et al. (10.1007/s10825-006-0003-z) oxidation model o...
Definition lsOxidationDiffusion.hpp:92
void setSolveBounds(const IndexType &passedMinIndex, const IndexType &passedMaxIndex)
Definition lsOxidationModel.hpp:64
void setDeformationField(SmartPointer< OxidationDeformation< T, D > > passedDeformationField)
Definition lsOxidationModel.hpp:55
static auto New(Args &&...args)
Definition lsOxidationModel.hpp:46
T getResidual() const
Definition lsOxidationModel.hpp:245
OxidationModel(SmartPointer< OxidationDiffusion< T, D > > passedDiffusionField, SmartPointer< OxidationDeformation< T, D > > passedDeformationField, OxidationCouplingParameters passedParameters={})
Definition lsOxidationModel.hpp:38
bool hasConverged() const
Definition lsOxidationModel.hpp:246
void setDiffusionField(SmartPointer< OxidationDiffusion< T, D > > passedDiffusionField)
Definition lsOxidationModel.hpp:50
unsigned getIterations() const
Definition lsOxidationModel.hpp:244
void clearSolveBounds()
Definition lsOxidationModel.hpp:71
void apply()
Definition lsOxidationModel.hpp:73
std::string getFailureReason() const
Definition lsOxidationModel.hpp:247
void setParameters(OxidationCouplingParameters passedParameters)
Definition lsOxidationModel.hpp:60
Definition lsAdvect.hpp:41
Definition lsOxidationModel.hpp:13
double tolerance
Definition lsOxidationModel.hpp:15
double relaxation
Definition lsOxidationModel.hpp:16
unsigned maxIterations
Definition lsOxidationModel.hpp:14