diff --git a/SU2_CFD/src/solvers/CEulerSolver.cpp b/SU2_CFD/src/solvers/CEulerSolver.cpp
index 32c265e55656..2b040b298b3c 100644
--- a/SU2_CFD/src/solvers/CEulerSolver.cpp
+++ b/SU2_CFD/src/solvers/CEulerSolver.cpp
@@ -7766,6 +7766,8 @@ void CEulerSolver::BC_Supersonic_Outlet(CGeometry *geometry, CSolver **solver_co
conv_numerics->SetNormal(Normal);
conv_numerics->SetPrimitive(V_domain, V_outlet);
+ if (config->GetKind_FluidModel() != STANDARD_AIR && config->GetKind_FluidModel() != IDEAL_GAS)
+ conv_numerics->SetSecondary(nodes->GetSecondary(iPoint), nodes->GetSecondary(iPoint));
if (dynamic_grid)
conv_numerics->SetGridVel(geometry->nodes->GetGridVel(iPoint),
@@ -7803,6 +7805,8 @@ void CEulerSolver::BC_Supersonic_Outlet(CGeometry *geometry, CSolver **solver_co
/*--- Primitive variables, and gradient ---*/
visc_numerics->SetPrimitive(V_domain, V_domain);
+ if (config->GetKind_FluidModel() != STANDARD_AIR && config->GetKind_FluidModel() != IDEAL_GAS)
+ visc_numerics->SetSecondary(nodes->GetSecondary(iPoint), nodes->GetSecondary(iPoint));
visc_numerics->SetPrimVarGradient(nodes->GetGradient_Primitive(iPoint), nodes->GetGradient_Primitive(iPoint));
/*--- Turbulent kinetic energy ---*/
diff --git a/UnitTests/SU2_CFD/solvers/supersonic_outlet_tests.cpp b/UnitTests/SU2_CFD/solvers/supersonic_outlet_tests.cpp
new file mode 100644
index 000000000000..62d635a8507b
--- /dev/null
+++ b/UnitTests/SU2_CFD/solvers/supersonic_outlet_tests.cpp
@@ -0,0 +1,123 @@
+/*!
+ * \file supersonic_outlet_tests.cpp
+ * \brief Regression for extrapolated supersonic outlet thermodynamic data.
+ * \version 8.5.0 "Harrier"
+ *
+ * SU2 Project Website: https://su2code.github.io
+ *
+ * The SU2 Project is maintained by the SU2 Foundation
+ * (http://su2foundation.org)
+ *
+ * Copyright 2012-2026, SU2 Contributors (cf. AUTHORS.md)
+ *
+ * SU2 is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * SU2 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with SU2. If not, see .
+ */
+
+#include "catch.hpp"
+#include "../../UnitQuadTestCase.hpp"
+#include "../../../SU2_CFD/include/variables/CNSVariable.hpp"
+#include "../../../SU2_CFD/include/fluid/CPengRobinson.hpp"
+#include "../../../SU2_CFD/include/numerics/flow/convection/hllc.hpp"
+#include "../../../SU2_CFD/include/numerics/flow/flow_diffusion.hpp"
+
+TEST_CASE("Supersonic outlet supplies general-gas thermodynamic data", "[Supersonic-outlet]") {
+ for (const auto nDim : {2u, 3u}) {
+ for (const bool realGas : {true, false}) {
+ for (const bool moving : {false, true}) {
+ for (const bool viscous : {false, true}) {
+ UnitQuadTestCase test;
+ test.config_options =
+ std::string(viscous ? "SOLVER= NAVIER_STOKES\n" : "SOLVER= EULER\n") +
+ "MESH_FORMAT= " + std::string(nDim == 2 ? "RECTANGLE" : "BOX") +
+ "\nMESH_BOX_SIZE= 5,5,5\nREF_DIMENSIONALIZATION= DIMENSIONAL\nMACH_NUMBER= 0.1\n"
+ "FREESTREAM_OPTION= DENSITY_FS\nFREESTREAM_DENSITY= 230\nFREESTREAM_PRESSURE= 1500112\n"
+ "GAS_CONSTANT= 35.152\nCONV_NUM_METHOD_FLOW= HLLC\nTIME_DISCRE_FLOW= EULER_IMPLICIT\n"
+ "REYNOLDS_NUMBER= 1E6\nREYNOLDS_LENGTH= 1\n"
+ "VISCOSITY_MODEL= CONSTANT_VISCOSITY\nCONDUCTIVITY_MODEL= CONSTANT_CONDUCTIVITY\n"
+ "GRID_MOVEMENT= STEADY_TRANSLATION\nTRANSLATION_RATE= 0,0,0\n"
+ "MARKER_SUPERSONIC_OUTLET= (x_plus)\nMARKER_MONITORING= (x_plus)\nMARKER_EULER= " +
+ std::string(nDim == 2 ? "(x_minus,y_minus,y_plus)\n" : "(x_minus,y_minus,y_plus,z_minus,z_plus)\n") +
+ (realGas ? "FLUID_MODEL= PR_GAS\nGAMMA_VALUE= 1.0125\nCRITICAL_PRESSURE= 1415200\n"
+ "CRITICAL_TEMPERATURE= 564.1\nACENTRIC_FACTOR= 0.529\n"
+ : "FLUID_MODEL= IDEAL_GAS\nGAMMA_VALUE= 1.4\n");
+ test.InitConfig();
+ test.InitGeometry();
+ test.InitSolver();
+ std::unique_ptr gas =
+ realGas ? std::unique_ptr(new CPengRobinson(1.0125, 35.152, 1415200, 564.1, .529))
+ : std::unique_ptr(new CIdealGas(1.4, 35.152));
+ gas->SetLaminarViscosityModel(test.config.get());
+ gas->SetThermalConductivityModel(test.config.get());
+ gas->SetTDState_Prho(1500112, 230);
+ const auto nVar = nDim + 2;
+ const su2double grid[3] = {moving ? 20.0 : 0.0, 0, 0};
+ const su2double velocity[3] = {2 * gas->GetSoundSpeed() + grid[0], 2, 0};
+ const su2double density = gas->GetDensity(), pressure = gas->GetPressure();
+ const auto energy = gas->GetStaticEnergy() + .5 * GeometryToolbox::SquaredNorm(nDim, velocity);
+ const su2double enthalpy = energy + pressure / density;
+ su2double state[5] = {density};
+ for (auto i = 0u; i < nDim; ++i) state[i + 1] = density * velocity[i];
+ state[nVar - 1] = density * energy;
+ auto* solver = test.solver[FLOW_SOL];
+ auto* nodes = static_cast(solver->GetNodes());
+ for (auto p = 0ul; p < test.geometry->GetnPoint(); ++p) {
+ nodes->SetSolution(p, state);
+ nodes->SetSolution_Old(p, state);
+ if (viscous) {
+ REQUIRE(static_cast(nodes)->SetPrimVar(p, 0, 0, gas.get()));
+ static_cast(nodes)->SetSecondaryVar(p, gas.get());
+ } else {
+ REQUIRE(nodes->SetPrimVar(p, gas.get()));
+ nodes->SetSecondaryVar(p, gas.get());
+ }
+ test.geometry->nodes->SetGridVel(p, grid);
+ for (auto i = 0u; i < nVar; ++i) solver->LinSysRes(p, i) = 0;
+ }
+ std::unique_ptr numerics =
+ realGas ? std::unique_ptr(new CUpwGeneralHLLC_Flow(nDim, nVar, test.config.get()))
+ : std::unique_ptr(new CUpwHLLC_Flow(nDim, nVar, test.config.get()));
+ std::unique_ptr diffusion;
+ if (viscous) {
+ if (realGas)
+ diffusion.reset(new CGeneralAvgGrad_Flow(nDim, nVar, true, test.config.get()));
+ else
+ diffusion.reset(new CAvgGrad_Flow(nDim, nVar, true, test.config.get()));
+ }
+ for (auto marker = 0u; marker < test.config->GetnMarker_All(); ++marker) {
+ if (test.config->GetMarker_All_TagBound(marker) != "x_plus") continue;
+ solver->BC_Supersonic_Outlet(test.geometry.get(), test.solver, numerics.get(), diffusion.get(),
+ test.config.get(), marker);
+ for (auto v = 0ul; v < test.geometry->nVertex[marker]; ++v) {
+ const auto p = test.geometry->vertex[marker][v]->GetNode();
+ su2double normal[3], flux[5];
+ test.geometry->vertex[marker][v]->GetNormal(normal);
+ for (auto i = 0u; i < nDim; ++i) normal[i] = -normal[i];
+ numerics->GetInviscidProjFlux(&density, velocity, &pressure, &enthalpy, normal, flux);
+ numerics->SetNormal(normal);
+ numerics->SetPrimitive(nodes->GetPrimitive(p), nodes->GetPrimitive(p));
+ if (realGas) numerics->SetSecondary(nodes->GetSecondary(p), nodes->GetSecondary(p));
+ const auto reference = numerics->ComputeResidual(test.config.get());
+ for (auto i = 0u; i < nVar; ++i) {
+ // The boundary must use the same extrapolated state as an interior equal-state flux.
+ CHECK(solver->LinSysRes(p, i) == Approx(SU2_TYPE::GetValue(reference.residual[i])));
+ if (!moving) CHECK(solver->LinSysRes(p, i) == Approx(SU2_TYPE::GetValue(flux[i])));
+ for (auto j = 0u; j < nVar; ++j) CHECK(std::isfinite(solver->Jacobian.GetBlock(p, p)[i * nVar + j]));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/UnitTests/meson.build b/UnitTests/meson.build
index ba3c63afce92..9f5e19f99709 100644
--- a/UnitTests/meson.build
+++ b/UnitTests/meson.build
@@ -20,6 +20,7 @@ su2_cfd_tests = files(['Common/CConfig_tests.cpp',
'SU2_CFD/output/COutput_convergence_tests.cpp',
'SU2_CFD/gradients.cpp',
'SU2_CFD/solvers/CNEMOEulerSolver_tests.cpp',
+ 'SU2_CFD/solvers/supersonic_outlet_tests.cpp',
'SU2_CFD/nemo_viscous_assembly.cpp',
'SU2_CFD/windowing.cpp',
'Common/toolboxes/random_toolbox_tests.cpp',