-
Notifications
You must be signed in to change notification settings - Fork 975
Expand file tree
/
Copy pathCDiscAdjMultizoneDriver.hpp
More file actions
307 lines (261 loc) · 11.4 KB
/
CDiscAdjMultizoneDriver.hpp
File metadata and controls
307 lines (261 loc) · 11.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
/*!
* \class CDiscAdjMultizoneDriver.hpp
* \brief Class for driving adjoint multi-zone problems.
* \author O. Burghardt, P. Gomes, T. Albring, R. Sanchez
* \version 8.4.0 "Harrier"
*
* SU2 Project Website: https://su2code.github.io
*
* The SU2 Project is maintained by the SU2 Foundation
* (http://su2foundation.org)
*
* Copyright 2012-2026, SU2 Contributors (cf. AUTHORS.md)
*
* SU2 is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* SU2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with SU2. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "CMultizoneDriver.hpp"
#include "../../../Common/include/toolboxes/CQuasiNewtonInvLeastSquares.hpp"
#include "../../../Common/include/linear_algebra/CPreconditioner.hpp"
#include "../../../Common/include/linear_algebra/CMatrixVectorProduct.hpp"
#include "../../../Common/include/linear_algebra/CSysSolve.hpp"
/*!
* \brief Block Gauss-Seidel driver for multizone / multiphysics discrete adjoint problems.
* \ingroup DiscAdj
*/
class CDiscAdjMultizoneDriver : public CMultizoneDriver {
protected:
#ifdef CODI_FORWARD_TYPE
using Scalar = su2double;
#else
using Scalar = passivedouble;
#endif
class AdjointProduct : public CMatrixVectorProduct<Scalar> {
public:
CDiscAdjMultizoneDriver* const driver;
const unsigned short iZone = 0;
mutable unsigned long iInnerIter = 0;
AdjointProduct(CDiscAdjMultizoneDriver* d, unsigned short i) : driver(d), iZone(i) {}
inline void operator()(const CSysVector<Scalar> & u, CSysVector<Scalar> & v) const override {
driver->SetAllSolutions(iZone, true, u);
driver->Iterate(iZone, iInnerIter, true);
driver->GetAllSolutions(iZone, true, v);
v -= u;
++iInnerIter;
}
};
class Identity : public CPreconditioner<Scalar> {
public:
inline bool IsIdentity() const override { return true; }
inline void operator()(const CSysVector<Scalar> & u, CSysVector<Scalar> & v) const override { v = u; }
};
/*!
* \brief Kinds of recordings.
*/
enum class Kind_Tape {
FULL_SOLVER_TAPE, /*!< \brief Entire derivative information for a coupled adjoint
solution update. */
OBJECTIVE_FUNCTION_TAPE, /*!< \brief Record only the dependence of the objective function
w.r.t. solver variables (from all zones). */
};
/*!
* \brief Position markers within a tape.
*/
enum Tape_Positions {
START = 0, /*!< \brief Beginning of the tape. */
REGISTERED = 1, /*!< \brief Solver variables are registered on the tape. */
DEPENDENCIES = 2, /*!< \brief Derived values (e.g. gradients) are set. */
OBJECTIVE_FUNCTION = 3, /*!< \brief Objective function is set. */
TRANSFER = 4, /*!< \brief Solution data is transferred between coupled solvers of
different physical zones (giving cross contributions). */
ITERATION_READY = 5 /*!< \brief Until here, all derivative information is gathered so
that it can be connected to a solver update evaluation. */
};
RECORDING RecordingState = RECORDING::CLEAR_INDICES; /*!< \brief The kind of recording that the tape currently holds. */
bool eval_transfer = false; /*!< \brief Evaluate the transfer section of the tape. */
su2double ObjFunc; /*!< \brief Value of the objective function. */
AD::Identifier ObjFunc_Index; /*!< \brief Index of the value of the objective function. */
CIteration*** direct_iteration; /*!< \brief Array of pointers to the direct iterations. */
COutput** direct_output; /*!< \brief Array of pointers to the direct outputs. */
vector<unsigned short> direct_nInst; /*!< \brief Total number of instances in the direct problem. */
vector<unsigned long> nInnerIter; /*!< \brief Number of inner iterations for each zone. */
unsigned long wrt_sol_freq = std::numeric_limits<unsigned long>::max(); /*!< \brief File output frequency. */
su2vector<bool> Has_Deformation; /*!< \brief True if iZone has mesh deformation (used for
lazy evaluation of TRANSFER tape section). */
/*!< \brief Individual cross-terms of the coupled problem, 5D array [iZone][jZone][iSol](iPoint,iVar).
The column sum, i.e. along all iZones for each jZone, gives the External (total cross-term)
for jZone, we need to store all terms to have BGS-type updates with relaxation. */
vector<vector<vector<su2passivematrix> > > Cross_Terms;
/*!< \brief Fixed-Point corrector that can be applied to inner iterations. */
vector<CQuasiNewtonInvLeastSquares<passivedouble> > FixPtCorrector;
/*!< \brief Members to use GMRES to drive inner iterations (alternative to quasi-Newton). */
static constexpr unsigned long KrylovMinIters = 3;
const Scalar KrylovTol = 0.01;
vector<CSysSolve<Scalar> > LinSolver;
vector<CSysVector<Scalar> > AdjRHS, AdjSol;
public:
/*!
* \brief Constructor of the class.
* \param[in] confFile - Configuration file name.
* \param[in] val_nZone - Total number of zones.
* \param[in] MPICommunicator - MPI communicator for SU2.
*/
CDiscAdjMultizoneDriver(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunicator);
/*!
* \brief Destructor of the class.
*/
~CDiscAdjMultizoneDriver(void) override;
/*!
* \brief [Overload] Launch the computation for discrete adjoint multizone problems.
*/
void StartSolver() override;
/*!
* \brief Preprocess the multizone iteration
*/
void Preprocess(unsigned long TimeIter) override;
/*!
* \brief [Overload] Run an discrete adjoint update of all solvers within multiple zones.
*/
void Run() override;
protected:
/*!
* \brief Run one inner iteration for a given zone.
* \return The result of "monitor".
*/
bool Iterate(unsigned short iZone, unsigned long iInnerIter, bool KrylovMode = false);
/*!
* \brief Run inner iterations using a Krylov method (GMRES atm).
*/
void KrylovInnerIters(unsigned short iZone);
/*!
* \brief Evaluate the gradient of the objective function and add to "External".
* \return "True" if the gradient is numerically 0.
*/
bool EvaluateObjectiveFunctionGradient();
/*!
* \brief Evaluate sensitivites for the current adjoint solution and output files.
* \param[in] Iter - Current outer or time iteration.
* \param[in] force_writing - Force file output.
*/
void EvaluateSensitivities(unsigned long Iter, bool force_writing);
/*!
* \brief Setup the matrix of cross-terms. Allocate necessary memory and initialize to zero.
*/
void InitializeCrossTerms();
/*!
* \brief Record one iteration of the primal problem within each zone.
* \param[in] kind_recording - Kind of variables with respect to which we are recording.
* \param[in] tape_type - indicator which part of a solution update will be recorded.
* \param[in] record_zone - zone where solution update will be recorded.
*/
void SetRecording(RECORDING kind_recording, Kind_Tape tape_type, unsigned short record_zone);
/*!
* \brief Transfer data between zones and update grids when required.
*/
void HandleDataTransfer();
/*!
* \brief Run one direct iteration in a zone.
* \param[in] iZone - Zone in which we run an iteration.
* \param[in] kind_recording - Kind of variables with respect to which we are recording.
*/
void DirectIteration(unsigned short iZone, RECORDING kind_recording);
/*!
* \brief Set the objective function.
* \param[in] kind_recording - Kind of variables with respect to which we are recording.
*/
void SetObjFunction(RECORDING kind_recording);
/*!
* \brief Initialize the adjoint value of the objective function.
*/
void SetAdjObjFunction();
/*!
* \brief Summary of all routines to evaluate the adjoints in iZone.
* \param[in] iZone - Zone in which adjoints are evaluated depending on their (preceding) seeding.
* \param[in] eval_transfer - Evaluate adjoints of transfer and mesh deformation routines.
*/
void ComputeAdjoints(unsigned short iZone, bool eval_transfer = true);
/*!
* \brief Puts BGSSolution_k back into Solution.
* \param[in] iZone - Zone index.
*/
void Set_Solution_To_BGSSolution_k(unsigned short iZone);
/*!
* \brief Puts Solution into BGSSolution_k.
* \param[in] iZone - Zone index.
*/
void Set_BGSSolution_k_To_Solution(unsigned short iZone);
/*!
* \brief Add Solution vector to External.
* \param[in] iZone - Zone index.
*/
void AddSolutionToExternal(unsigned short iZone);
/*!
* \brief Puts dual time derivative vector to External.
*/
void SetExternalToDualTimeDer();
/*!
* \brief Add External_Old vector to Solution.
* \param[in] iZone - Zone index.
*/
void AddExternalToSolution(unsigned short iZone);
/*!
* \brief Puts Solution into SolutionOld.
* \param[in] iZone - Zone index.
*/
void SetSolutionOldToSolution(unsigned short iZone);
/*!
* \brief Extract contribution of iZone to jZone with BGS relaxation.
* \param[in] iZone - Source zone (the one that was initialized).
* \param[in] jZone - Target zone (the one that transfers to iZone in the primal problem).
*/
void UpdateCrossTerm(unsigned short iZone, unsigned short jZone);
/*!
* \brief Compute BGS residuals.
* \param[in] iZone - Zone where solver residuals are computed.
*/
void SetResidual_BGS(unsigned short iZone);
/*!
* \brief gets Convergence on physical time scale, (deactivated in adjoint case)
* \return false
*/
inline bool GetTimeConvergence() const override { return false; }
/*!
* \brief Get the external of all adjoint solvers in a zone.
* \param[in] iZone - Index of the zone.
* \param[out] rhs - Object with interface (iPoint,iVar), set to -external.
*/
template<class Container>
void GetAdjointRHS(unsigned short iZone, Container& rhs) const {
const auto nPoint = geometry_container[iZone][INST_0][MESH_0]->GetnPoint();
for (auto iSol = 0u, offset = 0u; iSol < MAX_SOLS; ++iSol) {
auto solver = solver_container[iZone][INST_0][MESH_0][iSol];
if (!(solver && solver->GetAdjoint())) continue;
const auto& ext = solver->GetNodes()->Get_External();
for (auto iPoint = 0ul; iPoint < nPoint; ++iPoint)
for (auto iVar = 0ul; iVar < solver->GetnVar(); ++iVar)
rhs(iPoint,offset+iVar) = -SU2_TYPE::GetValue(ext(iPoint,iVar));
offset += solver->GetnVar();
}
}
/*!
* \brief Launch the tape test run of the discrete adjoint multizone solver.
*/
void TapeTest ();
/*!
* \brief Get the total error count after a tape test run of the discrete adjoint multizone solver.
* \param[in] debug_control - DebugControl from which this rank's contribution to the total error count is read.
* \return The total error count across all ranks.
*/
int TapeTestGatherErrors(AD::DebugControl& debug_control) const;
};