Skip to content

Fixed CL: write the finite difference dCX/dCL to flow.meta regardless of the screen output frequency - #2952

Open
nikita-ageev wants to merge 4 commits into
su2code:developfrom
nikita-ageev:fix/fixedcl-fd-metadata
Open

nikita-ageev wants to merge 4 commits into
su2code:developfrom
nikita-ageev:fix/fixedcl-fd-metadata

Conversation

@nikita-ageev

Copy link
Copy Markdown

Proposed Changes

Fixes #2937.

In fixed CL mode CFlowOutput::SetFixedCLScreenOutput stores the iteration at which the finite difference step starts and, when the step ends, prints the "Fixed CL Mode (Finite Difference)" summary and writes flow.meta with DCD_DCL_VALUE and DCMX/DCMY/DCMZ_DCL_VALUE. It is called from SetAdditionalScreenOutput, i.e. only on screen output iterations. When the finite difference step ends on an iteration that is not a multiple of SCREEN_WRT_FREQ_INNER (typically when it stops at ITER_DCL_DALPHA), the summary and the final WriteMetaData are skipped. flow.meta then keeps the values written at the start of the step, and a discrete adjoint run reads stale dCX/dCL.

This PR overrides WriteScreenOutput in CFlowOutput: in fixed CL mode with Finite_Difference_Mode set, the screen output is written on the iteration where the step starts (CL_DRIVER_COMMAND != 0) and on the iteration where it ends (AOA == PREV_AOA, the same condition SetFixedCLScreenOutput already uses). All other iterations follow the screen frequency as before. The override applies to CFlowCompOutput and CNEMOCompOutput, both of which call SetFixedCLScreenOutput.

Test: TestCases/fixed_cl/naca0012/inv_NACA0012.cfg with the QuickStart mesh, RESTART_SOL= NO, serial, develop at a6b7496. flow.meta written at the end:

SCREEN_WRT_FREQ_INNER develop: DCD_DCL_VALUE / DCMZ_DCL_VALUE this PR
1 0.0713516 / 0.128264 0.0713516 / 0.128264
7 0.0581557 / 0.160879 0.0713516 / 0.128264
10 0.0581557 / 0.160879 0.0713516 / 0.128264
1000 0.0581557 / 0.160879 0.0713516 / 0.128264

ITER and AOA in flow.meta are the same in all runs. With SCREEN_WRT_FREQ_INNER= 1 the log, history.csv and flow.meta are identical to develop; with 10 the history.csv and the restart file are identical to develop, the only difference is the finite difference summary on screen and the corrected flow.meta. fixedcl_naca0012 and contadj_fixedcl_naca0012 from serial_regression.py pass with the stored values.

No new regression test: the regression framework compares history values at test_iter, and the fix only changes flow.meta and screen output. I can add a check if there is a preferred way to test meta data files.

Related Work

#2937 (issue). No other open PR touches the fixed CL output.

