{"id": "discipline_contract", "title": "Discipline contract for MDO integration", "description": "The interface a multidisciplinary framework integrates against is checked on a small inviscid aerofoil case (NACA 0012, M = 0.5, \u03b1 = 2\u00b0, 64 elements of degree 2). (i) The partial-derivative products of residual and outputs (apply_linear) in forward and reverse mode must be transposes of each other, with respect to the state and to all inputs including the surface displacement field, both at the discipline's solution and at a point named by the caller that is not a solution. (ii) The forward products must agree with central finite differences of the residual (apply_nonlinear) and of the outputs, taken along smooth directions (the numerical flux is only piecewise smooth, so a rough direction would test the finite difference and not the derivative). (iii) solve_linear must invert apply_linear in both modes, and the two modes must be transposes of each other. (iv) The reduced (total) products tangent_product and adjoint_product must be transposes of each other. (v) A linear solve that cannot reach its tolerance must raise, or be flagged when the caller asks for that; and adjoint and direct totals, which solve different linear systems of the same linearisation, must approach each other as the tolerance of those solves is tightened. (vi) Wrapped as an OpenMDAO implicit component, the discipline must pass OpenMDAO's own check of partial derivatives, reproduce the discipline's total derivatives, and, coupled to a linear structure in a block Gauss\u2013Seidel cycle, give a coupled total derivative that agrees with a finite difference of re-converged coupled analyses.", "passed": true, "checks": [{"name": "flow solve converged", "value": true, "expected": "true", "passed": true}, {"name": "apply_linear forward vs reverse: largest relative dot-product defect over both points", "value": 2.509108526807702e-16, "expected": "< 1e-11 (round-off)", "passed": true}, {"name": "solve_linear forward vs reverse: largest relative dot-product defect", "value": 4.050990703152813e-12, "expected": "< 1e-8 (two Krylov solves to 1e-11)", "passed": true}, {"name": "solve_linear inverts apply_linear in both modes: largest relative residual, recomputed with apply_linear", "value": 9.550459834064449e-12, "expected": "< 1e-9 (solves to 1e-11; preconditioned residual)", "passed": true}, {"name": "partials (residual, cl, cd, cm, f_surface) with respect to state and inputs vs central differences: largest relative difference", "value": 1.1537619025937098e-08, "expected": "< 1e-6 (the bound of the linearization study for JVP vs central differences; smooth directions)", "passed": true}, {"name": "total products, tangent_product vs adjoint_product: relative dot-product defect", "value": 6.637352423181062e-10, "expected": "< 1e-7 (two linear solves to 1e-10)", "passed": true}, {"name": "a linear solve that misses its tolerance raises LinearSolveError and reports the reduction it achieved", "value": 1.6483632593727308e-14, "expected": "raised, with 0 < reduction < 1e-10", "passed": true}, {"name": "with on_failure='flag' the same solve returns with info.converged", "value": false, "expected": "false", "passed": true}, {"name": "adjoint and direct totals meet as the linear tolerance tightens: largest relative difference at 1e-8, 1e-10, 1e-12", "value": "2.9e-05 / 1.3e-06 / 5.8e-09", "expected": "decreasing, below 1e-7 at 1e-12", "passed": true}, {"name": "OpenMDAO is installed (extra 'mdo')", "value": true, "expected": "true", "passed": true}, {"name": "OpenMDAO check_partials of the implicit flow component and the functionals component (forward and reverse vs central differences): largest relative error", "value": 5.647073721827089e-09, "expected": "< 1e-6", "passed": true}, {"name": "OpenMDAO totals through the implicit component vs the discipline's adjoint totals (rel., largest)", "value": 4.143386736239992e-16, "expected": "< 1e-6 (linear solves to 1e-10)", "passed": true}, {"name": "coupled flow\u2013structure adjoint through the implicit component vs finite difference (rel.)", "value": 1.2306740978331783e-07, "expected": "< 5e-6 (finite-difference step 1e-4)", "passed": true}, {"name": "coupled totals, forward vs reverse mode (rel.)", "value": 9.706058939078313e-10, "expected": "< 1e-6 (linear block Gauss\u2013Seidel to 1e-9)", "passed": true}, {"name": "the coupling is active: largest deflection [chords]", "value": 0.005555411812862289, "expected": "> 1e-5", "passed": true}], "charts": [], "tables": [{"id": "contract", "title": "Linear operators of the discipline", "columns": ["point", "check", "left side / value", "right side / reference", "relative difference"], "rows": [["solution (the discipline's point)", "apply_linear: forward vs reverse (dot product)", 1812.3861364619079, 1812.3861364619083, 2.509108526807702e-16], ["solution (the discipline's point)", "residual partials vs central difference (step 1e-06)", 44.49160182777408, 44.491601872525486, 1.3197198948481657e-09], ["solution (the discipline's point)", "partials of cl vs central difference (step 1e-06)", 0.09192211639504613, 0.09192211614106327, 2.7630223626428235e-09], ["solution (the discipline's point)", "partials of cd vs central difference (step 1e-06)", 0.19124403506704385, 0.19124403504312132, 1.250890288824776e-10], ["solution (the discipline's point)", "partials of cm vs central difference (step 1e-06)", 0.01444457045521215, 0.014444570584776217, 8.969741748113631e-09], ["solution (the discipline's point)", "partials of f_surface vs central difference (step 1e-06)", 0.5161425867925478, 0.5161425867955538, 5.490319786905606e-10], ["solution (the discipline's point)", "solve_linear fwd: |A x \u2212 b| / |b| by apply_linear", 35, 9.550073040792928e-12, 9.550459834064449e-12], ["solution (the discipline's point)", "solve_linear rev: |A\u1d40 y \u2212 c| / |c| by apply_linear", 35, 6.345590223458847e-12, 6.34562428653658e-12], ["solution (the discipline's point)", "solve_linear: forward vs reverse (dot product)", 7684.662647490721, 7684.6626474804225, 1.3400989712329857e-12], ["named point (perturbed state and inputs)", "apply_linear: forward vs reverse (dot product)", 1883.3906011585113, 1883.3906011585113, 0.0], ["named point (perturbed state and inputs)", "residual partials vs central difference (step 1e-06)", 50.89405240843462, 50.89405241331946, 1.0737359947172154e-09], ["named point (perturbed state and inputs)", "partials of cl vs central difference (step 1e-06)", 0.09434233196928163, 0.09434233155802829, 4.3591602003976465e-09], ["named point (perturbed state and inputs)", "partials of cd vs central difference (step 1e-06)", 0.1907307183400462, 0.19073071837530375, 1.848551045284357e-10], ["named point (perturbed state and inputs)", "partials of cm vs central difference (step 1e-06)", 0.014664273610569017, 0.014664273441378217, 1.1537619025937098e-08], ["named point (perturbed state and inputs)", "partials of f_surface vs central difference (step 1e-06)", 0.5171756621270838, 0.5171756621274309, 2.2627968699248274e-10], ["named point (perturbed state and inputs)", "solve_linear fwd: |A x \u2212 b| / |b| by apply_linear", 35, 6.844627867540854e-12, 6.8460374823516335e-12], ["named point (perturbed state and inputs)", "solve_linear rev: |A\u1d40 y \u2212 c| / |c| by apply_linear", 36, 3.7119094046268216e-12, 3.71200290712063e-12], ["named point (perturbed state and inputs)", "solve_linear: forward vs reverse (dot product)", 7763.838178498975, 7763.838178530426, 4.050990703152813e-12], ["solution (the discipline's point)", "tangent_product vs adjoint_product (dot product)", -4.144651796987414, -4.144651799738366, 6.637352423181062e-10]]}, {"id": "tolerance", "title": "Adjoint and direct totals against the tolerance of their linear solves", "columns": ["linear tolerance", "derivative", "adjoint", "direct", "relative difference"], "rows": [[1e-08, "d cl / d alpha", 7.518154449858666, 7.518154844997146, 5.255790660139064e-08], [1e-08, "d cl / d mach", 0.1867089811990073, 0.1867036345177427, 2.863644389403313e-05], [1e-10, "d cl / d alpha", 7.518154448674136, 7.518154459363959, 1.421868000529879e-09], [1e-10, "d cl / d mach", 0.18670898148983386, 0.18670873155675424, 1.3386237642504528e-06], [1e-12, "d cl / d alpha", 7.518154448733103, 7.518154448846527, 1.508667289041752e-11], [1e-12, "d cl / d mach", 0.1867089814200873, 0.18670898033809147, 5.795092544767421e-09]]}, {"id": "openmdao", "title": "OpenMDAO integration", "columns": ["quantity", "value"], "rows": [["check_partials flow.solver: 4 (of, wrt) pairs, directional", 3.0314564874826074e-09], ["check_partials flow.functionals: 12 (of, wrt) pairs, directional", 5.647073721827089e-09], ["totals through the implicit component (reverse) vs FlowDiscipline.totals", 4.143386736239992e-16], ["coupled dcl/d\u03b1, OpenMDAO reverse mode", 7.541170974686074], ["coupled dcl/d\u03b1, OpenMDAO forward mode", 7.541170982005579], ["coupled dcl/d\u03b1, central difference of re-converged coupled analyses", 7.54117004661381], ["relative difference, reverse mode vs finite difference", 1.2306740978331783e-07], ["dcl/d\u03b1 of the rigid aerofoil", 7.518154448674136], ["largest deflection [chords]", 0.005555411812862289]]}], "provenance": {"version": "0.4.0", "commit": "39979fcf902ad6116eb550b881b4278d4599c8e2", "dirty": false, "describe": "39979fcf90", "device": {"platform": "cpu", "device": "cpu:0", "device_kind": "cpu", "jax": "0.11.2", "x64": true}, "timestamp": "2026-11-12T11:40:21-0500"}, "wall_time": 249.94, "notes": "OpenMDAO 3.45.2. The coupled derivative differs from the rigid one by +0.31 %. Measured in this run: largest dot-product defect of apply_linear 2.5e-16, of solve_linear 4.1e-12, of the total products 6.6e-10; largest difference between partials and central differences 1.2e-08; the solve with an unreachable tolerance stopped at a reduction of 1.6e-14.", "level": "quick"}