From 85ad37074f40d9cf917d9de7542fbd3c5dc30f96 Mon Sep 17 00:00:00 2001 From: Ole Burghardt Date: Wed, 28 Jan 2026 15:55:19 +0100 Subject: [PATCH 01/19] Change some simple functions in ad_structure.hpp belonging to the tape check functionality. --- Common/include/CConfig.hpp | 8 ++--- Common/include/basic_types/ad_structure.hpp | 35 ++++++++++++--------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 45c4618fa485..21d5ea4d9118 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -5483,14 +5483,14 @@ class CConfig { unsigned short GetnVar(void); /*! - * \brief Provides the number of variables. - * \return Number of variables. + * \brief Provides the total number of zones. + * \return Total number of zones. */ unsigned short GetnZone(void) const { return nZone; } /*! - * \brief Provides the number of variables. - * \return Number of variables. + * \brief Provides the zone index the configuration belongs to. + * \return Zone index. */ unsigned short GetiZone(void) const { return iZone; } diff --git a/Common/include/basic_types/ad_structure.hpp b/Common/include/basic_types/ad_structure.hpp index 8ec6fabf7bed..177781489948 100644 --- a/Common/include/basic_types/ad_structure.hpp +++ b/Common/include/basic_types/ad_structure.hpp @@ -1,7 +1,7 @@ /*! * \file ad_structure.hpp * \brief Main routines for the algorithmic differentiation (AD) structure. - * \author T. Albring, J. Blühdorn + * \author T. Albring, J. Blühdorn, 0. Burghardt * \version 8.2.0 "Harrier" * * SU2 Project Website: https://su2code.github.io @@ -296,14 +296,14 @@ inline void ClearTagOnVariable(su2double& v) {} /*! * \brief Struct to store information about errors during a tag debug run. */ -struct ErrorReport {}; +struct DebugStatus {}; /*! - * \brief Set a reference to the output file of an ErrorReport. - * \param[in] report - the ErrorReport whose output file is set. + * \brief Set a pointer to the output file of a DebugStatus. + * \param[in] status - the DebugStatus whose output file is set. * \param[in] output_file - pointer to the output file. */ -inline void SetDebugReportFile(ErrorReport& report, std::ostream* output_file) {} +inline void SetDebugReportFile(DebugStatus& status, std::ostream* output_file) {} /*! * \brief Set the ErrorReport to which error information from a tag debug recording is written. @@ -312,17 +312,17 @@ inline void SetDebugReportFile(ErrorReport& report, std::ostream* output_file) { inline void SetTagErrorCallback(ErrorReport& report) {} /*! - * \brief Reset the error counter in an ErrorReport. - * \param[in] report - the ErrorReport whose error counter is resetted. + * \brief Reset the error counter in a DebugStatus. + * \param[in] status - the DebugStatus whose error counter is resetted. */ -inline void ResetErrorCounter(ErrorReport& report) {} +inline void ResetErrorCounter(DebugStatus& status) {} /*! - * \brief Get the error count of an ErrorReport. - * \param[in] report - the ErrorReport whose pointer to its error counter is returned. + * \brief Get the error count of a DebugStatus. + * \param[in] status - the DebugStatus whose error count is reported. * \return Value of the error counter. */ -inline unsigned long GetErrorCount(const ErrorReport& report) { return 0; } +inline unsigned long GetErrorCount(const DebugStatus& status) { return 0; } /*! * \brief Pushes back the current tape position to the tape position's vector. @@ -744,16 +744,21 @@ FORCEINLINE void ResumePreaccumulation(bool wasActive) { SU2_OMP_SAFE_GLOBAL_ACCESS(PreaccEnabled = true;) } -struct ErrorReport { +struct DebugStatus { + bool init_run = false; + bool ignore_preacc = false; + bool ignore_single_zone = false; + bool ignore_zones = false; + unsigned short ignore_izone = 0; unsigned long ErrorCounter = 0; std::ostream* out = &std::cout; }; -FORCEINLINE void ResetErrorCounter(ErrorReport& report) { report.ErrorCounter = 0; } +FORCEINLINE void ResetErrorCounter(DebugStatus& status) { status.ErrorCounter = 0; } -FORCEINLINE void SetDebugReportFile(ErrorReport& report, std::ostream* output_file) { report.out = output_file; } +FORCEINLINE void SetDebugReportFile(DebugStatus& status, std::ostream* output_file) { status.out = output_file; } -FORCEINLINE unsigned long GetErrorCount(const ErrorReport& report) { return report.ErrorCounter; } +FORCEINLINE unsigned long GetErrorCount(const DebugStatus& status) { return status.ErrorCounter; } #ifdef CODI_TAG_TAPE From a25b87183db250113d0e1c94d5353ea5ae1b8031 Mon Sep 17 00:00:00 2001 From: Ole Burghardt Date: Wed, 28 Jan 2026 17:04:54 +0100 Subject: [PATCH 02/19] Changes in CDiscAdjMultizoneDriver.hpp for extension of the tape check functionality. --- .../drivers/CDiscAdjMultizoneDriver.hpp | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/SU2_CFD/include/drivers/CDiscAdjMultizoneDriver.hpp b/SU2_CFD/include/drivers/CDiscAdjMultizoneDriver.hpp index 8eec26d2e82b..1befbacf2cab 100644 --- a/SU2_CFD/include/drivers/CDiscAdjMultizoneDriver.hpp +++ b/SU2_CFD/include/drivers/CDiscAdjMultizoneDriver.hpp @@ -141,16 +141,6 @@ class CDiscAdjMultizoneDriver : public CMultizoneDriver { */ void StartSolver() override; - /*! - * \brief [Overload] Launch the tape test mode for the discrete adjoint multizone solver. - */ - void TapeTest (); - - /*! - * \brief [Overload] Get error numbers after a tape test run of the discrete adjoint multizone solver. - */ - int TapeTestGatherErrors(AD::ErrorReport& error_report) const; - /*! * \brief Preprocess the multizone iteration */ @@ -303,4 +293,23 @@ class CDiscAdjMultizoneDriver : public CMultizoneDriver { } } + /*! + * \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_status - DebugStatus from which this rank's contribution to the total error count is read. + * \return The total error count across all ranks. + */ + int TapeTestGatherErrors(AD::DebugStatus& debug_status) const; + + /*! + * \brief Get the zone-specific tag. + * \param[in] iZone - Zone index from which the zone-specific tag is formed. + * \param[in] init - Boolean whether we want the initialization tag or the checking tag. + * \return The zone-specific tag. + */ + int TapeTestGetTag(unsigned short iZone, bool init) const; }; From 6bd7a4865d38f8e7e06aee63023eb969405a3c52 Mon Sep 17 00:00:00 2001 From: Ole Burghardt Date: Wed, 28 Jan 2026 17:07:26 +0100 Subject: [PATCH 03/19] Adding SetCurrentStatus to ad_structure.hpp for extension of the tape check functionality. --- Common/include/basic_types/ad_structure.hpp | 11 +++++++++++ Common/src/basic_types/ad_structure.cpp | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/Common/include/basic_types/ad_structure.hpp b/Common/include/basic_types/ad_structure.hpp index 177781489948..0bf16d86a9e2 100644 --- a/Common/include/basic_types/ad_structure.hpp +++ b/Common/include/basic_types/ad_structure.hpp @@ -298,6 +298,12 @@ inline void ClearTagOnVariable(su2double& v) {} */ struct DebugStatus {}; +/*! + * \brief Set a pointer to the current DebugStatus. + * \param[in] status - pointer to the current status. + */ +inline void SetCurrentStatus(DebugStatus *status) {} + /*! * \brief Set a pointer to the output file of a DebugStatus. * \param[in] status - the DebugStatus whose output file is set. @@ -762,6 +768,10 @@ FORCEINLINE unsigned long GetErrorCount(const DebugStatus& status) { return stat #ifdef CODI_TAG_TAPE +extern DebugStatus* current_status; + +FORCEINLINE void SetCurrentStatus(DebugStatus* status) { current_status = status; } + FORCEINLINE void SetTag(int tag) { AD::getTape().setCurTag(tag); } FORCEINLINE void ClearTagOnVariable(su2double& v) { AD::getTape().clearTagOnVariable(v); } @@ -777,6 +787,7 @@ FORCEINLINE void SetTagErrorCallback(ErrorReport& report) { } #else +FORCEINLINE void SetCurrentStatus(DebugStatus* status) {} FORCEINLINE void SetTag(int tag) {} FORCEINLINE void ClearTagOnVariable(su2double& v) {} FORCEINLINE void SetTagErrorCallback(ErrorReport report) {} diff --git a/Common/src/basic_types/ad_structure.cpp b/Common/src/basic_types/ad_structure.cpp index 489a47e400f6..30fff28e9697 100644 --- a/Common/src/basic_types/ad_structure.cpp +++ b/Common/src/basic_types/ad_structure.cpp @@ -48,6 +48,10 @@ SU2_OMP(threadprivate(PreaccHelper)) ExtFuncHelper FuncHelper; +#ifdef CODI_TAG_TAPE +DebugStatus* current_status = NULL; +#endif // CODI_TAG_TAPE + #endif void Initialize() { From ec85644f7a3df34da3e99c65dfea6e9515765517 Mon Sep 17 00:00:00 2001 From: Ole Burghardt Date: Thu, 29 Jan 2026 10:04:18 +0100 Subject: [PATCH 04/19] Extend tagErrorCallback to transform tag mismatches into errors in a more useful way. --- Common/include/basic_types/ad_structure.hpp | 35 +++++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/Common/include/basic_types/ad_structure.hpp b/Common/include/basic_types/ad_structure.hpp index 0bf16d86a9e2..a9df87147485 100644 --- a/Common/include/basic_types/ad_structure.hpp +++ b/Common/include/basic_types/ad_structure.hpp @@ -776,10 +776,39 @@ FORCEINLINE void SetTag(int tag) { AD::getTape().setCurTag(tag); } FORCEINLINE void ClearTagOnVariable(su2double& v) { AD::getTape().clearTagOnVariable(v); } static void tagErrorCallback(const int& correctTag, const int& wrongTag, void* userData) { - auto* report = static_cast(userData); + auto* status = static_cast(userData); - report->ErrorCounter += 1; - *(report->out) << "Use of variable with bad tag '" << wrongTag << "', should be '" << correctTag << "'." << std::endl; + bool throw_mismatch_error = true; + + if (status->ignore_preacc || status->ignore_single_zone || status->ignore_zones) { + + /*--- The callback could be due to a preaccumulation tag mismatch, if not, we deduce + * that it is either due to a zone index mismatch, or due to a mismatch in the least + * significant bit that will always result in an error. ---*/ + + if (correctTag == 1337) { + if (status->ignore_preacc) { + throw_mismatch_error = false; + } + } + else if (correctTag % 10 == wrongTag % 10) { + if (status->ignore_single_zone) { + /*--- A mismatch with a specified zone index might be allowed. ---*/ + if (wrongTag / 10 == status->ignore_single_zone) { + throw_mismatch_error = false; + } + } + if (status->ignore_zones) { + throw_mismatch_error = false; + } + } + } + + if (throw_mismatch_error) { + status->ErrorCounter += 1; + *(status->out) << "Use of variable with bad tag '" << std::setw(2) << std::setfill('0') << wrongTag + << "', should be '" << std::setw(2) << std::setfill('0') << correctTag << "'." << std::endl; + } } FORCEINLINE void SetTagErrorCallback(ErrorReport& report) { From d27cbd707538a59eca4c8407e336b80b956422cc Mon Sep 17 00:00:00 2001 From: Ole Burghardt Date: Thu, 29 Jan 2026 11:22:38 +0100 Subject: [PATCH 05/19] Set the tagErrorCallback function via a AD::SetCallbackMode wrapper. --- Common/include/basic_types/ad_structure.hpp | 49 ++++++++++++++++++--- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/Common/include/basic_types/ad_structure.hpp b/Common/include/basic_types/ad_structure.hpp index a9df87147485..b10024577484 100644 --- a/Common/include/basic_types/ad_structure.hpp +++ b/Common/include/basic_types/ad_structure.hpp @@ -36,7 +36,12 @@ * In case there is no reverse type configured, they have no effect at all, * and so the real versions of the routined are after #else. */ + namespace AD { + +enum class TAPE_TEST_MODE { IGNORE_PREACC, ACTIVATE_PREACC, IGNORE_SINGLE_ZONE, + ACTIVATE_SINGLE_ZONE, IGNORE_ZONES, ACTIVATE_ZONES, ACTIVATE_ALL}; + #ifndef CODI_REVERSE_TYPE using Identifier = int; @@ -304,6 +309,13 @@ struct DebugStatus {}; */ inline void SetCurrentStatus(DebugStatus *status) {} +/*! + * \brief Set the mode which kind of tag mismatches are considered errors and written to file. + * \param[in] kind_test_mode - specification which kind of tag mismatches are considered. + * \param[in] izone - the zone w.r.t. which a tag mismatch is allowed. + */ +inline void SetCallbackMode(TAPE_TEST_MODE kind_test_mode, unsigned short izone = 0) {} + /*! * \brief Set a pointer to the output file of a DebugStatus. * \param[in] status - the DebugStatus whose output file is set. @@ -312,10 +324,11 @@ inline void SetCurrentStatus(DebugStatus *status) {} inline void SetDebugReportFile(DebugStatus& status, std::ostream* output_file) {} /*! - * \brief Set the ErrorReport to which error information from a tag debug recording is written. - * \param[in] report - the ErrorReport to which error information is written. + * \brief Set the mode which kind of tag mismatches are considered errors and written to file. + * \param[in] kind_test_mode - specification which kind of tag mismatches are considered. + * \param[in] izone - the zone w.r.t. which a tag mismatch is allowed. */ -inline void SetTagErrorCallback(ErrorReport& report) {} +inline void SetCallbackMode(TAPE_TEST_MODE kind_test_mode, unsigned short izone = 0) {} /*! * \brief Reset the error counter in a DebugStatus. @@ -811,15 +824,39 @@ static void tagErrorCallback(const int& correctTag, const int& wrongTag, void* u } } -FORCEINLINE void SetTagErrorCallback(ErrorReport& report) { - AD::getTape().setTagErrorCallback(tagErrorCallback, &report); +FORCEINLINE void SetCallbackMode(TAPE_TEST_MODE kind_test_mode, unsigned short izone = 0) { + + if (kind_test_mode == AD::TAPE_TEST_MODE::IGNORE_PREACC) { + current_status->ignore_preacc = true; + } + if (kind_test_mode == AD::TAPE_TEST_MODE::ACTIVATE_PREACC + || kind_test_mode == AD::TAPE_TEST_MODE::ACTIVATE_ALL) { + current_status->ignore_preacc = false; + } + if (kind_test_mode == AD::TAPE_TEST_MODE::IGNORE_SINGLE_ZONE) { + current_status->ignore_single_zone = true; + current_status->ignore_izone = izone; + } + if (kind_test_mode == AD::TAPE_TEST_MODE::ACTIVATE_SINGLE_ZONE + || kind_test_mode == AD::TAPE_TEST_MODE::ACTIVATE_ALL) { + current_status->ignore_single_zone = false; + } + if (kind_test_mode == AD::TAPE_TEST_MODE::IGNORE_ZONES) { + current_status->ignore_zones = true; + } + if (kind_test_mode == AD::TAPE_TEST_MODE::ACTIVATE_ZONES + || kind_test_mode == AD::TAPE_TEST_MODE::ACTIVATE_ALL) { + current_status->ignore_zones = false; + } + + AD::getTape().setTagErrorCallback(tagErrorCallback, current_status); } #else FORCEINLINE void SetCurrentStatus(DebugStatus* status) {} FORCEINLINE void SetTag(int tag) {} FORCEINLINE void ClearTagOnVariable(su2double& v) {} -FORCEINLINE void SetTagErrorCallback(ErrorReport report) {} +FORCEINLINE void SetCallbackMode(TAPE_TEST_MODE kind_test_mode, unsigned short izone = 0) {} #endif // CODI_TAG_TAPE From 0d9a5e973885f270f3b212cbd6824a14dfd68b50 Mon Sep 17 00:00:00 2001 From: Ole Burghardt Date: Thu, 29 Jan 2026 11:36:28 +0100 Subject: [PATCH 06/19] Add CDiscAdjMultizoneDriver::TapeTestGetTag for zone-specific tags. --- SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp index 42d2de2c1c59..6bbcf48a70d3 100644 --- a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp @@ -299,9 +299,9 @@ void CDiscAdjMultizoneDriver::TapeTest() { } } -int CDiscAdjMultizoneDriver::TapeTestGatherErrors(AD::ErrorReport& error_report) const { +int CDiscAdjMultizoneDriver::TapeTestGatherErrors(AD::DebugStatus& debug_status) const { - int num_errors = AD::GetErrorCount(error_report); + int num_errors = AD::GetErrorCount(debug_status); int total_errors = 0; std::vector process_error(size); SU2_MPI::Allreduce(&num_errors, &total_errors, 1, MPI_INT, MPI_SUM, SU2_MPI::GetComm()); @@ -319,6 +319,16 @@ int CDiscAdjMultizoneDriver::TapeTestGatherErrors(AD::ErrorReport& error_report) return total_errors; } +int CDiscAdjMultizoneDriver::TapeTestGetTag(unsigned short iZone, bool init) const { + + if (init) { + return (nZone > 1) ? ((int)iZone + 1) * 10 + 1 : 1; + } + else { + return (nZone > 1) ? ((int)iZone + 1) * 10 + 2 : 2; + } +} + bool CDiscAdjMultizoneDriver::Iterate(unsigned short iZone, unsigned long iInnerIter, bool KrylovMode) { config_container[iZone]->SetInnerIter(iInnerIter); From 557299a5d671da61e9a005e8d5ebce1b689c89ce Mon Sep 17 00:00:00 2001 From: Ole Burghardt Date: Thu, 29 Jan 2026 14:27:37 +0100 Subject: [PATCH 07/19] Main changes in CDiscAdjMultizoneDriver::TapeTest and CDiscAdjMultizoneDriver::SetRecording for zone-specific tags. --- .../src/drivers/CDiscAdjMultizoneDriver.cpp | 85 +++++++++++++++---- 1 file changed, 70 insertions(+), 15 deletions(-) diff --git a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp index 6bbcf48a70d3..746d20cadc23 100644 --- a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp @@ -231,22 +231,41 @@ void CDiscAdjMultizoneDriver::StartSolver() { void CDiscAdjMultizoneDriver::TapeTest() { + if (nZone > 100) { + SU2_MPI::Error("The tape debug mode tag system is limited to a maximum zone number of 100.", CURRENT_FUNCTION); + } + if (rank == MASTER_NODE) { cout <<"\n---------------------------- Start Debug Run ----------------------------" << endl; } int total_errors = 0; - AD::ErrorReport error_report; - AD::SetTagErrorCallback(error_report); - std::ofstream out1("run1_process" + to_string(rank) + ".out"); - std::ofstream out2("run2_process" + to_string(rank) + ".out"); - AD::ResetErrorCounter(error_report); - AD::SetDebugReportFile(error_report, &out1); + /*--- Errors are reported to an instance of AD::DebugStatus that holds an error counter, a pointer to + * an error log file and configurations determined by the TAPE_TEST_MODE settings. ---*/ + AD::DebugStatus debug_status; + + /*--- Set a pointer to the current status internally in the AD structure. ---*/ + AD::SetCurrentStatus(&debug_status); + + /*--- Set the default tag mismatch callback (consider every mismatch an error). ---*/ + AD::SetCallbackMode(AD::TAPE_TEST_MODE::ACTIVATE_ALL); + + // Make this a config option? + // AD::SetCallbackMode(AD::TAPE_TEST_MODE::IGNORE_ZONES); - /*--- This recording will assign the initial (same) tag to each registered variable. + /*--- Reset the error counter and set the error log file (each process writes its own). ---*/ + AD::ResetErrorCounter(debug_status); + std::ofstream out("debug_run_process" + to_string(rank) + ".out"); + AD::SetDebugReportFile(debug_status, &out); + + /*--- This recording will assign an initial, zone-specific tag to each registered variable. * During the recording, each dependent variable will be assigned the same tag. ---*/ + out << "-----------------------------------------------------------------------------------------" << std::endl; + out << "INITIAL recording." << std::endl; + out << "Errors appearing in this recording are most likely preaccumulation errors (preaccumulation tag: 1337).\n" << std::endl; + if(driver_config->GetAD_CheckTapeType() == CHECK_TAPE_TYPE::OBJECTIVE_FUNCTION) { if(driver_config->GetAD_CheckTapeVariables() == CHECK_TAPE_VARIABLES::MESH_COORDINATES) { if (rank == MASTER_NODE) cout << "\nChecking OBJECTIVE_FUNCTION_TAPE for SOLVER_VARIABLES_AND_MESH_COORDINATES." << endl; @@ -267,10 +286,10 @@ void CDiscAdjMultizoneDriver::TapeTest() { SetRecording(RECORDING::TAG_INIT_SOLVER_VARIABLES, Kind_Tape::FULL_SOLVER_TAPE, ZONE_0); } } - total_errors = TapeTestGatherErrors(error_report); - AD::ResetErrorCounter(error_report); - AD::SetDebugReportFile(error_report, &out2); + /*--- Gather errors from all ranks from the initial recording (e.g. preaccumulation errors). ---*/ + total_errors = TapeTestGatherErrors(debug_status); + AD::ResetErrorCounter(debug_status); /*--- This recording repeats the initial recording with a different tag. * If a variable was used before it became dependent on the inputs, this variable will still carry the tag @@ -278,6 +297,13 @@ void CDiscAdjMultizoneDriver::TapeTest() { * In such a case, a possible reason could be that such a variable is set by a post-processing routine while * for a mathematically correct recording this dependency must be included earlier. ---*/ + out << "-------------------------------------------------------------------------------------------------" << std::endl; + out << "IZONE = " << iZone << ", SECOND recording." << std::endl; + out << "Errors appearing hereafter are most likely mathematical errors (e.g. check for circular dependencies)." << std::endl; + + /*--- We ignore preaccumulation mismatches during the second recording as they have already been reported. ---*/ + AD::SetCallbackMode(AD::TAPE_TEST_MODE::IGNORE_PREACC); + if(driver_config->GetAD_CheckTapeType() == CHECK_TAPE_TYPE::OBJECTIVE_FUNCTION) { if(driver_config->GetAD_CheckTapeVariables() == CHECK_TAPE_VARIABLES::MESH_COORDINATES) SetRecording(RECORDING::TAG_CHECK_SOLVER_AND_MESH, Kind_Tape::OBJECTIVE_FUNCTION_TAPE, ZONE_0); @@ -290,7 +316,8 @@ void CDiscAdjMultizoneDriver::TapeTest() { else SetRecording(RECORDING::TAG_CHECK_SOLVER_VARIABLES, Kind_Tape::FULL_SOLVER_TAPE, ZONE_0); } - total_errors += TapeTestGatherErrors(error_report); + total_errors += TapeTestGatherErrors(debug_status); + if (rank == MASTER_NODE) { cout << "\n------------------------- Tape Test Run Summary -------------------------" << endl; @@ -710,16 +737,27 @@ void CDiscAdjMultizoneDriver::SetRecording(RECORDING kind_recording, Kind_Tape t } } + /*--- Boolean only used for debug tape recordings. ---*/ + bool tape_test_init = false; + if (rank == MASTER_NODE) { cout << "\n-------------------------------------------------------------------------\n"; switch(kind_recording) { case RECORDING::CLEAR_INDICES: cout << "Clearing the computational graph." << endl; break; case RECORDING::MESH_COORDS: cout << "Storing computational graph wrt MESH COORDINATES." << endl; break; case RECORDING::SOLUTION_VARIABLES: cout << "Storing computational graph wrt CONSERVATIVE VARIABLES." << endl; break; - case RECORDING::TAG_INIT_SOLVER_VARIABLES: cout << "Simulating recording with tag 1 on conservative variables." << endl; AD::SetTag(1); break; - case RECORDING::TAG_CHECK_SOLVER_VARIABLES: cout << "Checking first recording with tag 2 on conservative variables." << endl; AD::SetTag(2); break; - case RECORDING::TAG_INIT_SOLVER_AND_MESH: cout << "Simulating recording with tag 1 on conservative variables and mesh coordinates." << endl; AD::SetTag(1); break; - case RECORDING::TAG_CHECK_SOLVER_AND_MESH: cout << "Checking first recording with tag 2 on conservative variables and mesh coordinates." << endl; AD::SetTag(2); break; + case RECORDING::TAG_INIT_SOLVER_VARIABLES: + cout << "Simulating recording w.r.t. conservative variables ..." << endl; + tape_test_init = true; break; + case RECORDING::TAG_CHECK_SOLVER_VARIABLES: + cout << "Checking first recording w.r.t. conservative variables ..." << endl; + tape_test_init = false; break; + case RECORDING::TAG_INIT_SOLVER_AND_MESH: + cout << "Simulating recording w.r.t. conservative variables and mesh coordinates ..." << endl; + tape_test_init = true; break; + case RECORDING::TAG_CHECK_SOLVER_AND_MESH: + cout << "Checking first recording w.r.t. conservative variables and mesh coordinates ..." << endl; + tape_test_init = false; break; default: break; } } @@ -744,6 +782,12 @@ void CDiscAdjMultizoneDriver::SetRecording(RECORDING kind_recording, Kind_Tape t type_recording = RECORDING::MESH_DEFORM; } + /*--- If we are in tape debug mode, set a global (but zone-specific) tag. + * Every variable that we register below will be initialized with this tag. ---*/ + int tag = TapeTestGetTag(iZone, tape_test_init); + cout << " - with tag " << tag << " on zone " << iZone << "." << endl; + AD::SetTag(tag); + iteration_container[iZone][INST_0]->RegisterInput(solver_container, geometry_container, config_container, iZone, INST_0, type_recording); } @@ -752,6 +796,10 @@ void CDiscAdjMultizoneDriver::SetRecording(RECORDING kind_recording, Kind_Tape t AD::Push_TapePosition(); /// REGISTERED for (iZone = 0; iZone < nZone; iZone++) { + + /*--- If in tape debug mode, set the zone-specific tag for computations in this zone. ---*/ + AD::SetTag(TapeTestGetTag(iZone, tape_test_init)); + iteration_container[iZone][INST_0]->SetDependencies(solver_container, geometry_container, numerics_container, config_container, iZone, INST_0, kind_recording); } @@ -765,6 +813,10 @@ void CDiscAdjMultizoneDriver::SetRecording(RECORDING kind_recording, Kind_Tape t if ((tape_type == Kind_Tape::OBJECTIVE_FUNCTION_TAPE) || (kind_recording == RECORDING::MESH_COORDS)) { HandleDataTransfer(); for (iZone = 0; iZone < nZone; iZone++) { + + /*--- If in tape debug mode, set the zone-specific test tag for computations in this zone. ---*/ + AD::SetTag(TapeTestGetTag(iZone, tape_test_init)); + if (Has_Deformation(iZone)) { iteration_container[iZone][INST_0]->SetDependencies(solver_container, geometry_container, numerics_container, config_container, iZone, INST_0, kind_recording); @@ -791,6 +843,9 @@ void CDiscAdjMultizoneDriver::SetRecording(RECORDING kind_recording, Kind_Tape t AD::Push_TapePosition(); /// enter_zone + /*--- If in tape debug mode, set the zone-specific test tag for computations in this zone. ---*/ + AD::SetTag(TapeTestGetTag(iZone, tape_test_init)); + DirectIteration(iZone, kind_recording); iteration_container[iZone][INST_0]->RegisterOutput(solver_container, geometry_container, From 5d21f3fff73c2355b018bf8b483a5953bae5033a Mon Sep 17 00:00:00 2001 From: Ole Burghardt Date: Thu, 29 Jan 2026 23:58:41 +0100 Subject: [PATCH 08/19] Small fix. --- Common/include/basic_types/ad_structure.hpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Common/include/basic_types/ad_structure.hpp b/Common/include/basic_types/ad_structure.hpp index 474864bb15bb..0e19c9643138 100644 --- a/Common/include/basic_types/ad_structure.hpp +++ b/Common/include/basic_types/ad_structure.hpp @@ -323,13 +323,6 @@ inline void SetCallbackMode(TAPE_TEST_MODE kind_test_mode, unsigned short izone */ inline void SetDebugReportFile(DebugStatus& status, std::ostream* output_file) {} -/*! - * \brief Set the mode which kind of tag mismatches are considered errors and written to file. - * \param[in] kind_test_mode - specification which kind of tag mismatches are considered. - * \param[in] izone - the zone w.r.t. which a tag mismatch is allowed. - */ -inline void SetCallbackMode(TAPE_TEST_MODE kind_test_mode, unsigned short izone = 0) {} - /*! * \brief Reset the error counter in a DebugStatus. * \param[in] status - the DebugStatus whose error counter is resetted. From e345e55d6952a7d1f5e92c4ad83502ebc47d0cac Mon Sep 17 00:00:00 2001 From: Ole Burghardt Date: Fri, 30 Jan 2026 00:15:50 +0100 Subject: [PATCH 09/19] Clang format. --- Common/include/basic_types/ad_structure.hpp | 35 +++++++++++---------- Common/src/basic_types/ad_structure.cpp | 2 +- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/Common/include/basic_types/ad_structure.hpp b/Common/include/basic_types/ad_structure.hpp index 0e19c9643138..dfe3128ebdba 100644 --- a/Common/include/basic_types/ad_structure.hpp +++ b/Common/include/basic_types/ad_structure.hpp @@ -39,8 +39,15 @@ namespace AD { -enum class TAPE_TEST_MODE { IGNORE_PREACC, ACTIVATE_PREACC, IGNORE_SINGLE_ZONE, - ACTIVATE_SINGLE_ZONE, IGNORE_ZONES, ACTIVATE_ZONES, ACTIVATE_ALL}; +enum class TAPE_TEST_MODE { + IGNORE_PREACC, + ACTIVATE_PREACC, + IGNORE_SINGLE_ZONE, + ACTIVATE_SINGLE_ZONE, + IGNORE_ZONES, + ACTIVATE_ZONES, + ACTIVATE_ALL +}; #ifndef CODI_REVERSE_TYPE @@ -307,7 +314,7 @@ struct DebugStatus {}; * \brief Set a pointer to the current DebugStatus. * \param[in] status - pointer to the current status. */ -inline void SetCurrentStatus(DebugStatus *status) {} +inline void SetCurrentStatus(DebugStatus* status) {} /*! * \brief Set the mode which kind of tag mismatches are considered errors and written to file. @@ -787,7 +794,6 @@ static void tagErrorCallback(const int& correctTag, const int& wrongTag, void* u bool throw_mismatch_error = true; if (status->ignore_preacc || status->ignore_single_zone || status->ignore_zones) { - /*--- The callback could be due to a preaccumulation tag mismatch, if not, we deduce * that it is either due to a zone index mismatch, or due to a mismatch in the least * significant bit that will always result in an error. ---*/ @@ -796,8 +802,7 @@ static void tagErrorCallback(const int& correctTag, const int& wrongTag, void* u if (status->ignore_preacc) { throw_mismatch_error = false; } - } - else if (correctTag % 10 == wrongTag % 10) { + } else if (correctTag % 10 == wrongTag % 10) { if (status->ignore_single_zone) { /*--- A mismatch with a specified zone index might be allowed. ---*/ if (wrongTag / 10 == status->ignore_single_zone) { @@ -817,28 +822,24 @@ static void tagErrorCallback(const int& correctTag, const int& wrongTag, void* u } } -FORCEINLINE void SetCallbackMode(TAPE_TEST_MODE kind_test_mode, unsigned short izone = 0) { - - if (kind_test_mode == AD::TAPE_TEST_MODE::IGNORE_PREACC) { +FORCEINLINE void SetCallbackMode(TAPE_TEST_MODE kind_mode, unsigned short izone = 0) { + if (kind_mode == AD::TAPE_TEST_MODE::IGNORE_PREACC) { current_status->ignore_preacc = true; } - if (kind_test_mode == AD::TAPE_TEST_MODE::ACTIVATE_PREACC - || kind_test_mode == AD::TAPE_TEST_MODE::ACTIVATE_ALL) { + if (kind_mode == AD::TAPE_TEST_MODE::ACTIVATE_PREACC || kind_mode == AD::TAPE_TEST_MODE::ACTIVATE_ALL) { current_status->ignore_preacc = false; } - if (kind_test_mode == AD::TAPE_TEST_MODE::IGNORE_SINGLE_ZONE) { + if (kind_mode == AD::TAPE_TEST_MODE::IGNORE_SINGLE_ZONE) { current_status->ignore_single_zone = true; current_status->ignore_izone = izone; } - if (kind_test_mode == AD::TAPE_TEST_MODE::ACTIVATE_SINGLE_ZONE - || kind_test_mode == AD::TAPE_TEST_MODE::ACTIVATE_ALL) { + if (kind_mode == AD::TAPE_TEST_MODE::ACTIVATE_SINGLE_ZONE || kind_mode == AD::TAPE_TEST_MODE::ACTIVATE_ALL) { current_status->ignore_single_zone = false; } - if (kind_test_mode == AD::TAPE_TEST_MODE::IGNORE_ZONES) { + if (kind_mode == AD::TAPE_TEST_MODE::IGNORE_ZONES) { current_status->ignore_zones = true; } - if (kind_test_mode == AD::TAPE_TEST_MODE::ACTIVATE_ZONES - || kind_test_mode == AD::TAPE_TEST_MODE::ACTIVATE_ALL) { + if (kind_mode == AD::TAPE_TEST_MODE::ACTIVATE_ZONES || kind_mode == AD::TAPE_TEST_MODE::ACTIVATE_ALL) { current_status->ignore_zones = false; } diff --git a/Common/src/basic_types/ad_structure.cpp b/Common/src/basic_types/ad_structure.cpp index 78d13d41e5ec..ccfeef336c63 100644 --- a/Common/src/basic_types/ad_structure.cpp +++ b/Common/src/basic_types/ad_structure.cpp @@ -50,7 +50,7 @@ ExtFuncHelper FuncHelper; #ifdef CODI_TAG_TAPE DebugStatus* current_status = NULL; -#endif // CODI_TAG_TAPE +#endif // CODI_TAG_TAPE #endif From 1162b46ea1d25f67e80eaaf87316b568708e325f Mon Sep 17 00:00:00 2001 From: Ole Burghardt Date: Thu, 5 Feb 2026 00:12:10 +0100 Subject: [PATCH 10/19] Redefine CHECK_TAPE_VARIABLES as SOLUTION_VARIABLES and MESH_COORDS, remove RECORDING::TAG_* options as they can, in fact, be avoided. --- Common/include/option_structure.hpp | 8 ++---- .../src/drivers/CDiscAdjMultizoneDriver.cpp | 28 ++++--------------- .../src/iteration/CDiscAdjFluidIteration.cpp | 4 +-- 3 files changed, 8 insertions(+), 32 deletions(-) diff --git a/Common/include/option_structure.hpp b/Common/include/option_structure.hpp index 690350fae050..41b552814b75 100644 --- a/Common/include/option_structure.hpp +++ b/Common/include/option_structure.hpp @@ -2618,7 +2618,7 @@ enum class CHECK_TAPE_VARIABLES { }; static const MapType CheckTapeVariables_Map = { MakePair("SOLVER_VARIABLES", CHECK_TAPE_VARIABLES::SOLVER_VARIABLES) - MakePair("SOLVER_VARIABLES_AND_MESH_COORDINATES", CHECK_TAPE_VARIABLES::MESH_COORDINATES) + MakePair("MESH_COORDINATES", CHECK_TAPE_VARIABLES::MESH_COORDINATES) }; enum class RECORDING { @@ -2626,11 +2626,7 @@ enum class RECORDING { SOLUTION_VARIABLES, MESH_COORDS, MESH_DEFORM, - SOLUTION_AND_MESH, - TAG_INIT_SOLVER_VARIABLES, - TAG_CHECK_SOLVER_VARIABLES, - TAG_INIT_SOLVER_AND_MESH, - TAG_CHECK_SOLVER_AND_MESH + SOLUTION_AND_MESH }; /*! diff --git a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp index 17d8f34f0f42..043c039b8a42 100644 --- a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp @@ -306,15 +306,15 @@ void CDiscAdjMultizoneDriver::TapeTest() { if(driver_config->GetAD_CheckTapeType() == CHECK_TAPE_TYPE::OBJECTIVE_FUNCTION) { if(driver_config->GetAD_CheckTapeVariables() == CHECK_TAPE_VARIABLES::MESH_COORDINATES) - SetRecording(RECORDING::TAG_CHECK_SOLVER_AND_MESH, Kind_Tape::OBJECTIVE_FUNCTION_TAPE, ZONE_0); + SetRecording(RECORDING::MESH_COORDS, Kind_Tape::OBJECTIVE_FUNCTION_TAPE, ZONE_0); else - SetRecording(RECORDING::TAG_CHECK_SOLVER_VARIABLES, Kind_Tape::OBJECTIVE_FUNCTION_TAPE, ZONE_0); + SetRecording(RECORDING::SOLUTION_VARIABLES, Kind_Tape::OBJECTIVE_FUNCTION_TAPE, ZONE_0); } else { if(driver_config->GetAD_CheckTapeVariables() == CHECK_TAPE_VARIABLES::MESH_COORDINATES) - SetRecording(RECORDING::TAG_CHECK_SOLVER_AND_MESH, Kind_Tape::FULL_SOLVER_TAPE, ZONE_0); + SetRecording(RECORDING::MESH_COORDS, Kind_Tape::FULL_SOLVER_TAPE, ZONE_0); else - SetRecording(RECORDING::TAG_CHECK_SOLVER_VARIABLES, Kind_Tape::FULL_SOLVER_TAPE, ZONE_0); + SetRecording(RECORDING::SOLUTION_VARIABLES, Kind_Tape::FULL_SOLVER_TAPE, ZONE_0); } total_errors += TapeTestGatherErrors(debug_status); @@ -737,27 +737,12 @@ void CDiscAdjMultizoneDriver::SetRecording(RECORDING kind_recording, Kind_Tape t } } - /*--- Boolean only used for debug tape recordings. ---*/ - bool tape_test_init = false; - if (rank == MASTER_NODE) { cout << "\n-------------------------------------------------------------------------\n"; switch(kind_recording) { case RECORDING::CLEAR_INDICES: cout << "Clearing the computational graph." << endl; break; case RECORDING::MESH_COORDS: cout << "Storing computational graph wrt MESH COORDINATES." << endl; break; case RECORDING::SOLUTION_VARIABLES: cout << "Storing computational graph wrt CONSERVATIVE VARIABLES." << endl; break; - case RECORDING::TAG_INIT_SOLVER_VARIABLES: - cout << "Simulating recording w.r.t. conservative variables ..." << endl; - tape_test_init = true; break; - case RECORDING::TAG_CHECK_SOLVER_VARIABLES: - cout << "Checking first recording w.r.t. conservative variables ..." << endl; - tape_test_init = false; break; - case RECORDING::TAG_INIT_SOLVER_AND_MESH: - cout << "Simulating recording w.r.t. conservative variables and mesh coordinates ..." << endl; - tape_test_init = true; break; - case RECORDING::TAG_CHECK_SOLVER_AND_MESH: - cout << "Checking first recording w.r.t. conservative variables and mesh coordinates ..." << endl; - tape_test_init = false; break; default: break; } } @@ -928,10 +913,7 @@ void CDiscAdjMultizoneDriver::SetObjFunction(RECORDING kind_recording) { AD::RegisterOutput(ObjFunc); AD::SetIndex(ObjFunc_Index, ObjFunc); if (kind_recording == RECORDING::SOLUTION_VARIABLES || - kind_recording == RECORDING::TAG_INIT_SOLVER_VARIABLES || - kind_recording == RECORDING::TAG_CHECK_SOLVER_VARIABLES || - kind_recording == RECORDING::TAG_INIT_SOLVER_AND_MESH || - kind_recording == RECORDING::TAG_CHECK_SOLVER_AND_MESH) { + kind_recording == RECORDING::MESH_COORDS) { cout << " Objective function : " << ObjFunc << endl; } } diff --git a/SU2_CFD/src/iteration/CDiscAdjFluidIteration.cpp b/SU2_CFD/src/iteration/CDiscAdjFluidIteration.cpp index a10f7c4505f9..eb8a2bd6734d 100644 --- a/SU2_CFD/src/iteration/CDiscAdjFluidIteration.cpp +++ b/SU2_CFD/src/iteration/CDiscAdjFluidIteration.cpp @@ -436,9 +436,7 @@ void CDiscAdjFluidIteration::RegisterInput(CSolver***** solver, CGeometry**** ge } if (kind_recording == RECORDING::MESH_COORDS || - kind_recording == RECORDING::SOLUTION_AND_MESH || - kind_recording == RECORDING::TAG_INIT_SOLVER_AND_MESH || - kind_recording == RECORDING::TAG_CHECK_SOLVER_AND_MESH) { + kind_recording == RECORDING::SOLUTION_AND_MESH) { /*--- Register node coordinates as input ---*/ geometry0->RegisterCoordinates(); From cabe6e08280982cbbf715dd71c674da69584a184 Mon Sep 17 00:00:00 2001 From: Ole Burghardt Date: Thu, 5 Feb 2026 00:18:19 +0100 Subject: [PATCH 11/19] Register solution variables, too, when CHECK_TAPE_VARIABLES = MESH_COORDS. --- SU2_CFD/src/iteration/CDiscAdjFluidIteration.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/SU2_CFD/src/iteration/CDiscAdjFluidIteration.cpp b/SU2_CFD/src/iteration/CDiscAdjFluidIteration.cpp index eb8a2bd6734d..1067b58a0237 100644 --- a/SU2_CFD/src/iteration/CDiscAdjFluidIteration.cpp +++ b/SU2_CFD/src/iteration/CDiscAdjFluidIteration.cpp @@ -404,12 +404,15 @@ void CDiscAdjFluidIteration::RegisterInput(CSolver***** solver, CGeometry**** ge SU2_OMP_PARALLEL_(if(solvers0[ADJFLOW_SOL]->GetHasHybridParallel())) { + bool AD_debug_mesh_coordinates = false; + if (config[iZone]->GetAD_CheckTapeVariables() == CHECK_TAPE_VARIABLES::MESH_COORDINATES) { + cout << "Register additional SOLUTION VARIABLES for tag debug mode (zone " << iZone << ")." << endl; + AD_debug_mesh_coordinates = true; + } + if (kind_recording == RECORDING::SOLUTION_VARIABLES || - kind_recording == RECORDING::TAG_INIT_SOLVER_VARIABLES || - kind_recording == RECORDING::TAG_CHECK_SOLVER_VARIABLES || - kind_recording == RECORDING::TAG_INIT_SOLVER_AND_MESH || - kind_recording == RECORDING::TAG_CHECK_SOLVER_AND_MESH || - kind_recording == RECORDING::SOLUTION_AND_MESH) { + kind_recording == RECORDING::SOLUTION_AND_MESH || + AD_debug_mesh_coordinates) { /*--- Register flow and turbulent variables as input ---*/ From 25eca836b120c7fb92724830804421c66da92f08 Mon Sep 17 00:00:00 2001 From: Ole Burghardt Date: Thu, 5 Feb 2026 00:24:06 +0100 Subject: [PATCH 12/19] Move CDiscAdjMultizoneDriver::TapeTestGetTag to AD::GetTag. --- Common/include/basic_types/ad_structure.hpp | 19 +++++++++++++++++++ .../drivers/CDiscAdjMultizoneDriver.hpp | 12 ++---------- .../src/drivers/CDiscAdjMultizoneDriver.cpp | 18 ++++-------------- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/Common/include/basic_types/ad_structure.hpp b/Common/include/basic_types/ad_structure.hpp index dfe3128ebdba..f05fed81040c 100644 --- a/Common/include/basic_types/ad_structure.hpp +++ b/Common/include/basic_types/ad_structure.hpp @@ -299,6 +299,13 @@ inline void SetIndex(Identifier& index, const su2double& data) {} */ inline void SetTag(int tag) {} +/*! + * \brief Compute the zone-specific tag. + * \param[in] iZone - Zone index from which the zone-specific tag is formed. + * \return The zone-specific tag. + */ +inline int GetTag(unsigned short iZone) {} + /*! * \brief Sets the tag of a variable to 0. * \param[in] v - the variable whose tag is cleared. @@ -786,6 +793,17 @@ extern DebugStatus* current_status; FORCEINLINE void SetCurrentStatus(DebugStatus* status) { current_status = status; } FORCEINLINE void SetTag(int tag) { AD::getTape().setCurTag(tag); } + +FORCEINLINE int GetTag(unsigned short iZone) { + + if (current_control->init_run) { + return (current_control->multizone_index) ? ((int)iZone + 1) * 10 + 1 : 1; + } + else { + return (current_control->multizone_index) ? ((int)iZone + 1) * 10 + 2 : 2; + } +} + FORCEINLINE void ClearTagOnVariable(su2double& v) { AD::getTape().clearTagOnVariable(v); } static void tagErrorCallback(const int& correctTag, const int& wrongTag, void* userData) { @@ -849,6 +867,7 @@ FORCEINLINE void SetCallbackMode(TAPE_TEST_MODE kind_mode, unsigned short izone #else FORCEINLINE void SetCurrentStatus(DebugStatus* status) {} FORCEINLINE void SetTag(int tag) {} +FORCEINLINE void GetTag(unsigned short iZone) {} FORCEINLINE void ClearTagOnVariable(su2double& v) {} FORCEINLINE void SetCallbackMode(TAPE_TEST_MODE kind_test_mode, unsigned short izone = 0) {} diff --git a/SU2_CFD/include/drivers/CDiscAdjMultizoneDriver.hpp b/SU2_CFD/include/drivers/CDiscAdjMultizoneDriver.hpp index 471601c9a4ed..6e1a012a8901 100644 --- a/SU2_CFD/include/drivers/CDiscAdjMultizoneDriver.hpp +++ b/SU2_CFD/include/drivers/CDiscAdjMultizoneDriver.hpp @@ -300,16 +300,8 @@ class CDiscAdjMultizoneDriver : public CMultizoneDriver { /*! * \brief Get the total error count after a tape test run of the discrete adjoint multizone solver. - * \param[in] debug_status - DebugStatus from which this rank's contribution to the total error count is read. + * \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::DebugStatus& debug_status) const; - - /*! - * \brief Get the zone-specific tag. - * \param[in] iZone - Zone index from which the zone-specific tag is formed. - * \param[in] init - Boolean whether we want the initialization tag or the checking tag. - * \return The zone-specific tag. - */ - int TapeTestGetTag(unsigned short iZone, bool init) const; + int TapeTestGatherErrors(AD::DebugControl& debug_control) const; }; diff --git a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp index 043c039b8a42..d7dbfd74ad44 100644 --- a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp @@ -346,16 +346,6 @@ int CDiscAdjMultizoneDriver::TapeTestGatherErrors(AD::DebugStatus& debug_status) return total_errors; } -int CDiscAdjMultizoneDriver::TapeTestGetTag(unsigned short iZone, bool init) const { - - if (init) { - return (nZone > 1) ? ((int)iZone + 1) * 10 + 1 : 1; - } - else { - return (nZone > 1) ? ((int)iZone + 1) * 10 + 2 : 2; - } -} - bool CDiscAdjMultizoneDriver::Iterate(unsigned short iZone, unsigned long iInnerIter, bool KrylovMode) { config_container[iZone]->SetInnerIter(iInnerIter); @@ -769,7 +759,7 @@ void CDiscAdjMultizoneDriver::SetRecording(RECORDING kind_recording, Kind_Tape t /*--- If we are in tape debug mode, set a global (but zone-specific) tag. * Every variable that we register below will be initialized with this tag. ---*/ - int tag = TapeTestGetTag(iZone, tape_test_init); + int tag = AD::GetTag(iZone); cout << " - with tag " << tag << " on zone " << iZone << "." << endl; AD::SetTag(tag); @@ -783,7 +773,7 @@ void CDiscAdjMultizoneDriver::SetRecording(RECORDING kind_recording, Kind_Tape t for (iZone = 0; iZone < nZone; iZone++) { /*--- If in tape debug mode, set the zone-specific tag for computations in this zone. ---*/ - AD::SetTag(TapeTestGetTag(iZone, tape_test_init)); + AD::SetTag(AD::GetTag(iZone)); iteration_container[iZone][INST_0]->SetDependencies(solver_container, geometry_container, numerics_container, config_container, iZone, INST_0, kind_recording); @@ -800,7 +790,7 @@ void CDiscAdjMultizoneDriver::SetRecording(RECORDING kind_recording, Kind_Tape t for (iZone = 0; iZone < nZone; iZone++) { /*--- If in tape debug mode, set the zone-specific test tag for computations in this zone. ---*/ - AD::SetTag(TapeTestGetTag(iZone, tape_test_init)); + AD::SetTag(AD::GetTag(iZone)); if (Has_Deformation(iZone)) { iteration_container[iZone][INST_0]->SetDependencies(solver_container, geometry_container, numerics_container, @@ -829,7 +819,7 @@ void CDiscAdjMultizoneDriver::SetRecording(RECORDING kind_recording, Kind_Tape t AD::Push_TapePosition(); /// enter_zone /*--- If in tape debug mode, set the zone-specific test tag for computations in this zone. ---*/ - AD::SetTag(TapeTestGetTag(iZone, tape_test_init)); + AD::SetTag(AD::GetTag(iZone)); DirectIteration(iZone, kind_recording); From 5afe777c48b024be016bcfca94b7fb4004944e1c Mon Sep 17 00:00:00 2001 From: Ole Burghardt Date: Thu, 5 Feb 2026 00:32:57 +0100 Subject: [PATCH 13/19] Follow-up removal of RECORDING_TAG* options. --- SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp index d7dbfd74ad44..2504dca72a1e 100644 --- a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp @@ -269,21 +269,21 @@ void CDiscAdjMultizoneDriver::TapeTest() { if(driver_config->GetAD_CheckTapeType() == CHECK_TAPE_TYPE::OBJECTIVE_FUNCTION) { if(driver_config->GetAD_CheckTapeVariables() == CHECK_TAPE_VARIABLES::MESH_COORDINATES) { if (rank == MASTER_NODE) cout << "\nChecking OBJECTIVE_FUNCTION_TAPE for SOLVER_VARIABLES_AND_MESH_COORDINATES." << endl; - SetRecording(RECORDING::TAG_INIT_SOLVER_AND_MESH, Kind_Tape::OBJECTIVE_FUNCTION_TAPE, ZONE_0); + SetRecording(RECORDING::MESH_COORDS, Kind_Tape::OBJECTIVE_FUNCTION_TAPE, ZONE_0); } else { if (rank == MASTER_NODE) cout << "\nChecking OBJECTIVE_FUNCTION_TAPE for SOLVER_VARIABLES." << endl; - SetRecording(RECORDING::TAG_INIT_SOLVER_VARIABLES, Kind_Tape::OBJECTIVE_FUNCTION_TAPE, ZONE_0); + SetRecording(RECORDING::SOLUTION_VARIABLES, Kind_Tape::OBJECTIVE_FUNCTION_TAPE, ZONE_0); } } else { if(driver_config->GetAD_CheckTapeVariables() == CHECK_TAPE_VARIABLES::MESH_COORDINATES) { if (rank == MASTER_NODE) cout << "\nChecking FULL_SOLVER_TAPE for SOLVER_VARIABLES_AND_MESH_COORDINATES." << endl; - SetRecording(RECORDING::TAG_INIT_SOLVER_AND_MESH, Kind_Tape::FULL_SOLVER_TAPE, ZONE_0); + SetRecording(RECORDING::MESH_COORDS, Kind_Tape::FULL_SOLVER_TAPE, ZONE_0); } else { if (rank == MASTER_NODE) cout << "\nChecking FULL_SOLVER_TAPE for SOLVER_VARIABLES." << endl; - SetRecording(RECORDING::TAG_INIT_SOLVER_VARIABLES, Kind_Tape::FULL_SOLVER_TAPE, ZONE_0); + SetRecording(RECORDING::SOLUTION_VARIABLES, Kind_Tape::FULL_SOLVER_TAPE, ZONE_0); } } From 935ddafe01590ed7002ea1ae994c9e1a1620875f Mon Sep 17 00:00:00 2001 From: Ole Burghardt Date: Thu, 5 Feb 2026 13:53:03 +0100 Subject: [PATCH 14/19] Renamings, transform AD::SetCallbackMode to AD::SetTapeDebugOption that only sets the debug mode options. --- Common/include/basic_types/ad_structure.hpp | 91 ++++++++++--------- Common/src/basic_types/ad_structure.cpp | 2 +- .../src/drivers/CDiscAdjMultizoneDriver.cpp | 26 +++--- 3 files changed, 61 insertions(+), 58 deletions(-) diff --git a/Common/include/basic_types/ad_structure.hpp b/Common/include/basic_types/ad_structure.hpp index f05fed81040c..0dc40eccc55d 100644 --- a/Common/include/basic_types/ad_structure.hpp +++ b/Common/include/basic_types/ad_structure.hpp @@ -39,7 +39,7 @@ namespace AD { -enum class TAPE_TEST_MODE { +enum class TAPE_DEBUG_OPTION { IGNORE_PREACC, ACTIVATE_PREACC, IGNORE_SINGLE_ZONE, @@ -315,40 +315,40 @@ inline void ClearTagOnVariable(su2double& v) {} /*! * \brief Struct to store information about errors during a tag debug run. */ -struct DebugStatus {}; +struct DebugControl {}; /*! - * \brief Set a pointer to the current DebugStatus. - * \param[in] status - pointer to the current status. + * \brief Set a pointer to the current DebugControl. + * \param[in] control - pointer to the current debug control. */ -inline void SetCurrentStatus(DebugStatus* status) {} +inline void SetDebugControl(DebugControl* control) {} /*! - * \brief Set the mode which kind of tag mismatches are considered errors and written to file. - * \param[in] kind_test_mode - specification which kind of tag mismatches are considered. + * \brief Set options which kind of tag mismatches are considered errors and written to file. + * \param[in] option - specification which kind of tag mismatches are considered. * \param[in] izone - the zone w.r.t. which a tag mismatch is allowed. */ -inline void SetCallbackMode(TAPE_TEST_MODE kind_test_mode, unsigned short izone = 0) {} +inline void SetTapeDebugOption(TAPE_DEBUG_OPTION option, unsigned short izone = 0) {} /*! - * \brief Set a pointer to the output file of a DebugStatus. - * \param[in] status - the DebugStatus whose output file is set. + * \brief Set a pointer to the output file of a DebugControl. + * \param[in] control - the DebugControl whose output file is set. * \param[in] output_file - pointer to the output file. */ -inline void SetDebugReportFile(DebugStatus& status, std::ostream* output_file) {} +inline void SetDebugReportFile(DebugControl& control, std::ostream* output_file) {} /*! - * \brief Reset the error counter in a DebugStatus. - * \param[in] status - the DebugStatus whose error counter is resetted. + * \brief Reset the error counter in a DebugControl. + * \param[in] control - the DebugControl whose error counter is resetted. */ -inline void ResetErrorCounter(DebugStatus& status) {} +inline void ResetErrorCounter(DebugControl& control) {} /*! - * \brief Get the error count of a DebugStatus. - * \param[in] status - the DebugStatus whose error count is reported. + * \brief Get the error count of a DebugControl. + * \param[in] control - the DebugControl whose error count is reported. * \return Value of the error counter. */ -inline unsigned long GetErrorCount(const DebugStatus& status) { return 0; } +inline unsigned long GetErrorCount(const DebugControl& control) { return 0; } /*! * \brief Pushes back the current tape position to the tape position's vector. @@ -770,7 +770,10 @@ FORCEINLINE void ResumePreaccumulation(bool wasActive) { SU2_OMP_SAFE_GLOBAL_ACCESS(PreaccEnabled = true;) } -struct DebugStatus { +#ifdef CODI_TAG_TAPE + +struct DebugControl { + bool multizone_index = false; bool init_run = false; bool ignore_preacc = false; bool ignore_single_zone = false; @@ -780,17 +783,15 @@ struct DebugStatus { std::ostream* out = &std::cout; }; -FORCEINLINE void ResetErrorCounter(DebugStatus& status) { status.ErrorCounter = 0; } +FORCEINLINE void ResetErrorCounter(DebugControl& control) { control.ErrorCounter = 0; } -FORCEINLINE void SetDebugReportFile(DebugStatus& status, std::ostream* output_file) { status.out = output_file; } +FORCEINLINE void SetDebugReportFile(DebugControl& control, std::ostream* output_file) { control.out = output_file; } -FORCEINLINE unsigned long GetErrorCount(const DebugStatus& status) { return status.ErrorCounter; } +FORCEINLINE unsigned long GetErrorCount(const DebugControl& control) { return control.ErrorCounter; } -#ifdef CODI_TAG_TAPE +extern DebugControl* current_control; -extern DebugStatus* current_status; - -FORCEINLINE void SetCurrentStatus(DebugStatus* status) { current_status = status; } +FORCEINLINE void SetDebugControl(DebugControl* control) { current_control = control; } FORCEINLINE void SetTag(int tag) { AD::getTape().setCurTag(tag); } @@ -807,7 +808,7 @@ FORCEINLINE int GetTag(unsigned short iZone) { FORCEINLINE void ClearTagOnVariable(su2double& v) { AD::getTape().clearTagOnVariable(v); } static void tagErrorCallback(const int& correctTag, const int& wrongTag, void* userData) { - auto* status = static_cast(userData); + auto* status = static_cast(userData); bool throw_mismatch_error = true; @@ -840,36 +841,38 @@ static void tagErrorCallback(const int& correctTag, const int& wrongTag, void* u } } -FORCEINLINE void SetCallbackMode(TAPE_TEST_MODE kind_mode, unsigned short izone = 0) { - if (kind_mode == AD::TAPE_TEST_MODE::IGNORE_PREACC) { - current_status->ignore_preacc = true; +FORCEINLINE void SetTapeDebugOption(TAPE_DEBUG_OPTION option, unsigned short izone = 0) { + if (option == AD::TAPE_DEBUG_OPTION::IGNORE_PREACC) { + current_control->ignore_preacc = true; } - if (kind_mode == AD::TAPE_TEST_MODE::ACTIVATE_PREACC || kind_mode == AD::TAPE_TEST_MODE::ACTIVATE_ALL) { - current_status->ignore_preacc = false; + if (option == AD::TAPE_DEBUG_OPTION::ACTIVATE_PREACC || option == AD::TAPE_DEBUG_OPTION::ACTIVATE_ALL) { + current_control->ignore_preacc = false; } - if (kind_mode == AD::TAPE_TEST_MODE::IGNORE_SINGLE_ZONE) { - current_status->ignore_single_zone = true; - current_status->ignore_izone = izone; + if (option == AD::TAPE_DEBUG_OPTION::IGNORE_SINGLE_ZONE) { + current_control->ignore_single_zone = true; + current_control->ignore_izone = izone; } - if (kind_mode == AD::TAPE_TEST_MODE::ACTIVATE_SINGLE_ZONE || kind_mode == AD::TAPE_TEST_MODE::ACTIVATE_ALL) { - current_status->ignore_single_zone = false; + if (option == AD::TAPE_DEBUG_OPTION::ACTIVATE_SINGLE_ZONE || option == AD::TAPE_DEBUG_OPTION::ACTIVATE_ALL) { + current_control->ignore_single_zone = false; } - if (kind_mode == AD::TAPE_TEST_MODE::IGNORE_ZONES) { - current_status->ignore_zones = true; + if (option == AD::TAPE_DEBUG_OPTION::IGNORE_ZONES) { + current_control->ignore_zones = true; } - if (kind_mode == AD::TAPE_TEST_MODE::ACTIVATE_ZONES || kind_mode == AD::TAPE_TEST_MODE::ACTIVATE_ALL) { - current_status->ignore_zones = false; + if (option == AD::TAPE_DEBUG_OPTION::ACTIVATE_ZONES || option == AD::TAPE_DEBUG_OPTION::ACTIVATE_ALL) { + current_control->ignore_zones = false; } - - AD::getTape().setTagErrorCallback(tagErrorCallback, current_status); } #else -FORCEINLINE void SetCurrentStatus(DebugStatus* status) {} +struct DebugControl {}; +FORCEINLINE void ResetErrorCounter(DebugControl& control) {} +FORCEINLINE void SetDebugReportFile(DebugControl& control, std::ostream* output_file) {} +FORCEINLINE unsigned long GetErrorCount(const DebugControl& control) {} +FORCEINLINE void SetDebugControl(DebugControl* status) {} FORCEINLINE void SetTag(int tag) {} FORCEINLINE void GetTag(unsigned short iZone) {} FORCEINLINE void ClearTagOnVariable(su2double& v) {} -FORCEINLINE void SetCallbackMode(TAPE_TEST_MODE kind_test_mode, unsigned short izone = 0) {} +FORCEINLINE void SetTapeDebugOption(TAPE_DEBUG_OPTION option, unsigned short izone = 0) {} #endif // CODI_TAG_TAPE diff --git a/Common/src/basic_types/ad_structure.cpp b/Common/src/basic_types/ad_structure.cpp index ccfeef336c63..07a36a4b42a2 100644 --- a/Common/src/basic_types/ad_structure.cpp +++ b/Common/src/basic_types/ad_structure.cpp @@ -49,7 +49,7 @@ SU2_OMP(threadprivate(PreaccHelper)) ExtFuncHelper FuncHelper; #ifdef CODI_TAG_TAPE -DebugStatus* current_status = NULL; +DebugControl* current_control = NULL; #endif // CODI_TAG_TAPE #endif diff --git a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp index 2504dca72a1e..5c774752edfd 100644 --- a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp @@ -241,23 +241,23 @@ void CDiscAdjMultizoneDriver::TapeTest() { int total_errors = 0; - /*--- Errors are reported to an instance of AD::DebugStatus that holds an error counter, a pointer to - * an error log file and configurations determined by the TAPE_TEST_MODE settings. ---*/ - AD::DebugStatus debug_status; + /*--- Errors are reported to an instance of AD::DebugControl that holds an error counter, a pointer to + * an error log file and configurations determined by the TAPE_DEBUG_OPTION settings. ---*/ + AD::DebugControl debug_control; /*--- Set a pointer to the current status internally in the AD structure. ---*/ - AD::SetCurrentStatus(&debug_status); + AD::SetDebugControl(&debug_control); /*--- Set the default tag mismatch callback (consider every mismatch an error). ---*/ - AD::SetCallbackMode(AD::TAPE_TEST_MODE::ACTIVATE_ALL); + AD::SetTapeDebugOption(AD::TAPE_DEBUG_OPTION::ACTIVATE_ALL); // Make this a config option? // AD::SetCallbackMode(AD::TAPE_TEST_MODE::IGNORE_ZONES); /*--- Reset the error counter and set the error log file (each process writes its own). ---*/ - AD::ResetErrorCounter(debug_status); + AD::ResetErrorCounter(debug_control); std::ofstream out("debug_run_process" + to_string(rank) + ".out"); - AD::SetDebugReportFile(debug_status, &out); + AD::SetDebugReportFile(debug_control, &out); /*--- This recording will assign an initial, zone-specific tag to each registered variable. * During the recording, each dependent variable will be assigned the same tag. ---*/ @@ -288,8 +288,8 @@ void CDiscAdjMultizoneDriver::TapeTest() { } /*--- Gather errors from all ranks from the initial recording (e.g. preaccumulation errors). ---*/ - total_errors = TapeTestGatherErrors(debug_status); - AD::ResetErrorCounter(debug_status); + total_errors = TapeTestGatherErrors(debug_control); + AD::ResetErrorCounter(debug_control); /*--- This recording repeats the initial recording with a different tag. * If a variable was used before it became dependent on the inputs, this variable will still carry the tag @@ -302,7 +302,7 @@ void CDiscAdjMultizoneDriver::TapeTest() { out << "Errors appearing hereafter are most likely mathematical errors (e.g. check for circular dependencies)." << std::endl; /*--- We ignore preaccumulation mismatches during the second recording as they have already been reported. ---*/ - AD::SetCallbackMode(AD::TAPE_TEST_MODE::IGNORE_PREACC); + AD::SetTapeDebugOption(AD::TAPE_DEBUG_OPTION::IGNORE_PREACC); if(driver_config->GetAD_CheckTapeType() == CHECK_TAPE_TYPE::OBJECTIVE_FUNCTION) { if(driver_config->GetAD_CheckTapeVariables() == CHECK_TAPE_VARIABLES::MESH_COORDINATES) @@ -316,7 +316,7 @@ void CDiscAdjMultizoneDriver::TapeTest() { else SetRecording(RECORDING::SOLUTION_VARIABLES, Kind_Tape::FULL_SOLVER_TAPE, ZONE_0); } - total_errors += TapeTestGatherErrors(debug_status); + total_errors += TapeTestGatherErrors(debug_control); if (rank == MASTER_NODE) { @@ -326,9 +326,9 @@ void CDiscAdjMultizoneDriver::TapeTest() { } } -int CDiscAdjMultizoneDriver::TapeTestGatherErrors(AD::DebugStatus& debug_status) const { +int CDiscAdjMultizoneDriver::TapeTestGatherErrors(AD::DebugControl& debug_control) const { - int num_errors = AD::GetErrorCount(debug_status); + int num_errors = AD::GetErrorCount(debug_control); int total_errors = 0; std::vector process_error(size); SU2_MPI::Allreduce(&num_errors, &total_errors, 1, MPI_INT, MPI_SUM, SU2_MPI::GetComm()); From 12916b04e6770a8cbaa74b99ee592466ba536f38 Mon Sep 17 00:00:00 2001 From: Ole Burghardt Date: Fri, 6 Feb 2026 10:10:02 +0100 Subject: [PATCH 15/19] Add AD::ActivateTagErrorCallback that sets the tag error callback function of the AD tape (debug mode). --- Common/include/basic_types/ad_structure.hpp | 14 ++++++++++++++ SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp | 2 ++ 2 files changed, 16 insertions(+) diff --git a/Common/include/basic_types/ad_structure.hpp b/Common/include/basic_types/ad_structure.hpp index 0dc40eccc55d..45c373ca4d72 100644 --- a/Common/include/basic_types/ad_structure.hpp +++ b/Common/include/basic_types/ad_structure.hpp @@ -330,6 +330,11 @@ inline void SetDebugControl(DebugControl* control) {} */ inline void SetTapeDebugOption(TAPE_DEBUG_OPTION option, unsigned short izone = 0) {} +/*! + * \brief Activate the error callback by letting the tape call tagErrorCallback whenever a tag mismatch arises. + */ +inline void ActivateTagErrorCallback() {} + /*! * \brief Set a pointer to the output file of a DebugControl. * \param[in] control - the DebugControl whose output file is set. @@ -863,6 +868,14 @@ FORCEINLINE void SetTapeDebugOption(TAPE_DEBUG_OPTION option, unsigned short izo } } +FORCEINLINE void ActivateTagErrorCallback() { + if (current_control != NULL) { + AD::getTape().setTagErrorCallback(tagErrorCallback, current_control); + } else { + std::cout << "No tape debug control set!" << std::endl; + } +} + #else struct DebugControl {}; FORCEINLINE void ResetErrorCounter(DebugControl& control) {} @@ -873,6 +886,7 @@ FORCEINLINE void SetTag(int tag) {} FORCEINLINE void GetTag(unsigned short iZone) {} FORCEINLINE void ClearTagOnVariable(su2double& v) {} FORCEINLINE void SetTapeDebugOption(TAPE_DEBUG_OPTION option, unsigned short izone = 0) {} +FORCEINLINE void ActivateTagErrorCallback() {} #endif // CODI_TAG_TAPE diff --git a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp index 5c774752edfd..38eceb6c7e86 100644 --- a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp @@ -248,6 +248,8 @@ void CDiscAdjMultizoneDriver::TapeTest() { /*--- Set a pointer to the current status internally in the AD structure. ---*/ AD::SetDebugControl(&debug_control); + AD::ActivateTagErrorCallback(); + /*--- Set the default tag mismatch callback (consider every mismatch an error). ---*/ AD::SetTapeDebugOption(AD::TAPE_DEBUG_OPTION::ACTIVATE_ALL); From 86f450891c2b78c536de5ba71e4b824d1a77587c Mon Sep 17 00:00:00 2001 From: Ole Burghardt Date: Fri, 6 Feb 2026 10:13:39 +0100 Subject: [PATCH 16/19] Set init and check tags via SetTapeDebugOption (tape debug mode). --- Common/include/basic_types/ad_structure.hpp | 16 ++++++++++++---- SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp | 6 +++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Common/include/basic_types/ad_structure.hpp b/Common/include/basic_types/ad_structure.hpp index 45c373ca4d72..0de7167e006d 100644 --- a/Common/include/basic_types/ad_structure.hpp +++ b/Common/include/basic_types/ad_structure.hpp @@ -46,7 +46,9 @@ enum class TAPE_DEBUG_OPTION { ACTIVATE_SINGLE_ZONE, IGNORE_ZONES, ACTIVATE_ZONES, - ACTIVATE_ALL + ACTIVATE_ALL_ERRORS, + INIT_RUN, + CHECK_RUN }; #ifndef CODI_REVERSE_TYPE @@ -850,22 +852,28 @@ FORCEINLINE void SetTapeDebugOption(TAPE_DEBUG_OPTION option, unsigned short izo if (option == AD::TAPE_DEBUG_OPTION::IGNORE_PREACC) { current_control->ignore_preacc = true; } - if (option == AD::TAPE_DEBUG_OPTION::ACTIVATE_PREACC || option == AD::TAPE_DEBUG_OPTION::ACTIVATE_ALL) { + if (option == AD::TAPE_DEBUG_OPTION::ACTIVATE_PREACC || option == AD::TAPE_DEBUG_OPTION::ACTIVATE_ALL_ERRORS) { current_control->ignore_preacc = false; } if (option == AD::TAPE_DEBUG_OPTION::IGNORE_SINGLE_ZONE) { current_control->ignore_single_zone = true; current_control->ignore_izone = izone; } - if (option == AD::TAPE_DEBUG_OPTION::ACTIVATE_SINGLE_ZONE || option == AD::TAPE_DEBUG_OPTION::ACTIVATE_ALL) { + if (option == AD::TAPE_DEBUG_OPTION::ACTIVATE_SINGLE_ZONE || option == AD::TAPE_DEBUG_OPTION::ACTIVATE_ALL_ERRORS) { current_control->ignore_single_zone = false; } if (option == AD::TAPE_DEBUG_OPTION::IGNORE_ZONES) { current_control->ignore_zones = true; } - if (option == AD::TAPE_DEBUG_OPTION::ACTIVATE_ZONES || option == AD::TAPE_DEBUG_OPTION::ACTIVATE_ALL) { + if (option == AD::TAPE_DEBUG_OPTION::ACTIVATE_ZONES || option == AD::TAPE_DEBUG_OPTION::ACTIVATE_ALL_ERRORS) { current_control->ignore_zones = false; } + if (option == AD::TAPE_DEBUG_OPTION::INIT_RUN) { + current_control->init_run = true; + } + if (option == AD::TAPE_DEBUG_OPTION::CHECK_RUN) { + current_control->init_run = false; + } } FORCEINLINE void ActivateTagErrorCallback() { diff --git a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp index 38eceb6c7e86..2668c1edd60d 100644 --- a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp @@ -251,7 +251,7 @@ void CDiscAdjMultizoneDriver::TapeTest() { AD::ActivateTagErrorCallback(); /*--- Set the default tag mismatch callback (consider every mismatch an error). ---*/ - AD::SetTapeDebugOption(AD::TAPE_DEBUG_OPTION::ACTIVATE_ALL); + AD::SetTapeDebugOption(AD::TAPE_DEBUG_OPTION::ACTIVATE_ALL_ERRORS); // Make this a config option? // AD::SetCallbackMode(AD::TAPE_TEST_MODE::IGNORE_ZONES); @@ -268,6 +268,8 @@ void CDiscAdjMultizoneDriver::TapeTest() { out << "INITIAL recording." << std::endl; out << "Errors appearing in this recording are most likely preaccumulation errors (preaccumulation tag: 1337).\n" << std::endl; + AD::SetTapeDebugOption(AD::TAPE_DEBUG_OPTION::INIT_RUN); + if(driver_config->GetAD_CheckTapeType() == CHECK_TAPE_TYPE::OBJECTIVE_FUNCTION) { if(driver_config->GetAD_CheckTapeVariables() == CHECK_TAPE_VARIABLES::MESH_COORDINATES) { if (rank == MASTER_NODE) cout << "\nChecking OBJECTIVE_FUNCTION_TAPE for SOLVER_VARIABLES_AND_MESH_COORDINATES." << endl; @@ -303,6 +305,8 @@ void CDiscAdjMultizoneDriver::TapeTest() { out << "IZONE = " << iZone << ", SECOND recording." << std::endl; out << "Errors appearing hereafter are most likely mathematical errors (e.g. check for circular dependencies)." << std::endl; + AD::SetTapeDebugOption(AD::TAPE_DEBUG_OPTION::CHECK_RUN); + /*--- We ignore preaccumulation mismatches during the second recording as they have already been reported. ---*/ AD::SetTapeDebugOption(AD::TAPE_DEBUG_OPTION::IGNORE_PREACC); From 4e4d6716fcea2bb5557618d0464c3635a8dc0e5e Mon Sep 17 00:00:00 2001 From: Ole Burghardt Date: Fri, 6 Feb 2026 10:17:00 +0100 Subject: [PATCH 17/19] Set multizone tags via SetTapeDebugOption (tape debug mode). --- Common/include/basic_types/ad_structure.hpp | 12 ++++++------ SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Common/include/basic_types/ad_structure.hpp b/Common/include/basic_types/ad_structure.hpp index 0de7167e006d..e30478d77745 100644 --- a/Common/include/basic_types/ad_structure.hpp +++ b/Common/include/basic_types/ad_structure.hpp @@ -780,7 +780,7 @@ FORCEINLINE void ResumePreaccumulation(bool wasActive) { #ifdef CODI_TAG_TAPE struct DebugControl { - bool multizone_index = false; + bool multizone_tags = false; bool init_run = false; bool ignore_preacc = false; bool ignore_single_zone = false; @@ -803,12 +803,10 @@ FORCEINLINE void SetDebugControl(DebugControl* control) { current_control = cont FORCEINLINE void SetTag(int tag) { AD::getTape().setCurTag(tag); } FORCEINLINE int GetTag(unsigned short iZone) { - if (current_control->init_run) { - return (current_control->multizone_index) ? ((int)iZone + 1) * 10 + 1 : 1; - } - else { - return (current_control->multizone_index) ? ((int)iZone + 1) * 10 + 2 : 2; + return (current_control->multizone_tags) ? ((int)iZone + 1) * 10 + 1 : 1; + } else { + return (current_control->multizone_tags) ? ((int)iZone + 1) * 10 + 2 : 2; } } @@ -874,6 +872,8 @@ FORCEINLINE void SetTapeDebugOption(TAPE_DEBUG_OPTION option, unsigned short izo if (option == AD::TAPE_DEBUG_OPTION::CHECK_RUN) { current_control->init_run = false; } + if (option == AD::TAPE_DEBUG_OPTION::MULTIZONE_TAGS) { + current_control->multizone_tags = true; } FORCEINLINE void ActivateTagErrorCallback() { diff --git a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp index 2668c1edd60d..d40e3ea7a01d 100644 --- a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp @@ -250,6 +250,9 @@ void CDiscAdjMultizoneDriver::TapeTest() { AD::ActivateTagErrorCallback(); + /*--- For multizone cases (nZone > 1), we use zone-specific tags. ---*/ + if(nZone > 1) { AD::SetTapeDebugOption(AD::TAPE_DEBUG_OPTION::MULTIZONE_TAGS); } + /*--- Set the default tag mismatch callback (consider every mismatch an error). ---*/ AD::SetTapeDebugOption(AD::TAPE_DEBUG_OPTION::ACTIVATE_ALL_ERRORS); From ad14b50abf259a5a1ec0a503e8cc77673ccaebee Mon Sep 17 00:00:00 2001 From: Ole Burghardt Date: Fri, 6 Feb 2026 10:20:22 +0100 Subject: [PATCH 18/19] Fixes (tape debug mode). --- Common/include/basic_types/ad_structure.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Common/include/basic_types/ad_structure.hpp b/Common/include/basic_types/ad_structure.hpp index e30478d77745..a4603788491a 100644 --- a/Common/include/basic_types/ad_structure.hpp +++ b/Common/include/basic_types/ad_structure.hpp @@ -306,7 +306,7 @@ inline void SetTag(int tag) {} * \param[in] iZone - Zone index from which the zone-specific tag is formed. * \return The zone-specific tag. */ -inline int GetTag(unsigned short iZone) {} +inline int GetTag(unsigned short iZone) { return 0; } /*! * \brief Sets the tag of a variable to 0. @@ -874,6 +874,7 @@ FORCEINLINE void SetTapeDebugOption(TAPE_DEBUG_OPTION option, unsigned short izo } if (option == AD::TAPE_DEBUG_OPTION::MULTIZONE_TAGS) { current_control->multizone_tags = true; + } } FORCEINLINE void ActivateTagErrorCallback() { @@ -888,10 +889,10 @@ FORCEINLINE void ActivateTagErrorCallback() { struct DebugControl {}; FORCEINLINE void ResetErrorCounter(DebugControl& control) {} FORCEINLINE void SetDebugReportFile(DebugControl& control, std::ostream* output_file) {} -FORCEINLINE unsigned long GetErrorCount(const DebugControl& control) {} +FORCEINLINE unsigned long GetErrorCount(const DebugControl& control) { return 0; } FORCEINLINE void SetDebugControl(DebugControl* status) {} FORCEINLINE void SetTag(int tag) {} -FORCEINLINE void GetTag(unsigned short iZone) {} +FORCEINLINE int GetTag(unsigned short iZone) { return 0; } FORCEINLINE void ClearTagOnVariable(su2double& v) {} FORCEINLINE void SetTapeDebugOption(TAPE_DEBUG_OPTION option, unsigned short izone = 0) {} FORCEINLINE void ActivateTagErrorCallback() {} From 61c531377305ba419493c446494a078a3d75197f Mon Sep 17 00:00:00 2001 From: Ole Burghardt Date: Fri, 6 Feb 2026 10:38:00 +0100 Subject: [PATCH 19/19] Fix (tape debug mode). --- Common/include/basic_types/ad_structure.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Common/include/basic_types/ad_structure.hpp b/Common/include/basic_types/ad_structure.hpp index a4603788491a..79d1636b7f5f 100644 --- a/Common/include/basic_types/ad_structure.hpp +++ b/Common/include/basic_types/ad_structure.hpp @@ -47,6 +47,7 @@ enum class TAPE_DEBUG_OPTION { IGNORE_ZONES, ACTIVATE_ZONES, ACTIVATE_ALL_ERRORS, + MULTIZONE_TAGS, INIT_RUN, CHECK_RUN };