PR Checklist

  • I am submitting my contribution to the develop branch.
  • My contribution generates no new compiler warnings (try with --warnlevel=3 when using meson).
  • My contribution is commented and consistent with SU2 style (https://su2code.github.io/docs_v7/Style-Guide/).
  • I used the pre-commit hook to prevent dirty commits and used pre-commit run --all to format old commits.
  • I have added a test case that demonstrates my contribution, if necessary.
  • I have updated appropriate documentation (Tutorials, Docs Page, config_template.cpp), if necessary.

…creen output frequency

SetFixedCLScreenOutput stores the iteration at which the finite difference
step starts and, at its end, writes flow.meta with dCD/dCL and dCMx/y/z/dCL.
It is called only on screen output iterations, so when the finite difference
step ended on an iteration that is not a multiple of SCREEN_WRT_FREQ_INNER the
meta data file kept the values from the start of the step and the adjoint read
stale derivatives. Always write the screen output at the start and the end of
the finite difference step in fixed CL mode.

Fixes su2code#2937
Comment thread SU2_CFD/src/output/CFlowOutput.cpp Outdated

if (config->GetFixed_CL_Mode() && config->GetFinite_Difference_Mode() &&
!(config->GetMultizone_Problem() && !config->GetWrt_ZoneConv())) {
const bool startFD = fabs(historyOutput_Map["CL_DRIVER_COMMAND"].value) > 1e-16;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use EPS,

Suggested change
const bool startFD = fabs(historyOutput_Map["CL_DRIVER_COMMAND"].value) > 1e-16;
const bool startFD = fabs(historyOutput_Map["CL_DRIVER_COMMAND"].value) > EPS;

@joshkellyjak joshkellyjak left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch, a test that catches this bug would be useful

Comment thread SU2_CFD/src/output/CFlowOutput.cpp Outdated
if (startFD || endFD) return true;
}

return COutput::WriteScreenOutput(config);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I correct in thinking writing the meta data file now depends on whether the screen line is printed? I'm not sure this is best way to fix this. I think the WriteMetaData call should come outside of SetFixedCLScreenOutput into code that runs every iteration e.g. SetHistoryOutput.

Comment thread SU2_CFD/src/output/CFlowOutput.cpp Outdated
if (config->GetFixed_CL_Mode() && config->GetFinite_Difference_Mode() &&
!(config->GetMultizone_Problem() && !config->GetWrt_ZoneConv())) {
const bool startFD = fabs(historyOutput_Map["CL_DRIVER_COMMAND"].value) > 1e-16;
const bool endFD = historyOutput_Map["AOA"].value == historyOutput_Map["PREV_AOA"].value;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these start and end conditions are copied from SetFixedCLScreenOutput, put them in helper functions so they can be accessed in multiple places and stay identical

Comment thread SU2_CFD/src/output/CFlowOutput.cpp Outdated
if (config->GetFixed_CL_Mode() && config->GetFinite_Difference_Mode() &&
!(config->GetMultizone_Problem() && !config->GetWrt_ZoneConv())) {
const bool startFD = fabs(historyOutput_Map["CL_DRIVER_COMMAND"].value) > 1e-16;
const bool endFD = historyOutput_Map["AOA"].value == historyOutput_Map["PREV_AOA"].value;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should use GetHistoryFieldValue(name) rather than historyOutput_Map["AOA"]

const bool startFD = fabs(GetHistoryFieldValue("CL_DRIVER_COMMAND")) > EPS; const bool endFD = GetHistoryFieldValue("AOA") == GetHistoryFieldValue("PREV_AOA");

@joshkellyjak joshkellyjak self-assigned this Oct 9, 2026
Address review comments:
- move the finite difference bookkeeping (start iteration and WriteMetaData at
  the end of the step) out of SetFixedCLScreenOutput into
  SetFixedCLFiniteDifference, called from LoadHistoryData every iteration;
- drop the WriteScreenOutput override, screen output frequency is unchanged;
- share the start/end conditions via FixedCLStartFD/FixedCLEndFD helpers,
  using GetHistoryFieldValue and EPS.
@nikita-ageev

Copy link
Copy Markdown
Author

Updated in ea814ec:

  • WriteMetaData placement: the WriteScreenOutput override is removed, so the screen output frequency is unchanged. The finite difference bookkeeping (storing the start iteration and writing the meta data at the end of the step) moved from SetFixedCLScreenOutput to a new SetFixedCLFiniteDifference, called every iteration from LoadHistoryData (inside SetHistoryOutput) in CFlowCompOutput and CNEMOCompOutput, right after SetAerodynamicCoefficients sets AOA. SetFixedCLScreenOutput now only prints.
  • Shared start/end conditions: added FixedCLStartFD() / FixedCLEndFD() helpers in CFlowOutput, used by both functions.
  • GetHistoryFieldValue and EPS: the helpers use GetHistoryFieldValue(...) and EPS, as suggested.

On the test: would a regression case be OK as a small fixed-CL finite-difference case with a SCREEN_WRT_FREQ_INNER that skips the end of the finite difference step, checking DCD_DCL_VALUE in flow.meta against the run with frequency 1? Or do you have an existing case in mind that I should extend?

Thanks for the review!

* \return <TRUE> if the AoA is equal to the previous AoA.
*/
bool FixedCLEndFD() const {
return GetHistoryFieldValue("AOA") == GetHistoryFieldValue("PREV_AOA");

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants