77 failureReason_.clear();
78 if (diffusionField ==
nullptr || deformationField ==
nullptr) {
80 .addError(
"OxidationModel: Missing diffusion or deformation "
86 if (useRequestedBounds) {
87 diffusionField->setSolveBounds(minIndex, maxIndex);
88 deformationField->setSolveBounds(minIndex, maxIndex);
90 diffusionField->clearSolveBounds();
91 deformationField->clearSolveBounds();
97 std::vector<IndexType> nodeIndices;
99 std::vector<T> p_km1, p_k;
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();
116 "diffusion solve failed (residual=" +
117 std::to_string(diffusionField->getNormalizedResidual()) +
119 std::to_string(diffusionField->getParameters().tolerance) +
")";
120 Logger::getInstance()
121 .addWarning(
"OxidationModel: " + failureReason_ +
".")
126 VIENNACORE_LOG_DEBUG(
"OxidationModel: coupling iteration " +
127 std::to_string(iterations + 1) +
"/" +
128 std::to_string(parameters.maxIterations) +
129 " starting deformation solve");
132 deformationField->apply();
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();
143 "deformation solve failed (mechanics=" +
144 std::to_string(deformationField->getResidual()) +
", pressure=" +
145 std::to_string(deformationField->getLastPressureResidual()) +
147 std::to_string(deformationField->getLastStokesResidual()) +
")";
148 VIENNACORE_LOG_WARNING(
"OxidationModel: " + failureReason_ +
".");
151 if (Logger::hasTiming())
152 Logger::getInstance()
153 .addTiming(
" deformation(couplingIter=" +
154 std::to_string(iterations + 1) +
")",
159 if (iterations == 0) {
162 deformationField->forEachSolutionNode([&](
const IndexType &idx,
T p) {
163 nodeIndices.push_back(idx);
168 deformationField->forEachSolutionNode(
169 [&](
const IndexType &,
T p) { p_raw[ii++] = p; });
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();
176 "deformation pressure feedback produced non-finite values";
177 VIENNACORE_LOG_WARNING(
"OxidationModel: " + failureReason_ +
".");
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;
195 if (dot_dF_dF >
T(1e-100))
197 std::max(
T(0.1), std::min(
T(1.0), -dot_Fkm1_dF / dot_dF_dF));
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]));
209 residual = (maxPressure > std::numeric_limits<T>::epsilon())
210 ? maxChange / maxPressure
214 for (std::size_t i = 0; i < n; ++i)
215 diffusionField->setPressure(nodeIndices[i], p_blended[i]);
218 p_km1 = p_k.empty() ? std::vector<T>(n,
T(0)) : std::move(p_k);
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)
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;
235 VIENNACORE_LOG_WARNING(
236 "OxidationModel: pressure-concentration coupling did not "
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.");