Documentation 6b54b78464
Loading...
Searching...
No Matches
ad_structure.hpp
Go to the documentation of this file.
1/*!
2 * \file ad_structure.hpp
3 * \brief Main routines for the algorithmic differentiation (AD) structure.
4 * \author T. Albring, J. Blühdorn, O. Burghardt
5 * \version 8.5.0 "Harrier"
6 *
7 * SU2 Project Website: https://su2code.github.io
8 *
9 * The SU2 Project is maintained by the SU2 Foundation
10 * (http://su2foundation.org)
11 *
12 * Copyright 2012-2026, SU2 Contributors (cf. AUTHORS.md)
13 *
14 * SU2 is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
18 *
19 * SU2 is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with SU2. If not, see <http://www.gnu.org/licenses/>.
26 */
27
28#pragma once
29
30#include "../code_config.hpp"
31#include "../parallelization/omp_structure.hpp"
32
33/*!
34 * \namespace AD
35 * \brief Contains routines for the reverse mode of AD.
36 * In case there is no reverse type configured, they have no effect at all,
37 * and so the real versions of the routined are after #else.
38 */
39
40namespace AD {
41
53
54#ifndef CODI_REVERSE_TYPE
55
56using Identifier = int;
57
58/*!
59 * \brief Start the recording of the operations and involved variables.
60 * If called, the computational graph of all operations occuring after the call will be stored,
61 * starting with the variables registered with RegisterInput.
62 */
63inline void StartRecording() {}
64
65/*!
66 * \brief Pause the recording of the operations and involved variables.
67 * If called, all operations occuring after the call will not be stored on the computational graph.
68 */
69inline bool PauseRecording() { return false; }
70
71/*!
72 * \brief Resume the recording of the operations and variables after the recording had been paused.
73 */
74inline void ResumeRecording(bool wasActive) { (void)wasActive; }
75
76/*!
77 * \brief Stops the recording of the operations and variables.
78 */
79inline void StopRecording() {}
80
81/*!
82 * \brief Check if the tape is active
83 * \param[out] Boolean which determines whether the tape is active.
84 */
85inline bool TapeActive() { return false; }
86
87/*!
88 * \brief Prints out tape statistics.
89 *
90 * Tape statistics are aggregated across OpenMP threads and MPI processes, if applicable.
91 * With MPI, the given communicator is used to reduce data across MPI processes, and the printing behaviour can be set
92 * per rank (usually, only the master rank prints).
93 */
94template <typename Comm>
95inline void PrintStatistics(Comm communicator, bool printingRank) {}
96
97/*!
98 * \brief Registers the variable as an input. I.e. as a leaf of the computational graph.
99 * \param[in] data - The variable to be registered as input.
100 */
101inline void RegisterInput(su2double& data) {}
102
103/*!
104 * \brief Registers the variable as an output. I.e. as the root of the computational graph.
105 * \param[in] data - The variable to be registered as output.
106 */
107inline void RegisterOutput(su2double& data) {}
108
109/*!
110 * \brief Resize the adjoint vector, for subsequent access without bounds checking.
111 */
112inline void ResizeAdjoints() {}
113
114/*!
115 * \brief Declare that the adjoints are being used, to protect against resizing.
116 *
117 * Should be used together with AD::EndUseAdjoints() to protect AD::SetDerivative() and AD::GetDerivative() calls,
118 * multiple at once if possible.
119 */
120inline void BeginUseAdjoints() {}
121
122/*!
123 * \brief Declare that the adjoints are no longer being used.
124 */
125inline void EndUseAdjoints() {}
126
127/*!
128 * \brief Sets the adjoint value at index to val
129 * \param[in] index - Position in the adjoint vector.
130 * \param[in] val - adjoint value to be set.
131 */
132inline void SetDerivative(Identifier index, const double val) {}
133
134/*!
135 * \brief Extracts the adjoint value at index
136 * \param[in] index - position in the adjoint vector where the derivative will be extracted.
137 * \return Derivative value.
138 */
139inline double GetDerivative(Identifier index) { return 0.0; }
140
141/*!
142 * \brief Returns the identifier that represents an inactive variable.
143 * \return Passive index.
144 */
145inline Identifier GetPassiveIndex() { return 0; }
146
147/*!
148 * \brief Clears the currently stored adjoints but keeps the computational graph.
149 */
150inline void ClearAdjoints() {}
151
152/*!
153 * \brief Computes the adjoints, i.e. the derivatives of the output with respect to the input variables.
154 */
155inline void ComputeAdjoint() {}
156
157/*!
158 * \brief Computes the adjoints, i.e. the derivatives of the output with respect to the input variables.
159 * \param[in] enter - Position where we start evaluating the tape.
160 * \param[in] leave - Position where we stop evaluating the tape.
161 */
162inline void ComputeAdjoint(unsigned short enter, unsigned short leave) {}
163
164/*!
165 * \brief Computes the adjoints, i.e., the derivatives of the output with respect to the input variables, using forward
166 * tape evaluation.
167 */
168inline void ComputeAdjointForward() {}
169
170/*!
171 * \brief Reset the tape structure to be ready for a new recording.
172 */
173inline void Reset() {}
174
175/*!
176 * \brief Reset the variable (set index to zero).
177 * \param[in] data - the variable to be unregistered from the tape.
178 */
179inline void ResetInput(su2double& data) {}
180
181/*!
182 * \brief Sets the scalar inputs of a preaccumulation section.
183 * \param[in] data - the scalar input variables.
184 */
185template <class... Ts>
186inline void SetPreaccIn(Ts&&... data) {}
187
188/*!
189 * \brief Sets the input variables of a preaccumulation section using a 1D array.
190 * \param[in] data - the input 1D array.
191 * \param[in] size - size of the array.
192 */
193template <class T>
194inline void SetPreaccIn(const T& data, const int size) {}
195
196/*!
197 * \brief Sets the input variables of a preaccumulation section using a 2D array.
198 * \param[in] data - the input 2D array.
199 * \param[in] size_x - size of the array in x dimension.
200 * \param[in] size_y - size of the array in y dimension.
201 */
202template <class T>
203inline void SetPreaccIn(const T& data, const int size_x, const int size_y) {}
204
205/*!
206 * \brief Starts a new preaccumulation section and sets the input variables.
207 *
208 * The idea of preaccumulation is to store only the Jacobi matrix of a code section during
209 * the taping process instead of all operations. This decreases the tape size and reduces runtime.
210 *
211 * Input/Output of the section are set with several calls to SetPreaccIn()/SetPreaccOut().
212 *
213 * Note: the call of this routine must be followed by a call of EndPreacc() and the end of the code section.
214 */
215inline void StartPreacc() {}
216
217/*!
218 * \brief Sets the scalar outputs of a preaccumulation section.
219 * \param[in] data - the scalar output variables.
220 */
221template <class... Ts>
222inline void SetPreaccOut(Ts&&... data) {}
223
224/*!
225 * \brief Sets the output variables of a preaccumulation section using a 1D array.
226 * \param[in] data - the output 1D array.
227 */
228template <class T>
229inline void SetPreaccOut(T&& data, const int size) {}
230
231/*!
232 * \brief Sets the input variables of a preaccumulation section using a 2D array.
233 * \param[in] data - the output 1D array.
234 */
235template <class T>
236inline void SetPreaccOut(T&& data, const int size_x, const int size_y) {}
237
238/*!
239 * \brief Ends a preaccumulation section and computes the local Jacobi matrix
240 * of a code section using the variables set with SetLocalInput(), SetLocalOutput() and pushes a statement
241 * for each output variable to the AD tape.
242 */
243inline void EndPreacc() {}
244
245/*!
246 * \brief Sets the scalar input of a externally differentiated function.
247 * \param[in] data - the scalar input variable.
248 */
249inline void SetExtFuncIn(su2double& data) {}
250
251/*!
252 * \brief Sets the input variables of a externally differentiated function using a 1D array.
253 * \param[in] data - the input 1D array.
254 * \param[in] size - number of rows.
255 */
256template <class T>
257inline void SetExtFuncIn(const T& data, const int size) {}
258
259/*!
260 * \brief Sets the input variables of a externally differentiated function using a 2D array.
261 * \param[in] data - the input 2D array.
262 * \param[in] size_x - number of rows.
263 * \param[in] size_y - number of columns.
264 */
265template <class T>
266inline void SetExtFuncIn(const T& data, const int size_x, const int size_y) {}
267
268/*!
269 * \brief Sets the scalar output of a externally differentiated function.
270 * \param[in] data - the scalar output variable.
271 */
272inline void SetExtFuncOut(su2double& data) {}
273
274/*!
275 * \brief Sets the output variables of a externally differentiated function using a 1D array.
276 * \param[in] data - the output 1D array.
277 * \param[in] size - number of rows.
278 */
279template <class T>
280inline void SetExtFuncOut(T&& data, const int size) {}
281
282/*!
283 * \brief Sets the output variables of a externally differentiated function using a 2D array.
284 * \param[in] data - the output 2D array.
285 * \param[in] size_x - number of rows.
286 * \param[in] size_y - number of columns.
287 */
288template <class T>
289inline void SetExtFuncOut(T&& data, const int size_x, const int size_y) {}
290
291/*!
292 * \brief Evaluates and saves gradient data from a variable.
293 * \param[in] data - variable whose gradient information will be extracted.
294 * \param[in] index - where obtained gradient information will be stored.
295 */
296inline void SetIndex(Identifier& index, const su2double& data) {}
297
298/*!
299 * \brief Sets the tag tape to a specific tag.
300 * \param[in] tag - the number to which the tag is set.
301 */
302inline void SetTag(int tag) {}
303
304/*!
305 * \brief Gets the current tag.
306 * \param[in] tag - the number to which the tag is set.
307 */
308inline int GetTag() { return 0; }
309
310/*!
311 * \brief Compute the zone-specific tag.
312 * \param[in] iZone - Zone index from which the zone-specific tag is formed.
313 * \return The zone-specific tag.
314 */
315inline int ComputeTag(unsigned short iZone) { return 0; }
316
317/*!
318 * \brief Sets the tag of a variable to 0.
319 * \param[in] v - the variable whose tag is cleared.
320 */
322
323/*!
324 * \brief Sets the tag of a variable to a specified value.
325 * \param[in] v - the variable whose tag is set manually.
326 */
327inline void SetTagOnVariable(su2double& v, int zone_tag = 0, int run_tag = 0) {}
328
329/*!
330 * \brief Struct to store information about errors during a tag debug run.
331 */
332struct DebugControl {};
333
334/*!
335 * \brief Set a pointer to the current DebugControl.
336 * \param[in] control - pointer to the current debug control.
337 */
338inline void SetDebugControl(DebugControl* control) {}
339
340/*!
341 * \brief Set options which kind of tag mismatches are considered errors and written to file.
342 * \param[in] option - specification which kind of tag mismatches are considered.
343 * \param[in] izone - the zone w.r.t. which a tag mismatch is allowed.
344 */
345inline void SetTapeDebugOption(TAPE_DEBUG_OPTION option, unsigned short izone = 0) {}
346
347/*!
348 * \brief Activate the error callback by letting the tape call tagErrorCallback whenever a tag mismatch arises.
349 */
351
352/*!
353 * \brief Set a pointer to the output file of a DebugControl.
354 * \param[in] control - the DebugControl whose output file is set.
355 * \param[in] output_file - pointer to the output file.
356 */
357inline void SetDebugReportFile(DebugControl& control, std::ostream* output_file) {}
358
359/*!
360 * \brief Reset the error counter in a DebugControl.
361 * \param[in] control - the DebugControl whose error counter is resetted.
362 */
363inline void ResetErrorCounter(DebugControl& control) {}
364
365/*!
366 * \brief Get the error count of a DebugControl.
367 * \param[in] control - the DebugControl whose error count is reported.
368 * \return Value of the error counter.
369 */
370inline unsigned long GetErrorCount(const DebugControl& control) { return 0; }
371
372/*!
373 * \brief Pushes back the current tape position to the tape position's vector.
374 */
375inline void Push_TapePosition() {}
376
377/*!
378 * \brief Start a passive region, i.e. stop recording.
379 * \return True if tape was active.
380 */
381inline bool BeginPassive() { return false; }
382
383/*!
384 * \brief End a passive region, i.e. start recording if we were recording before.
385 * \param[in] wasActive - Whether we were recording before entering the passive region.
386 */
387inline void EndPassive(bool wasActive) {}
388
389/*!
390 * \brief Pause the use of preaccumulation.
391 * \return True if preaccumulation was active.
392 */
393inline bool PausePreaccumulation() { return false; }
394
395/*!
396 * \brief Resume the use of preaccumulation.
397 * \param[in] wasActive - Whether preaccumulation was active before pausing.
398 */
399inline void ResumePreaccumulation(bool wasActive) {}
400
401/*!
402 * \brief Begin a hybrid parallel adjoint evaluation mode that assumes an inherently safe reverse path.
403 */
404inline void StartNoSharedReading() {}
405
406/*!
407 * \brief End the "no shared reading" adjoint evaluation mode.
408 */
409inline void EndNoSharedReading() {}
410
411#else
412using CheckpointHandler = codi::ExternalFunctionUserData;
413
414using Tape = su2double::Tape;
415using Identifier = su2double::Identifier;
416
417#ifdef HAVE_OPDI
418using ExtFuncHelper = codi::OpenMPExternalFunctionHelper<su2double>;
419#else
420using ExtFuncHelper = codi::ExternalFunctionHelper<su2double>;
421#endif
422
423extern ExtFuncHelper FuncHelper;
424
425extern bool PreaccActive;
426#ifdef HAVE_OPDI
427SU2_OMP(threadprivate(PreaccActive))
428#endif
429
430extern bool PreaccEnabled;
431
432#ifdef HAVE_OPDI
433using CoDiTapePosition = Tape::Position;
434using OpDiState = void*;
435using TapePosition = std::pair<CoDiTapePosition, OpDiState>;
436#else
437using TapePosition = Tape::Position;
438#endif
439
440extern TapePosition StartPosition, EndPosition;
441
442extern std::vector<TapePosition> TapePositions;
443
444extern codi::PreaccumulationHelper<su2double> PreaccHelper;
445#ifdef HAVE_OPDI
446SU2_OMP(threadprivate(PreaccHelper))
447#endif
448
449/*--- Reference to the tape. ---*/
450
451FORCEINLINE Tape& getTape() { return su2double::getTape(); }
452
453FORCEINLINE void RegisterInput(su2double& data) { AD::getTape().registerInput(data); }
454
455FORCEINLINE void RegisterOutput(su2double& data) { AD::getTape().registerOutput(data); }
456
457FORCEINLINE void ResetInput(su2double& data) { data = data.getValue(); }
458
459FORCEINLINE void StartRecording() { AD::getTape().setActive(); }
460
462 if (AD::getTape().isActive()) {
463 AD::getTape().setPassive();
464 return true;
465 }
466 return false;
467}
468
469FORCEINLINE void ResumeRecording(bool wasActive) {
470 if (wasActive) {
471 AD::getTape().setActive();
472 }
473}
474
475FORCEINLINE void StopRecording() { AD::getTape().setPassive(); }
476
477FORCEINLINE bool TapeActive() { return AD::getTape().isActive(); }
478
479template <typename Comm>
480FORCEINLINE void PrintStatistics(Comm communicator, bool printingRank) {
481 if (printingRank) {
482 std::cout << "-------------------------------------------------------\n";
483 std::cout << " Serial parts of the tape\n";
484#ifdef HAVE_MPI
485 std::cout << " (aggregated across MPI processes)\n";
486#endif
487 std::cout << "-------------------------------------------------------\n";
488 }
489
490 codi::TapeValues serialTapeValues = AD::getTape().getTapeValues();
491 serialTapeValues.combineDataMPI(communicator);
492
493 if (printingRank) {
494 serialTapeValues.formatDefault(std::cout);
495 }
496
497 double totalMemoryUsed = serialTapeValues.getUsedMemorySize();
498 double totalMemoryAllocated = serialTapeValues.getAllocatedMemorySize();
499
500#ifdef HAVE_OPDI
501
502 if (printingRank) {
503 std::cout << "-------------------------------------------------------\n";
504 std::cout << " OpenMP parallel parts of the tape\n";
505 std::cout << " (aggregated across OpenMP threads)\n";
506#ifdef HAVE_MPI
507 std::cout << " (aggregated across MPI processes)\n";
508#endif
509 std::cout << "-------------------------------------------------------\n";
510 }
511
512 codi::TapeValues* aggregatedOpenMPTapeValues = nullptr;
513
514 // clang-format off
515
517 if (omp_get_thread_num() == 0) { // master thread
518 codi::TapeValues masterTapeValues = AD::getTape().getTapeValues();
519 aggregatedOpenMPTapeValues = &masterTapeValues;
520
521 SU2_OMP_BARRIER // master completes initialization
522 SU2_OMP_BARRIER // other threads complete adding their data
523
524 aggregatedOpenMPTapeValues->combineDataMPI(communicator);
525 totalMemoryUsed += aggregatedOpenMPTapeValues->getUsedMemorySize();
526 totalMemoryAllocated += aggregatedOpenMPTapeValues->getAllocatedMemorySize();
527 if (printingRank) {
528 aggregatedOpenMPTapeValues->formatDefault(std::cout);
529 }
530 aggregatedOpenMPTapeValues = nullptr;
531 } else { // other threads
532 SU2_OMP_BARRIER // master completes initialization
534 aggregatedOpenMPTapeValues->combineData(AD::getTape().getTapeValues());
536 SU2_OMP_BARRIER // other threads complete adding their data
537 }
539
540// clang-format on
541#endif
542
543 if (printingRank) {
544 std::cout << "-------------------------------------------------------\n";
545 std::cout << " Total memory used : " << totalMemoryUsed / 1024.0 / 1024.0 << " MB\n";
546 std::cout << " Total memory allocated : " << totalMemoryAllocated / 1024.0 / 1024.0 << " MB\n";
547 std::cout << "-------------------------------------------------------\n";
548 }
549}
550
551FORCEINLINE void ClearAdjoints() { AD::getTape().clearAdjoints(); }
552
554#if defined(HAVE_OPDI)
555 opdi::logic->prepareEvaluate();
556#endif
557 AD::getTape().evaluate();
558#if defined(HAVE_OPDI)
559 opdi::logic->postEvaluate();
560#endif
561}
562
563FORCEINLINE void ComputeAdjoint(unsigned short enter, unsigned short leave) {
564#if defined(HAVE_OPDI)
565 opdi::logic->recoverState(TapePositions[enter].second);
566 opdi::logic->prepareEvaluate();
567 AD::getTape().evaluate(TapePositions[enter].first, TapePositions[leave].first);
568#else
569 AD::getTape().evaluate(TapePositions[enter], TapePositions[leave]);
570#endif
571}
572
573FORCEINLINE void ComputeAdjointForward() { AD::getTape().evaluateForward(); }
574
575FORCEINLINE void Reset() {
576 AD::getTape().reset();
577#if defined(HAVE_OPDI)
578 opdi::logic->reset();
579#endif
580 if (TapePositions.size() != 0) {
581#if defined(HAVE_OPDI)
582 for (TapePosition& pos : TapePositions) {
583 opdi::logic->freeState(pos.second);
584 }
585#endif
586 TapePositions.clear();
587 }
588}
589
590FORCEINLINE void ResizeAdjoints() { AD::getTape().resizeAdjointVector(); }
591
592FORCEINLINE void BeginUseAdjoints() { AD::getTape().beginUseAdjointVector(); }
593
594FORCEINLINE void EndUseAdjoints() { AD::getTape().endUseAdjointVector(); }
595
596FORCEINLINE void SetIndex(Identifier& index, const su2double& data) { index = data.getIdentifier(); }
597
598// WARNING: For performance reasons, this method does not perform bounds checking.
599// When using it, please ensure sufficient adjoint vector size by a call to AD::ResizeAdjoints().
600// This method does not perform locking either.
601// It should be safeguarded by calls to AD::BeginUseAdjoints() and AD::EndUseAdjoints().
602FORCEINLINE void SetDerivative(Identifier index, const double val) {
603 // Allow multiple threads to "set the derivative" of passive variables without causing data races.
604 if (!AD::getTape().isIdentifierActive(index)) return;
605
606 AD::getTape().setGradient(index, val, codi::AdjointsManagement::Manual);
607}
608
609// WARNING: For performance reasons, this method does not perform bounds checking.
610// If called after tape evaluations, the adjoints should exist.
611// Otherwise, please ensure sufficient adjoint vector size by a call to AD::ResizeAdjoints().
612// This method does not perform locking either.
613// It should be safeguarded by calls to AD::BeginUseAdjoints() and AD::EndUseAdjoints().
615 return AD::getTape().getGradient(index, codi::AdjointsManagement::Manual);
616}
617
618FORCEINLINE Identifier GetPassiveIndex() { return AD::getTape().getPassiveIndex(); }
619
620/*--- Base case for parameter pack expansion. ---*/
621FORCEINLINE void SetPreaccIn() {}
622
623template <class T, class... Ts, su2enable_if<std::is_same<T, su2double>::value> = 0>
624FORCEINLINE void SetPreaccIn(const T& data, Ts&&... moreData) {
625 if (!PreaccActive) return;
626 PreaccHelper.addInput(data);
627 SetPreaccIn(moreData...);
628}
629
630template <class T, class... Ts, su2enable_if<std::is_same<T, su2double>::value> = 0>
631FORCEINLINE void SetPreaccIn(T&& data, Ts&&... moreData) {
632 static_assert(!std::is_same<T, su2double>::value, "rvalues cannot be registered");
633}
634
635template <class T>
636FORCEINLINE void SetPreaccIn(const T& data, const int size) {
637 if (PreaccActive) {
638 for (int i = 0; i < size; i++) {
639 PreaccHelper.addInput(data[i]);
640 }
641 }
642}
643
644template <class T>
645FORCEINLINE void SetPreaccIn(const T& data, const int size_x, const int size_y) {
646 if (!PreaccActive) return;
647 for (int i = 0; i < size_x; i++) {
648 for (int j = 0; j < size_y; j++) {
649 PreaccHelper.addInput(data[i][j]);
650 }
651 }
652}
653
655 if (AD::getTape().isActive() && PreaccEnabled) {
656 PreaccHelper.start();
657 PreaccActive = true;
658 }
659}
660
661/*--- Base case for parameter pack expansion. ---*/
663
664template <class T, class... Ts, su2enable_if<std::is_same<T, su2double>::value> = 0>
665FORCEINLINE void SetPreaccOut(T& data, Ts&&... moreData) {
666 if (!PreaccActive) return;
667 PreaccHelper.addOutput(data);
668 SetPreaccOut(moreData...);
669}
670
671template <class T>
672FORCEINLINE void SetPreaccOut(T&& data, const int size) {
673 if (PreaccActive) {
674 for (int i = 0; i < size; i++) {
675 PreaccHelper.addOutput(data[i]);
676 }
677 }
678}
679
680template <class T>
681FORCEINLINE void SetPreaccOut(T&& data, const int size_x, const int size_y) {
682 if (!PreaccActive) return;
683 for (int i = 0; i < size_x; i++) {
684 for (int j = 0; j < size_y; j++) {
685 PreaccHelper.addOutput(data[i][j]);
686 }
687 }
688}
689
691#if defined(HAVE_OPDI)
692 TapePositions.push_back({AD::getTape().getPosition(), opdi::logic->exportState()});
693#else
694 TapePositions.push_back(AD::getTape().getPosition());
695#endif
696}
697
698FORCEINLINE void EndPreacc() {
699 if (PreaccActive) {
700 PreaccHelper.finish(false);
701 PreaccActive = false;
702 }
703}
704
705FORCEINLINE void SetExtFuncIn(const su2double& data) { FuncHelper.addInput(data); }
706
707template <class T>
708FORCEINLINE void SetExtFuncIn(const T& data, const int size) {
709 for (int i = 0; i < size; i++) {
710 FuncHelper.addInput(data[i]);
711 }
712}
713
714template <class T>
715FORCEINLINE void SetExtFuncIn(const T& data, const int size_x, const int size_y) {
716 for (int i = 0; i < size_x; i++) {
717 for (int j = 0; j < size_y; j++) {
718 FuncHelper.addInput(data[i][j]);
719 }
720 }
721}
722
724 if (AD::getTape().isActive()) {
725 FuncHelper.addOutput(data);
726 }
727}
728
729template <class T>
730FORCEINLINE void SetExtFuncOut(T&& data, const int size) {
731 for (int i = 0; i < size; i++) {
732 if (AD::getTape().isActive()) {
733 FuncHelper.addOutput(data[i]);
734 }
735 }
736}
737
738template <class T>
739FORCEINLINE void SetExtFuncOut(T&& data, const int size_x, const int size_y) {
740 for (int i = 0; i < size_x; i++) {
741 for (int j = 0; j < size_y; j++) {
742 if (AD::getTape().isActive()) {
743 FuncHelper.addOutput(data[i][j]);
744 }
745 }
746 }
747}
748
749FORCEINLINE void delete_handler(void* handler) {
750 CheckpointHandler* checkpoint = static_cast<CheckpointHandler*>(handler);
751 checkpoint->clear();
752}
753
755 if (AD::getTape().isActive()) {
756 AD::getTape().setPassive();
757 return true;
758 }
759 return false;
760}
761
762FORCEINLINE void EndPassive(bool wasActive) {
763 if (wasActive) AD::getTape().setActive();
764}
765
767#ifdef HAVE_OPDI
768 opdi::logic->setAdjointAccessMode(opdi::LogicInterface::AdjointAccessMode::Classical);
769 opdi::logic->addReverseBarrier();
770#endif
771}
772
774#ifdef HAVE_OPDI
775 opdi::logic->setAdjointAccessMode(opdi::LogicInterface::AdjointAccessMode::Atomic);
776 opdi::logic->addReverseBarrier();
777#endif
778}
779
781 const auto current = PreaccEnabled;
782 if (!current) return false;
783 SU2_OMP_SAFE_GLOBAL_ACCESS(PreaccEnabled = false;)
784 return true;
785}
786
787FORCEINLINE void ResumePreaccumulation(bool wasActive) {
788 if (!wasActive) return;
789 SU2_OMP_SAFE_GLOBAL_ACCESS(PreaccEnabled = true;)
790}
791
792#ifdef CODI_TAG_TAPE
793
794struct DebugControl {
795 int current_tag;
796 bool multizone_tags = false;
797 bool init_run = false;
798 bool allow_preacc = false;
799 bool allow_zones = false;
800 unsigned short allow_izone = 0;
801 unsigned long ErrorCounter = 0;
802 std::ostream* out = &std::cout;
803};
804
805struct AdjustDebugControl {
806 TAPE_DEBUG_OPTION option;
807 void (*adjust)(DebugControl*, unsigned short);
808};
809
810static const AdjustDebugControl debug_control_adjustments[] = {
811 {TAPE_DEBUG_OPTION::ALLOW_PREACC, [](DebugControl* c, unsigned short) { c->allow_preacc = true; }},
812 {TAPE_DEBUG_OPTION::ACTIVATE_PREACC, [](DebugControl* c, unsigned short) { c->allow_preacc = false; }},
813 {TAPE_DEBUG_OPTION::ALLOW_ZONE, [](DebugControl* c, unsigned short zone) { c->allow_izone = zone + 1; }},
814 {TAPE_DEBUG_OPTION::ALLOW_ALL_ZONES, [](DebugControl* c, unsigned short) { c->allow_zones = true; }},
816 [](DebugControl* c, unsigned short) {
817 c->allow_zones = false;
818 c->allow_izone = 0;
819 }},
821 [](DebugControl* c, unsigned short) {
822 c->allow_preacc = false;
823 c->allow_zones = false;
824 c->allow_izone = 0;
825 }},
826 {TAPE_DEBUG_OPTION::INIT_RUN, [](DebugControl* c, unsigned short) { c->init_run = true; }},
827 {TAPE_DEBUG_OPTION::CHECK_RUN, [](DebugControl* c, unsigned short) { c->init_run = false; }},
828 {TAPE_DEBUG_OPTION::MULTIZONE_TAGS, [](DebugControl* c, unsigned short) { c->multizone_tags = true; }},
829};
830
831FORCEINLINE void ResetErrorCounter(DebugControl& control) { control.ErrorCounter = 0; }
832
833FORCEINLINE void SetDebugReportFile(DebugControl& control, std::ostream* output_file) { control.out = output_file; }
834
835FORCEINLINE unsigned long GetErrorCount(const DebugControl& control) { return control.ErrorCounter; }
836
837extern DebugControl* current_control;
838
839FORCEINLINE void SetDebugControl(DebugControl* control) { current_control = control; }
840
841FORCEINLINE void SetTag(int tag) {
842 current_control->current_tag = tag;
843 AD::getTape().setCurTag(tag);
844}
845
846FORCEINLINE int GetTag() { return current_control->current_tag; }
847
848FORCEINLINE int ComputeTag(unsigned short iZone) {
849 if (current_control->init_run) {
850 return (current_control->multizone_tags) ? ((int)iZone + 1) * 10 + 1 : 1;
851 } else {
852 return (current_control->multizone_tags) ? ((int)iZone + 1) * 10 + 2 : 2;
853 }
854}
855
856FORCEINLINE void ClearTagOnVariable(su2double& v) { AD::getTape().clearTagOnVariable(v); }
857
858FORCEINLINE void SetTagOnVariable(su2double& v, int zone_tag = 0, int run_tag = 0) {
859 int tag = v.getIdentifier().tag;
860 int tens = (zone_tag > 0) ? zone_tag + 1 : tag / 10;
861 int ones = (run_tag > 0 && run_tag < 10) ? run_tag : tag % 10;
862 if (tag != 0) {
863 v.getIdentifier().tag = tens * 10 + ones;
864 }
865}
866
867static void tagErrorCallback(const int& correctTag, const int& wrongTag, void* userData) {
868 auto* status = static_cast<DebugControl*>(userData);
869
870 bool throw_mismatch_error = true;
871
872 /*--- The callback could be due to a preaccumulation tag mismatch that we maybe want to allow, ... ---*/
873 if (status->allow_preacc) {
874 if (correctTag == 1337 || wrongTag == 1337) {
875 throw_mismatch_error = false;
876 }
877 }
878
879 /*--- ... or to a mismatch in the zone part of the tag. ---*/
880 if (status->allow_zones) {
881 throw_mismatch_error = false;
882 } else if (status->allow_izone > 0) {
883 if (wrongTag / 10 == status->allow_izone) {
884 throw_mismatch_error = false;
885 }
886 }
887
888 if (throw_mismatch_error) {
889 status->ErrorCounter += 1;
890 *(status->out) << "Use of variable with bad tag '" << std::setw(2) << std::setfill('0') << wrongTag
891 << "', should be '" << std::setw(2) << std::setfill('0') << correctTag << "'." << std::endl;
892 }
893}
894
895FORCEINLINE void SetTapeDebugOption(TAPE_DEBUG_OPTION option, unsigned short izone = 0) {
896 if (current_control == nullptr) {
897 return;
898 }
899 for (const AdjustDebugControl& entry : debug_control_adjustments) {
900 if (entry.option == option) {
901 entry.adjust(current_control, izone);
902 break;
903 }
904 }
905}
906
908 if (current_control != NULL) {
909 AD::getTape().setTagErrorCallback(tagErrorCallback, current_control);
910 } else {
911 std::cout << "No tape debug control set!" << std::endl;
912 }
913}
914
915#else
916struct DebugControl {};
917FORCEINLINE void ResetErrorCounter(DebugControl& control) {}
918FORCEINLINE void SetDebugReportFile(DebugControl& control, std::ostream* output_file) {}
919FORCEINLINE unsigned long GetErrorCount(const DebugControl& control) { return 0; }
920FORCEINLINE void SetDebugControl(DebugControl* status) {}
921FORCEINLINE int GetTag() { return 0; }
922FORCEINLINE void SetTag(int tag) {}
923FORCEINLINE int ComputeTag(unsigned short iZone) { return 0; }
925FORCEINLINE void SetTagOnVariable(su2double& v, int zone_tag = 0, int run_tag = 0) {}
926FORCEINLINE void SetTapeDebugOption(TAPE_DEBUG_OPTION option, unsigned short izone = 0) {}
928
929#endif // CODI_TAG_TAPE
930
931#endif // CODI_REVERSE_TYPE
932
933void Initialize();
934void Finalize();
935
936} // namespace AD
937
938/*--- If we compile under OSX we have to overload some of the operators for
939 * complex numbers to avoid the use of the standard operators
940 * (they use a lot of functions that are only defined for doubles) ---*/
941
942#ifdef __APPLE__
943
944namespace std {
945
946template <>
947inline su2double abs(const complex<su2double>& x) {
948 return sqrt(x.real() * x.real() + x.imag() * x.imag());
949}
950
951template <>
952inline complex<su2double> operator/(const complex<su2double>& x, const complex<su2double>& y) {
953 su2double d = (y.real() * y.real() + y.imag() * y.imag());
954 su2double real = (x.real() * y.real() + x.imag() * y.imag()) / d;
955 su2double imag = (x.imag() * y.real() - x.real() * y.imag()) / d;
956
957 return complex<su2double>(real, imag);
958}
959
960template <>
961inline complex<su2double> operator*(const complex<su2double>& x, const complex<su2double>& y) {
962 su2double real = (x.real() * y.real() - x.imag() * y.imag());
963 su2double imag = (x.imag() * y.real() + x.real() * y.imag());
964
965 return complex<su2double>(real, imag);
966}
967} // namespace std
968#endif
#define FORCEINLINE
Definition code_config.hpp:44
passivedouble su2double
Definition code_config.hpp:181
typename std::enable_if< condition, bool >::type su2enable_if
Definition code_config.hpp:75
FORCEINLINE ARRAY_T sqrt(const ARRAY_T &x)
Definition special_vectorization.hpp:116
FORCEINLINE ARRAY_T operator/(const ARRAY_T &a, const ARRAY_T &b)
Definition special_vectorization.hpp:130
FORCEINLINE ARRAY_T operator*(const ARRAY_T &a, const ARRAY_T &b)
Definition special_vectorization.hpp:129
FORCEINLINE ARRAY_T abs(const ARRAY_T &x)
Definition special_vectorization.hpp:117
Contains routines for the reverse mode of AD. In case there is no reverse type configured,...
void SetExtFuncIn(su2double &data)
Sets the scalar input of a externally differentiated function.
Definition ad_structure.hpp:249
void ComputeAdjoint()
Computes the adjoints, i.e. the derivatives of the output with respect to the input variables.
Definition ad_structure.hpp:155
bool PauseRecording()
Pause the recording of the operations and involved variables. If called, all operations occuring afte...
Definition ad_structure.hpp:69
void SetDebugControl(DebugControl *control)
Set a pointer to the current DebugControl.
Definition ad_structure.hpp:338
void RegisterInput(su2double &data)
Registers the variable as an input. I.e. as a leaf of the computational graph.
Definition ad_structure.hpp:101
void ClearTagOnVariable(su2double &v)
Sets the tag of a variable to 0.
Definition ad_structure.hpp:321
bool BeginPassive()
Start a passive region, i.e. stop recording.
Definition ad_structure.hpp:381
void SetTagOnVariable(su2double &v, int zone_tag=0, int run_tag=0)
Sets the tag of a variable to a specified value.
Definition ad_structure.hpp:327
void StartPreacc()
Starts a new preaccumulation section and sets the input variables.
Definition ad_structure.hpp:215
void SetExtFuncOut(su2double &data)
Sets the scalar output of a externally differentiated function.
Definition ad_structure.hpp:272
void EndPreacc()
Ends a preaccumulation section and computes the local Jacobi matrix of a code section using the varia...
Definition ad_structure.hpp:243
void ResumePreaccumulation(bool wasActive)
Resume the use of preaccumulation.
Definition ad_structure.hpp:399
void ResetErrorCounter(DebugControl &control)
Reset the error counter in a DebugControl.
Definition ad_structure.hpp:363
void PrintStatistics(Comm communicator, bool printingRank)
Prints out tape statistics.
Definition ad_structure.hpp:95
void Reset()
Reset the tape structure to be ready for a new recording.
Definition ad_structure.hpp:173
void ActivateTagErrorCallback()
Activate the error callback by letting the tape call tagErrorCallback whenever a tag mismatch arises.
Definition ad_structure.hpp:350
int Identifier
Definition ad_structure.hpp:56
void Finalize()
Definition ad_structure.cpp:64
void ResizeAdjoints()
Resize the adjoint vector, for subsequent access without bounds checking.
Definition ad_structure.hpp:112
void SetTapeDebugOption(TAPE_DEBUG_OPTION option, unsigned short izone=0)
Set options which kind of tag mismatches are considered errors and written to file.
Definition ad_structure.hpp:345
void Initialize()
Definition ad_structure.cpp:57
void Push_TapePosition()
Pushes back the current tape position to the tape position's vector.
Definition ad_structure.hpp:375
void ClearAdjoints()
Clears the currently stored adjoints but keeps the computational graph.
Definition ad_structure.hpp:150
void SetTag(int tag)
Sets the tag tape to a specific tag.
Definition ad_structure.hpp:302
double GetDerivative(Identifier index)
Extracts the adjoint value at index.
Definition ad_structure.hpp:139
void ResetInput(su2double &data)
Reset the variable (set index to zero).
Definition ad_structure.hpp:179
void SetDerivative(Identifier index, const double val)
Sets the adjoint value at index to val.
Definition ad_structure.hpp:132
void SetPreaccOut(Ts &&... data)
Sets the scalar outputs of a preaccumulation section.
Definition ad_structure.hpp:222
void StopRecording()
Stops the recording of the operations and variables.
Definition ad_structure.hpp:79
Identifier GetPassiveIndex()
Returns the identifier that represents an inactive variable.
Definition ad_structure.hpp:145
void SetPreaccIn(Ts &&... data)
Sets the scalar inputs of a preaccumulation section.
Definition ad_structure.hpp:186
void SetDebugReportFile(DebugControl &control, std::ostream *output_file)
Set a pointer to the output file of a DebugControl.
Definition ad_structure.hpp:357
void StartRecording()
Start the recording of the operations and involved variables. If called, the computational graph of a...
Definition ad_structure.hpp:63
int ComputeTag(unsigned short iZone)
Compute the zone-specific tag.
Definition ad_structure.hpp:315
void ComputeAdjointForward()
Computes the adjoints, i.e., the derivatives of the output with respect to the input variables,...
Definition ad_structure.hpp:168
void StartNoSharedReading()
Begin a hybrid parallel adjoint evaluation mode that assumes an inherently safe reverse path.
Definition ad_structure.hpp:404
void EndNoSharedReading()
End the "no shared reading" adjoint evaluation mode.
Definition ad_structure.hpp:409
int GetTag()
Gets the current tag.
Definition ad_structure.hpp:308
bool PausePreaccumulation()
Pause the use of preaccumulation.
Definition ad_structure.hpp:393
unsigned long GetErrorCount(const DebugControl &control)
Get the error count of a DebugControl.
Definition ad_structure.hpp:370
void SetIndex(Identifier &index, const su2double &data)
Evaluates and saves gradient data from a variable.
Definition ad_structure.hpp:296
bool TapeActive()
Check if the tape is active.
Definition ad_structure.hpp:85
void RegisterOutput(su2double &data)
Registers the variable as an output. I.e. as the root of the computational graph.
Definition ad_structure.hpp:107
TAPE_DEBUG_OPTION
Definition ad_structure.hpp:42
void ResumeRecording(bool wasActive)
Resume the recording of the operations and variables after the recording had been paused.
Definition ad_structure.hpp:74
void EndUseAdjoints()
Declare that the adjoints are no longer being used.
Definition ad_structure.hpp:125
void BeginUseAdjoints()
Declare that the adjoints are being used, to protect against resizing.
Definition ad_structure.hpp:120
void EndPassive(bool wasActive)
End a passive region, i.e. start recording if we were recording before.
Definition ad_structure.hpp:387
#define END_SU2_OMP_PARALLEL
Definition omp_structure.hpp:157
#define SU2_OMP_BARRIER
Definition omp_structure.hpp:142
#define SU2_OMP(ARGS)
Definition omp_structure.hpp:65
#define SU2_OMP_CRITICAL
Definition omp_structure.hpp:143
#define SU2_OMP_PARALLEL
Definition omp_structure.hpp:145
#define SU2_OMP_SAFE_GLOBAL_ACCESS(...)
Definition omp_structure.hpp:197
constexpr int omp_get_thread_num()
Index of current thread, akin to MPI rank.
Definition omp_structure.hpp:85
#define END_SU2_OMP_CRITICAL
Definition omp_structure.hpp:156
Struct to store information about errors during a tag debug run.
Definition ad_structure.hpp:332