Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
dc66724
custom species wall BC
bigfooted Nov 11, 2025
1d81103
default zero flux species wall BC
bigfooted Nov 11, 2025
747c7de
add keyword and testcase
bigfooted Nov 12, 2025
f1ab1a6
switch to passivedouble
bigfooted Nov 12, 2025
d779979
Potential fix for code scanning alert no. 5749: Resource not released…
bigfooted Nov 12, 2025
38d926d
typo in config_template.cfg
bigfooted Nov 12, 2025
9dc1597
Merge branch 'feature_custom_species_walls' of https://github.com/su2…
bigfooted Nov 12, 2025
88e2922
support per-species flux or value
bigfooted Nov 14, 2025
19d0bd6
Potential fix for code scanning alert no. 5752: Comparison of narrow …
bigfooted Nov 14, 2025
062e482
change out-of-bounds error into warning.
bigfooted Nov 14, 2025
017016f
Merge branch 'feature_custom_species_walls' of https://github.com/su2…
bigfooted Nov 14, 2025
5f7c4c9
add testcases
bigfooted Nov 15, 2025
3ece590
Merge branch 'develop' into feature_custom_species_walls
bigfooted Nov 18, 2025
b88877b
Merge branch 'develop' into feature_custom_species_walls
bigfooted Dec 4, 2025
e3d2dc8
Merge branch 'feature_custom_species_walls' of https://github.com/su2…
bigfooted Dec 4, 2025
39ad198
run precommit
bigfooted Dec 4, 2025
8aebccf
Merge branch 'develop' into feature_custom_species_walls
bigfooted Dec 17, 2025
ff27515
Potential fix for code scanning alert no. 5867: Unused local variable
bigfooted Dec 17, 2025
40d5b99
cleanup
bigfooted Dec 17, 2025
bbebbbb
empty line
bigfooted Dec 17, 2025
b916b03
add regression test
bigfooted Dec 17, 2025
dc70b78
Merge branch 'develop' into feature_custom_species_walls
bigfooted Dec 17, 2025
55179d0
Merge branch 'develop' into feature_custom_species_walls
bigfooted Dec 19, 2025
776059d
Apply suggestion from @bigfooted
bigfooted Dec 19, 2025
d18433d
update regression
bigfooted Dec 23, 2025
09ab65d
Merge branch 'develop' into feature_custom_species_walls
bigfooted Dec 23, 2025
a9bc5dc
Update Common/include/option_structure.hpp
bigfooted Dec 24, 2025
51e84b5
Update Common/include/CConfig.hpp
bigfooted Dec 24, 2025
d46ac46
Update SU2_CFD/include/drivers/CDriverBase.hpp
bigfooted Dec 24, 2025
4aa5216
Update SU2_CFD/include/solvers/CSolver.hpp
bigfooted Dec 24, 2025
9494da4
Update SU2_CFD/include/solvers/CSpeciesSolver.hpp
bigfooted Dec 24, 2025
76c604e
Update SU2_CFD/src/solvers/CSpeciesSolver.cpp
bigfooted Dec 24, 2025
f71f958
Update SU2_CFD/src/solvers/CSpeciesSolver.cpp
bigfooted Dec 24, 2025
d4f6e4b
Merge branch 'develop' into feature_custom_species_walls
bigfooted Dec 24, 2025
ae62850
Update SU2_CFD/include/solvers/CSpeciesSolver.hpp
bigfooted Dec 24, 2025
9749e64
Update SU2_CFD/include/solvers/CSpeciesSolver.hpp
bigfooted Dec 24, 2025
72eb31e
implement review changes
bigfooted Dec 24, 2025
dff9fbe
Merge branch 'feature_custom_species_walls' of https://github.com/su2…
bigfooted Dec 24, 2025
3357529
implement review changes
bigfooted Dec 24, 2025
f9b53b6
precommit
bigfooted Dec 25, 2025
ee4807d
Merge branch 'develop' into feature_custom_species_walls
bigfooted Dec 25, 2025
712cc6e
Merge branch 'develop' into feature_custom_species_walls
bigfooted Dec 27, 2025
23327a9
Merge branch 'develop' into feature_custom_species_walls
bigfooted Dec 28, 2025
8828523
Update Common/include/option_structure.hpp
bigfooted Dec 29, 2025
b0813b2
Merge branch 'develop' into feature_custom_species_walls
bigfooted Dec 29, 2025
275afe3
change names
bigfooted Dec 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions Common/include/CConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ class CConfig {
nMarker_Inlet, /*!< \brief Number of inlet flow markers. */
nMarker_Inlet_Species, /*!< \brief Number of inlet species markers. */
nSpecies_per_Inlet, /*!< \brief Number of species defined per inlet markers. */
nMarker_Wall_Species, /*!< \brief Number of wall species markers. */
nSpecies_per_Wall, /*!< \brief Number of species defined per wall markers. */
nMarker_Inlet_Turb, /*!< \brief Number of inlet turbulent markers. */
nTurb_Properties, /*!< \brief Number of turbulent properties per inlet markers. */
nMarker_Riemann, /*!< \brief Number of Riemann flow markers. */
Expand Down Expand Up @@ -255,6 +257,7 @@ class CConfig {
*Marker_ActDiskBemOutlet_Axis, /*!< \brief Actuator disk BEM outlet markers passed to MARKER_ACTDISK_BEM_AXIS. */
*Marker_Inlet, /*!< \brief Inlet flow markers. */
*Marker_Inlet_Species, /*!< \brief Inlet species markers. */
*Marker_Wall_Species, /*!< \brief Wall species markers. */
*Marker_Inlet_Turb, /*!< \brief Inlet turbulent markers. */
*Marker_Riemann, /*!< \brief Riemann markers. */
*Marker_Giles, /*!< \brief Giles markers. */
Expand Down Expand Up @@ -294,6 +297,8 @@ class CConfig {
su2double **Inlet_Velocity; /*!< \brief Specified flow velocity vectors for supersonic inlet boundaries. */
su2double **Inlet_SpeciesVal; /*!< \brief Specified species vector for inlet boundaries. */
su2double **Inlet_TurbVal; /*!< \brief Specified turbulent intensity and viscosity ratio for inlet boundaries. */
WALL_SPECIES_TYPE **Kind_Wall_Species; /*!< \brief Species boundary condition type for wall boundaries (FLUX or VALUE) per species. */
su2double **Wall_SpeciesVal; /*!< \brief Specified species flux or value for wall boundaries per species. */
su2double *EngineInflow_Target; /*!< \brief Specified fan face targets for nacelle boundaries. */
su2double *Inflow_Mach; /*!< \brief Specified fan face mach for nacelle boundaries. */
su2double *Inflow_Pressure; /*!< \brief Specified fan face pressure for nacelle boundaries. */
Expand Down Expand Up @@ -1394,6 +1399,11 @@ class CConfig {
void addGilesOption(const string name, unsigned short & nMarker_Giles, string * & Marker_Giles, unsigned short* & option_field, const map<string, Tenum> & enum_map,
su2double* & var1, su2double* & var2, su2double** & FlowDir, su2double* & relaxfactor1, su2double* & relaxfactor2);

template <class Tenum>
void addWallSpeciesOption(const string name, unsigned short & nMarker_Wall_Species, string * & Marker_Wall_Species,
WALL_SPECIES_TYPE** & option_field, const map<string, Tenum> & enum_map,
su2double** & value, unsigned short & nSpecies_per_Wall);

void addExhaustOption(const string& name, unsigned short & nMarker_Exhaust, string * & Marker_Exhaust,
su2double* & Ttotal, su2double* & Ptotal);

Expand Down Expand Up @@ -7149,6 +7159,22 @@ class CConfig {
*/
const su2double* GetInlet_SpeciesVal(const string& val_index) const;

/*!
* \brief Get the species value at a wall boundary for a specific species
* \param[in] val_marker - Marker tag corresponding to the wall boundary.
* \param[in] iSpecies - Species index.
* \return The wall species value (flux or Dirichlet value).
*/
su2double GetWall_SpeciesVal(const string& val_marker, unsigned short iSpecies) const;

/*!
* \brief Get the species boundary condition type at a wall boundary for a specific species
* \param[in] val_marker - Marker tag corresponding to the wall boundary.
* \param[in] iSpecies - Species index.
* \return The wall species type (FLUX or VALUE).
*/
WALL_SPECIES_TYPE GetWall_SpeciesType(const string& val_marker, unsigned short iSpecies) const;

/*!
* \brief Get the turbulent properties values at an inlet boundary
* \param[in] val_index - Index corresponding to the inlet boundary.
Expand Down
12 changes: 12 additions & 0 deletions Common/include/option_structure.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1835,6 +1835,18 @@ static const MapType<std::string, RIEMANN_TYPE> Giles_Map = {
MakePair("MASS_FLOW_OUTLET", MASS_FLOW_OUTLET)
};

/*!
* \brief Types of wall species boundary conditions.
*/
enum class WALL_SPECIES_TYPE {
FLUX, /*!< \brief Neumann flux boundary condition for wall species. */
VALUE /*!< \brief Dirichlet value boundary condition for wall species. */
};
static const MapType<std::string, WALL_SPECIES_TYPE> Wall_Map = {
MakePair("FLUX", WALL_SPECIES_TYPE::FLUX)
MakePair("VALUE", WALL_SPECIES_TYPE::VALUE)
};

/*!
* \brief Types of mixing process for averaging quantities at the boundaries.
*/
Expand Down
164 changes: 164 additions & 0 deletions Common/include/option_structure.inl
Original file line number Diff line number Diff line change
Expand Up @@ -1302,6 +1302,170 @@ class COptionRiemann : public COptionBase {
}
};

template <class Tenum>
class COptionWallSpecies : public COptionBase {
protected:
map<string, Tenum> m;
string name; // identifier for the option
unsigned short& size;
string*& marker;
WALL_SPECIES_TYPE**& field; // Reference to the field name (now 2D: marker x species)
su2double**& value; // Now 2D: marker x species
unsigned short& nSpecies_per_Wall;

public:
COptionWallSpecies(string option_field_name, unsigned short& nMarker_Wall_Species, string*& Marker_Wall_Species,
WALL_SPECIES_TYPE**& option_field, const map<string, Tenum> m, su2double**& value,
unsigned short& nSpecies_per_Wall)
: size(nMarker_Wall_Species),
marker(Marker_Wall_Species),
field(option_field),
value(value),
nSpecies_per_Wall(nSpecies_per_Wall) {
this->name = option_field_name;
this->m = m;
}
~COptionWallSpecies() override {
if (marker) {
delete[] marker;
marker = nullptr;
}
if (field) {
for (unsigned short i = 0; i < size; i++) {
delete[] field[i];
}
delete[] field;
field = nullptr;
}
if (value) {
for (unsigned short i = 0; i < size; i++) {
delete[] value[i];
}
delete[] value;
value = nullptr;
}
}

string SetValue(const vector<string>& option_value) override {
COptionBase::SetValue(option_value);
unsigned short totalVals = option_value.size();
if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) {
this->size = 0;
this->marker = nullptr;
this->field = nullptr;
this->value = nullptr;
this->nSpecies_per_Wall = 0;
return "";
}

/*--- Determine the number of markers and species per marker.
* Format: marker1, TYPE1, value1, TYPE2, value2, ..., marker2, TYPE1, value1, ...
* Each marker name starts with a letter, each TYPE is an enum string (starts with letter),
* and each value is numeric. Pattern: marker, (TYPE, value) x N ---*/

vector<unsigned short> marker_indices; // Indices where markers start
vector<unsigned short> species_counts; // Number of species per marker

// Find all marker positions (strings starting with a letter that are not TYPE keywords)
for (unsigned short i = 0; i < totalVals; i++) {
if (isalpha(option_value[i][0])) {
// Check if this could be a TYPE keyword (i.e., is it in the enum map?)
if (this->m.find(option_value[i]) != m.end()) {
continue; // This is a TYPE keyword, not a marker
}
// This is a marker name
marker_indices.push_back(i);
}
}

if (marker_indices.empty()) {
string newstring;
newstring.append(this->name);
newstring.append(": no valid markers found");
return newstring;
}

// Calculate number of species for each marker
for (size_t i = 0; i < marker_indices.size(); i++) {
unsigned short start_idx = marker_indices[i] + 1; // Start after marker name
unsigned short end_idx = (i + 1 < marker_indices.size()) ? marker_indices[i + 1] : totalVals;
unsigned short entries = end_idx - start_idx;

// Each species needs 2 entries: TYPE and value
if (entries % 2 != 0) {
string newstring;
newstring.append(this->name);
newstring.append(": each marker must have pairs of (TYPE, value) entries");
return newstring;
}

species_counts.push_back(entries / 2);
}

// Check that all markers have the same number of species
this->nSpecies_per_Wall = species_counts[0];
for (auto count : species_counts) {
if (count != this->nSpecies_per_Wall) {
string newstring;
newstring.append(this->name);
newstring.append(": all markers must specify the same number of species");
return newstring;
}
}

// Allocate arrays
this->size = marker_indices.size();
this->marker = new string[this->size];
this->field = new WALL_SPECIES_TYPE*[this->size];
this->value = new su2double*[this->size];

for (unsigned short i = 0; i < this->size; i++) {
this->field[i] = new WALL_SPECIES_TYPE[this->nSpecies_per_Wall];
this->value[i] = new su2double[this->nSpecies_per_Wall];
}

// Parse the values
for (unsigned short iMarker = 0; iMarker < this->size; iMarker++) {
unsigned short marker_idx = marker_indices[iMarker];
this->marker[iMarker].assign(option_value[marker_idx]);

// Parse species data for this marker
for (unsigned short iSpecies = 0; iSpecies < this->nSpecies_per_Wall; iSpecies++) {
unsigned short type_idx = marker_idx + 1 + 2 * iSpecies;
unsigned short val_idx = type_idx + 1;

// Check TYPE keyword
if (this->m.find(option_value[type_idx]) == m.end()) {
string str;
str.append(this->name);
str.append(": invalid option value ");
str.append(option_value[type_idx]);
str.append(". Check current SU2 options in config_template.cfg.");
return str;
}

Tenum val = this->m[option_value[type_idx]];
this->field[iMarker][iSpecies] = val;

istringstream ss_value(option_value[val_idx]);
if (!(ss_value >> this->value[iMarker][iSpecies])) {
return badValue("WallSpecies", this->name);
}
}
}

return "";
}

void SetDefault() override {
this->marker = nullptr;
this->field = nullptr;
this->value = nullptr;
this->size = 0; // There is no default value for list
this->nSpecies_per_Wall = 0;
}
};

template <class Tenum>
class COptionGiles : public COptionBase {
map<string, Tenum> m;
Expand Down
41 changes: 40 additions & 1 deletion Common/src/CConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,16 @@ void CConfig::addRiemannOption(const string name, unsigned short & nMarker_Riema
option_map.insert(pair<string, COptionBase *>(name, val));
}

template <class Tenum>
void CConfig::addWallSpeciesOption(const string name, unsigned short & nMarker_Wall_Species, string * & Marker_Wall_Species,
WALL_SPECIES_TYPE** & option_field, const map<string, Tenum> & enum_map,
su2double** & value, unsigned short & nSpecies_per_Wall) {
assert(option_map.find(name) == option_map.end());
all_options.insert(pair<string, bool>(name, true));
COptionBase* val = new COptionWallSpecies<Tenum>(name, nMarker_Wall_Species, Marker_Wall_Species, option_field, enum_map, value, nSpecies_per_Wall);
option_map.insert(pair<string, COptionBase *>(name, val));
}

template <class Tenum>
void CConfig::addGilesOption(const string name, unsigned short & nMarker_Giles, string * & Marker_Giles, unsigned short* & option_field, const map<string, Tenum> & enum_map,
su2double* & var1, su2double* & var2, su2double** & FlowDir, su2double* & relaxfactor1, su2double* & relaxfactor2) {
Expand Down Expand Up @@ -1621,6 +1631,11 @@ void CConfig::SetConfig_Options() {
/*!\brief MARKER_RIEMANN \n DESCRIPTION: Riemann boundary marker(s) with the following formats, a unit vector.
* \n OPTIONS: See \link Riemann_Map \endlink. The variables indicated by the option and the flow direction unit vector must be specified. \ingroup Config*/
addRiemannOption("MARKER_RIEMANN", nMarker_Riemann, Marker_Riemann, Kind_Data_Riemann, Riemann_Map, Riemann_Var1, Riemann_Var2, Riemann_FlowDir);
/*!\brief MARKER_WALL_SPECIES \n DESCRIPTION: Wall species boundary marker(s) with the following format:
* (marker_name, BC_TYPE, value, BC_TYPE, value, ...) where BC_TYPE is either FLUX (Neumann) or VALUE (Dirichlet).
* Each marker must specify the same number of species (N species per marker).
* \n OPTIONS: See \link Wall_Map \endlink. \ingroup Config*/
addWallSpeciesOption("MARKER_WALL_SPECIES", nMarker_Wall_Species, Marker_Wall_Species, Kind_Wall_Species, Wall_Map, Wall_SpeciesVal, nSpecies_per_Wall);
/*!\brief MARKER_GILES \n DESCRIPTION: Giles boundary marker(s) with the following formats, a unit vector. */
/* \n OPTIONS: See \link Giles_Map \endlink. The variables indicated by the option and the flow direction unit vector must be specified. \ingroup Config*/
addGilesOption("MARKER_GILES", nMarker_Giles, Marker_Giles, Kind_Data_Giles, Giles_Map, Giles_Var1, Giles_Var2, Giles_FlowDir, RelaxFactorAverage, RelaxFactorFourier);
Expand Down Expand Up @@ -5702,7 +5717,7 @@ void CConfig::SetPostprocessing(SU2_COMPONENT val_software, unsigned short val_i
/*--- Helper function that checks scalar variable bounds. ---*/
auto checkScalarBounds = [&](su2double scalar, const string& name, su2double lowerBound, su2double upperBound) {
if (scalar < lowerBound || scalar > upperBound)
SU2_MPI::Error(string("Variable: ") + name + string(", is out of bounds."), CURRENT_FUNCTION);
cout << "Value: " << scalar << " for " << name << " is out of bounds [" << lowerBound << "," << upperBound << "]." << endl;
};

/*--- Some options have to provide as many entries as there are additional species equations. ---*/
Expand All @@ -5713,6 +5728,8 @@ void CConfig::SetPostprocessing(SU2_COMPONENT val_software, unsigned short val_i
nSpecies_options.insert(nSpecies_options.end(), {nSpecies_Clipping_Min, nSpecies_Clipping_Max});
if (nMarker_Inlet_Species > 0)
nSpecies_options.push_back(nSpecies_per_Inlet);
if (nMarker_Wall_Species > 0)
nSpecies_options.push_back(nSpecies_per_Wall);
// Add more options for size check here.

/*--- nSpecies_Init is the master, but it simply checks for consistency. ---*/
Expand Down Expand Up @@ -9250,6 +9267,28 @@ const su2double* CConfig::GetInlet_SpeciesVal(const string& val_marker) const {
return Inlet_SpeciesVal[iMarker_Inlet_Species];
}

su2double CConfig::GetWall_SpeciesVal(const string& val_marker, unsigned short iSpecies) const {
/*--- Search for the marker in the wall species list ---*/
for (unsigned short iMarker_Wall_Species = 0; iMarker_Wall_Species < nMarker_Wall_Species; iMarker_Wall_Species++) {
if (Marker_Wall_Species[iMarker_Wall_Species] == val_marker) {
return Wall_SpeciesVal[iMarker_Wall_Species][iSpecies];
}
}
/*--- If marker not found (MARKER_WALL_SPECIES=NONE), return zero flux ---*/
return 0.0;
}

WALL_SPECIES_TYPE CConfig::GetWall_SpeciesType(const string& val_marker, unsigned short iSpecies) const {
/*--- Search for the marker in the wall species list ---*/
for (unsigned short iMarker_Wall_Species = 0; iMarker_Wall_Species < nMarker_Wall_Species; iMarker_Wall_Species++) {
if (Marker_Wall_Species[iMarker_Wall_Species] == val_marker) {
return Kind_Wall_Species[iMarker_Wall_Species][iSpecies];
}
}
/*--- If marker not found (MARKER_WALL_SPECIES=NONE), return FLUX type (zero flux BC) ---*/
return WALL_SPECIES_TYPE::FLUX;
}

const su2double* CConfig::GetInlet_TurbVal(const string& val_marker) const {
/*--- If Turbulent Inlet is not provided for the marker, return free stream values. ---*/
for (auto iMarker = 0u; iMarker < nMarker_Inlet_Turb; iMarker++) {
Expand Down
12 changes: 12 additions & 0 deletions SU2_CFD/include/drivers/CDriverBase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,18 @@ class CDriverBase {
main_geometry->SetCustomBoundaryHeatFlux(iMarker, iVertex, WallHeatFlux);
}

/*!
* \brief Set the wall normal scalar values at a vertex on a specified marker (MARKER_PYTHON_CUSTOM).
* \note This can be the input of a scalar transport equation.
* \param[in] iMarker - Marker identifier.
* \param[in] iVertex - Vertex identifier.
* \param[in] WallScalar - Value of the normal heat flux.
*/
inline void SetMarkerCustomScalar(unsigned short iMarker, unsigned long iVertex, vector<passivedouble> WallScalar) {
auto* solver = solver_container[selected_zone][INST_0][MESH_0][SPECIES_SOL];
solver->SetCustomBoundaryScalar(iMarker, iVertex, WallScalar);
}

/*!
* \brief Selects zone to be used for python driver operations.
* \param[in] iZone - Zone identifier.
Expand Down
10 changes: 10 additions & 0 deletions SU2_CFD/include/solvers/CSolver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2856,6 +2856,16 @@ class CSolver {
unsigned long val_vertex,
unsigned short val_dim) const { return 0; }


/*!
* \brief Set the value of the customized normal scalar values/flux at a specified vertex on a specified marker.
* \param[in] val_marker - Marker value
* \param[in] val_vertex - Boundary vertex value
*/
inline virtual void SetCustomBoundaryScalar(unsigned short val_marker, unsigned long val_vertex,
vector<passivedouble> val_customBoundaryScalar) { }


/*!
* \brief A virtual member
* \param[in] val_marker - Surface marker where the total temperature is set.
Expand Down
Loading