[WIP] Multizone adjoints for turbomachinery#2446
[WIP] Multizone adjoints for turbomachinery#2446joshkellyjak wants to merge 88 commits intodevelopfrom
Conversation
| AD::EndPreacc(); | ||
|
|
||
| /*--- Max is not differentiable, so we not register them for preacc. ---*/ |
There was a problem hiding this comment.
What is the difference between ending the preaccumulation before or after?
| } | ||
| } | ||
| } else if (Multizone_Problem && DiscreteAdjoint) { | ||
| SU2_MPI::Error(string("OUTPUT_WRT_FREQ cannot be specified for this solver " |
There was a problem hiding this comment.
| SU2_MPI::Error(string("OUTPUT_WRT_FREQ cannot be specified for this solver " | |
| SU2_MPI::Error("OUTPUT_WRT_FREQ cannot be specified for this solver " |
| "(writing of restart and sensitivity files not possible for multizone discrete adjoint during runtime yet).\n" | ||
| "Please remove this option from the config file, output files will be written when solver finalizes.\n"), CURRENT_FUNCTION); |
There was a problem hiding this comment.
Hmmm I'm pretty sure it is possible
There was a problem hiding this comment.
Yes and no, writing the files is fine, but the continuation of the multi-zone discrete adjoint solver is erratic. My guess is that some indices aren't cleared properly before re-recording the tape. (Writing adjoint solution variables to file only, without re-recording at all and without sensitivities, might give us some hints.)
The debug mode could eventually pin down where exactly things go wrong.
| BPressure = config->GetPressureOut_BC(); | ||
| Temperature = config->GetTotalTemperatureIn_BC(); | ||
|
|
||
| if (!reset){ | ||
| AD::RegisterInput(BPressure); | ||
| AD::RegisterInput(Temperature); | ||
| } | ||
|
|
||
| BPressure = config->GetPressureOut_BC(); | ||
| Temperature = config->GetTotalTemperatureIn_BC(); | ||
|
|
There was a problem hiding this comment.
Why are these wrong but not the others that follow the same pattern?
There was a problem hiding this comment.
This threw a tagging error, and if I remember correctly it's because in the other sections the variables it accesses are directly used in the solver, whereas in the Giles implementation they are not, creating a mismatch in tags.
There was a problem hiding this comment.
Can we fix it in a way that keeps a clear pattern for doing this type of thing?
There was a problem hiding this comment.
I can give it a go
There was a problem hiding this comment.
I think this actually removes a potential tag tool error message (= dependency error message in this case), but it breaks the functionality, since e.g. BPressure = config->GetPressureOut_BC(); deletes the index of BPressure, as the config value appears as a constant.
I'd suggest to fix this, for now, by tracking the config class value instead of the local copy (?)
…ding of objective function calculation
… to run in quasi-MZ approach. (NEEDS CLEANING)
… MZ turbo testcase
…m/su2code/SU2 into feature_mz_turbomachinery_adjoint
oleburghardt
left a comment
There was a problem hiding this comment.
@pcarruscag @joshkellyjak I'd suggest to solve problems in RegisterVariables in a different branch.
(The problem with the fix that I suggest is that, I think, some config class values are copied into the solver during initialization steps of the solver which might not be part of the recording. So it's also not a good solution, I'm afraid.)
| BPressure = config->GetPressureOut_BC(); | ||
| Temperature = config->GetTotalTemperatureIn_BC(); | ||
|
|
||
| if (!reset){ | ||
| AD::RegisterInput(BPressure); | ||
| AD::RegisterInput(Temperature); | ||
| } | ||
|
|
||
| BPressure = config->GetPressureOut_BC(); | ||
| Temperature = config->GetTotalTemperatureIn_BC(); | ||
|
|
There was a problem hiding this comment.
I think this actually removes a potential tag tool error message (= dependency error message in this case), but it breaks the functionality, since e.g. BPressure = config->GetPressureOut_BC(); deletes the index of BPressure, as the config value appears as a constant.
I'd suggest to fix this, for now, by tracking the config class value instead of the local copy (?)
Sure thing, this sounds reasonable from my perspective as it extends beyond the turbo world. For now it is maybe best to disable the tape tests in the regression workflow in that case? |
|
I reran the APU turbocharger test case as the residuals looked a little strange on the regression workflow, given I have validated this compared to experimental data I would argue that this updating the values here and adding new solution data to the testcase repo is justified. |
| for (auto iSize = 0; iSize < size; iSize++){ | ||
| if (buffDonorMarker[static_cast<size_t>(iSize) * static_cast<unsigned long>(nSpanDonor + 1)] != -1) { | ||
| for (auto iSpan = 0; iSpan < nSpanDonor + 1; iSpan++){ | ||
| for (size_t iVar = 0u; iVar < nMixingVars; iVar++) sendDonorVar[iSpan * nMixingVars + iVar] = buffDonorVar[static_cast<size_t>(iSize) * nSpanDonorVars + iSpan * nMixingVars + iVar]; |
Check failure
Code scanning / CodeQL
Multiplication result converted to larger type High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 days ago
To fix this class of problem, ensure that at least one operand of the multiplication is explicitly cast to the larger integer type before the multiplication. This forces the multiplication to be evaluated in the wider type, preventing overflow that would occur if it were done in a narrower type first and only then converted.
In this specific case, the problematic expression is in the indexing term on line 110:
sendDonorVar[iSpan * nMixingVars + iVar] = buffDonorVar[static_cast<size_t>(iSize) * nSpanDonorVars + iSpan * nMixingVars + iVar];Here, iSpan is an int and nMixingVars is (effectively) an unsigned short; their product is computed in int and only then converted to size_t as part of the whole index expression. To fix this without changing functionality, we should cast iSpan (or nMixingVars) to size_t before the multiplication so the product is computed in size_t. For consistency with the rest of the file, which uses static_cast<size_t>(...) for similar counts, we should use static_cast<size_t>(iSpan) * nMixingVars in both index expressions in that line.
No new imports or helper methods are needed; we only adjust the indexing expression in CMixingPlaneInterface::BroadcastData_MixingPlane inside CMixingPlaneInterface.cpp.
| @@ -107,7 +107,7 @@ | ||
| for (auto iSize = 0; iSize < size; iSize++){ | ||
| if (buffDonorMarker[static_cast<size_t>(iSize) * static_cast<unsigned long>(nSpanDonor + 1)] != -1) { | ||
| for (auto iSpan = 0; iSpan < nSpanDonor + 1; iSpan++){ | ||
| for (size_t iVar = 0u; iVar < nMixingVars; iVar++) sendDonorVar[iSpan * nMixingVars + iVar] = buffDonorVar[static_cast<size_t>(iSize) * nSpanDonorVars + iSpan * nMixingVars + iVar]; | ||
| for (size_t iVar = 0u; iVar < nMixingVars; iVar++) sendDonorVar[static_cast<size_t>(iSpan) * nMixingVars + iVar] = buffDonorVar[static_cast<size_t>(iSize) * nSpanDonorVars + static_cast<size_t>(iSpan) * nMixingVars + iVar]; | ||
| } | ||
| markDonor = buffDonorMarker[static_cast<unsigned long>(iSize) * static_cast<unsigned long>(nSpanDonor + 1)]; | ||
| break; // Avoid overwriting |
| for (auto iSize = 0; iSize < size; iSize++){ | ||
| if (buffDonorMarker[static_cast<size_t>(iSize) * static_cast<unsigned long>(nSpanDonor + 1)] != -1) { | ||
| for (auto iSpan = 0; iSpan < nSpanDonor + 1; iSpan++){ | ||
| for (size_t iVar = 0u; iVar < nMixingVars; iVar++) sendDonorVar[iSpan * nMixingVars + iVar] = buffDonorVar[static_cast<size_t>(iSize) * nSpanDonorVars + iSpan * nMixingVars + iVar]; |
Check failure
Code scanning / CodeQL
Multiplication result converted to larger type High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 days ago
In general, to avoid this kind of overflow, ensure that at least one operand of the multiplication is explicitly converted to the larger integer type before the multiplication, so that the operation is performed in that wider type.
Here, the problematic term is iSpan * nMixingVars in the index expression:
sendDonorVar[iSpan * nMixingVars + iVar] =
buffDonorVar[static_cast<size_t>(iSize) * nSpanDonorVars + iSpan * nMixingVars + iVar];The best minimal fix is to cast one of the operands in the product to size_t so that the multiplication is performed in size_t, matching the other indices. We should apply this both in the left‑hand index and the right‑hand index, to keep the expressions consistent and avoid any risk of overflow. No new headers or functions are needed; we only add static_cast<size_t> around iSpan (or nMixingVars) in those products.
Concretely, in SU2_CFD/src/interfaces/cfd/CMixingPlaneInterface.cpp, in the inner loop starting at line 109, update the index expressions on line 110 to:
sendDonorVar[static_cast<size_t>(iSpan) * nMixingVars + iVar]buffDonorVar[static_cast<size_t>(iSize) * nSpanDonorVars + static_cast<size_t>(iSpan) * nMixingVars + iVar]
This keeps behaviour the same for valid indices while ensuring the multiplication is computed in a wide type.
| @@ -107,7 +107,7 @@ | ||
| for (auto iSize = 0; iSize < size; iSize++){ | ||
| if (buffDonorMarker[static_cast<size_t>(iSize) * static_cast<unsigned long>(nSpanDonor + 1)] != -1) { | ||
| for (auto iSpan = 0; iSpan < nSpanDonor + 1; iSpan++){ | ||
| for (size_t iVar = 0u; iVar < nMixingVars; iVar++) sendDonorVar[iSpan * nMixingVars + iVar] = buffDonorVar[static_cast<size_t>(iSize) * nSpanDonorVars + iSpan * nMixingVars + iVar]; | ||
| for (size_t iVar = 0u; iVar < nMixingVars; iVar++) sendDonorVar[static_cast<size_t>(iSpan) * nMixingVars + iVar] = buffDonorVar[static_cast<size_t>(iSize) * nSpanDonorVars + static_cast<size_t>(iSpan) * nMixingVars + iVar]; | ||
| } | ||
| markDonor = buffDonorMarker[static_cast<unsigned long>(iSize) * static_cast<unsigned long>(nSpanDonor + 1)]; | ||
| break; // Avoid overwriting |
…m/su2code/SU2 into feature_mz_turbomachinery_adjoint
Proposed Changes
This is a cleaned up PR of the fixes needed for multizone adjoints for turbomachinery from the previous PR of @oleburghardt and I's work.
This hopefully is useable, so if you would like to test and report please feel free to contact me on Slack.
TODO:
Related Work
Now closed PR #2317
PR Checklist
Put an X by all that apply. You can fill this out after submitting the PR. If you have any questions, don't hesitate to ask! We want to help. These are a guide for you to know what the reviewers will be looking for in your contribution.
pre-commit run --allto format old commits.