Skip to content

Commit bf255b7

Browse files
Custom species wall BC (#2618)
* custom species wall BC Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com>
1 parent f541230 commit bf255b7

11 files changed

Lines changed: 552 additions & 2 deletions

File tree

Common/include/CConfig.hpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ class CConfig {
199199
nMarker_Inlet, /*!< \brief Number of inlet flow markers. */
200200
nMarker_Inlet_Species, /*!< \brief Number of inlet species markers. */
201201
nSpecies_per_Inlet, /*!< \brief Number of species defined per inlet markers. */
202+
nMarker_Wall_Species, /*!< \brief Number of wall species markers. */
203+
nSpecies_per_Wall, /*!< \brief Number of species defined per wall markers. */
202204
nMarker_Inlet_Turb, /*!< \brief Number of inlet turbulent markers. */
203205
nTurb_Properties, /*!< \brief Number of turbulent properties per inlet markers. */
204206
nMarker_Riemann, /*!< \brief Number of Riemann flow markers. */
@@ -255,6 +257,7 @@ class CConfig {
255257
*Marker_ActDiskBemOutlet_Axis, /*!< \brief Actuator disk BEM outlet markers passed to MARKER_ACTDISK_BEM_AXIS. */
256258
*Marker_Inlet, /*!< \brief Inlet flow markers. */
257259
*Marker_Inlet_Species, /*!< \brief Inlet species markers. */
260+
*Marker_Wall_Species, /*!< \brief Wall species markers. */
258261
*Marker_Inlet_Turb, /*!< \brief Inlet turbulent markers. */
259262
*Marker_Riemann, /*!< \brief Riemann markers. */
260263
*Marker_Giles, /*!< \brief Giles markers. */
@@ -294,6 +297,8 @@ class CConfig {
294297
su2double **Inlet_Velocity; /*!< \brief Specified flow velocity vectors for supersonic inlet boundaries. */
295298
su2double **Inlet_SpeciesVal; /*!< \brief Specified species vector for inlet boundaries. */
296299
su2double **Inlet_TurbVal; /*!< \brief Specified turbulent intensity and viscosity ratio for inlet boundaries. */
300+
WALL_SPECIES_TYPE **Kind_Wall_Species; /*!< \brief Species boundary condition type for wall boundaries (FLUX or VALUE) per species. */
301+
su2double **Wall_SpeciesVal; /*!< \brief Specified species flux or value for wall boundaries per species. */
297302
su2double *EngineInflow_Target; /*!< \brief Specified fan face targets for nacelle boundaries. */
298303
su2double *Inflow_Mach; /*!< \brief Specified fan face mach for nacelle boundaries. */
299304
su2double *Inflow_Pressure; /*!< \brief Specified fan face pressure for nacelle boundaries. */
@@ -1394,6 +1399,11 @@ class CConfig {
13941399
void addGilesOption(const string name, unsigned short & nMarker_Giles, string * & Marker_Giles, unsigned short* & option_field, const map<string, Tenum> & enum_map,
13951400
su2double* & var1, su2double* & var2, su2double** & FlowDir, su2double* & relaxfactor1, su2double* & relaxfactor2);
13961401

1402+
template <class Tenum>
1403+
void addWallSpeciesOption(const string name, unsigned short & nMarker_Wall_Species, string * & Marker_Wall_Species,
1404+
WALL_SPECIES_TYPE** & option_field, const map<string, Tenum> & enum_map,
1405+
su2double** & value, unsigned short & nSpecies_per_Wall);
1406+
13971407
void addExhaustOption(const string& name, unsigned short & nMarker_Exhaust, string * & Marker_Exhaust,
13981408
su2double* & Ttotal, su2double* & Ptotal);
13991409

@@ -7149,6 +7159,22 @@ class CConfig {
71497159
*/
71507160
const su2double* GetInlet_SpeciesVal(const string& val_index) const;
71517161

7162+
/*!
7163+
* \brief Get the species value at a wall boundary for a specific species
7164+
* \param[in] val_marker - Marker tag corresponding to the wall boundary.
7165+
* \param[in] iSpecies - Species index.
7166+
* \return The wall species value (flux or Dirichlet value).
7167+
*/
7168+
su2double GetWall_SpeciesVal(const string& val_marker, unsigned short iSpecies) const;
7169+
7170+
/*!
7171+
* \brief Get the species boundary condition type at a wall boundary for a specific species
7172+
* \param[in] val_marker - Marker tag corresponding to the wall boundary.
7173+
* \param[in] iSpecies - Species index.
7174+
* \return The wall species type (FLUX or VALUE).
7175+
*/
7176+
WALL_SPECIES_TYPE GetWall_SpeciesType(const string& val_marker, unsigned short iSpecies) const;
7177+
71527178
/*!
71537179
* \brief Get the turbulent properties values at an inlet boundary
71547180
* \param[in] val_index - Index corresponding to the inlet boundary.

Common/include/option_structure.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1835,6 +1835,18 @@ static const MapType<std::string, RIEMANN_TYPE> Giles_Map = {
18351835
MakePair("MASS_FLOW_OUTLET", MASS_FLOW_OUTLET)
18361836
};
18371837

1838+
/*!
1839+
* \brief Types of wall species boundary conditions.
1840+
*/
1841+
enum class WALL_SPECIES_TYPE {
1842+
FLUX, /*!< \brief Neumann flux boundary condition for wall species. */
1843+
VALUE /*!< \brief Dirichlet value boundary condition for wall species. */
1844+
};
1845+
static const MapType<std::string, WALL_SPECIES_TYPE> Wall_Map = {
1846+
MakePair("FLUX", WALL_SPECIES_TYPE::FLUX)
1847+
MakePair("VALUE", WALL_SPECIES_TYPE::VALUE)
1848+
};
1849+
18381850
/*!
18391851
* \brief Types of mixing process for averaging quantities at the boundaries.
18401852
*/

Common/include/option_structure.inl

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,6 +1302,170 @@ class COptionRiemann : public COptionBase {
13021302
}
13031303
};
13041304

1305+
template <class Tenum>
1306+
class COptionWallSpecies : public COptionBase {
1307+
protected:
1308+
map<string, Tenum> m;
1309+
string name; // identifier for the option
1310+
unsigned short& size;
1311+
string*& marker;
1312+
WALL_SPECIES_TYPE**& field; // Reference to the field name (now 2D: marker x species)
1313+
su2double**& value; // Now 2D: marker x species
1314+
unsigned short& nSpecies_per_Wall;
1315+
1316+
public:
1317+
COptionWallSpecies(string option_field_name, unsigned short& nMarker_Wall_Species, string*& Marker_Wall_Species,
1318+
WALL_SPECIES_TYPE**& option_field, const map<string, Tenum> m, su2double**& value,
1319+
unsigned short& nSpecies_per_Wall)
1320+
: size(nMarker_Wall_Species),
1321+
marker(Marker_Wall_Species),
1322+
field(option_field),
1323+
value(value),
1324+
nSpecies_per_Wall(nSpecies_per_Wall) {
1325+
this->name = option_field_name;
1326+
this->m = m;
1327+
}
1328+
~COptionWallSpecies() override {
1329+
if (marker) {
1330+
delete[] marker;
1331+
marker = nullptr;
1332+
}
1333+
if (field) {
1334+
for (unsigned short i = 0; i < size; i++) {
1335+
delete[] field[i];
1336+
}
1337+
delete[] field;
1338+
field = nullptr;
1339+
}
1340+
if (value) {
1341+
for (unsigned short i = 0; i < size; i++) {
1342+
delete[] value[i];
1343+
}
1344+
delete[] value;
1345+
value = nullptr;
1346+
}
1347+
}
1348+
1349+
string SetValue(const vector<string>& option_value) override {
1350+
COptionBase::SetValue(option_value);
1351+
unsigned short totalVals = option_value.size();
1352+
if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) {
1353+
this->size = 0;
1354+
this->marker = nullptr;
1355+
this->field = nullptr;
1356+
this->value = nullptr;
1357+
this->nSpecies_per_Wall = 0;
1358+
return "";
1359+
}
1360+
1361+
/*--- Determine the number of markers and species per marker.
1362+
* Format: marker1, TYPE1, value1, TYPE2, value2, ..., marker2, TYPE1, value1, ...
1363+
* Each marker name starts with a letter, each TYPE is an enum string (starts with letter),
1364+
* and each value is numeric. Pattern: marker, (TYPE, value) x N ---*/
1365+
1366+
vector<unsigned short> marker_indices; // Indices where markers start
1367+
vector<unsigned short> species_counts; // Number of species per marker
1368+
1369+
// Find all marker positions (strings starting with a letter that are not TYPE keywords)
1370+
for (unsigned short i = 0; i < totalVals; i++) {
1371+
if (isalpha(option_value[i][0])) {
1372+
// Check if this could be a TYPE keyword (i.e., is it in the enum map?)
1373+
if (this->m.find(option_value[i]) != m.end()) {
1374+
continue; // This is a TYPE keyword, not a marker
1375+
}
1376+
// This is a marker name
1377+
marker_indices.push_back(i);
1378+
}
1379+
}
1380+
1381+
if (marker_indices.empty()) {
1382+
string newstring;
1383+
newstring.append(this->name);
1384+
newstring.append(": no valid markers found");
1385+
return newstring;
1386+
}
1387+
1388+
// Calculate number of species for each marker
1389+
for (size_t i = 0; i < marker_indices.size(); i++) {
1390+
unsigned short start_idx = marker_indices[i] + 1; // Start after marker name
1391+
unsigned short end_idx = (i + 1 < marker_indices.size()) ? marker_indices[i + 1] : totalVals;
1392+
unsigned short entries = end_idx - start_idx;
1393+
1394+
// Each species needs 2 entries: TYPE and value
1395+
if (entries % 2 != 0) {
1396+
string newstring;
1397+
newstring.append(this->name);
1398+
newstring.append(": each marker must have pairs of (TYPE, value) entries");
1399+
return newstring;
1400+
}
1401+
1402+
species_counts.push_back(entries / 2);
1403+
}
1404+
1405+
// Check that all markers have the same number of species
1406+
this->nSpecies_per_Wall = species_counts[0];
1407+
for (auto count : species_counts) {
1408+
if (count != this->nSpecies_per_Wall) {
1409+
string newstring;
1410+
newstring.append(this->name);
1411+
newstring.append(": all markers must specify the same number of species");
1412+
return newstring;
1413+
}
1414+
}
1415+
1416+
// Allocate arrays
1417+
this->size = marker_indices.size();
1418+
this->marker = new string[this->size];
1419+
this->field = new WALL_SPECIES_TYPE*[this->size];
1420+
this->value = new su2double*[this->size];
1421+
1422+
for (unsigned short i = 0; i < this->size; i++) {
1423+
this->field[i] = new WALL_SPECIES_TYPE[this->nSpecies_per_Wall];
1424+
this->value[i] = new su2double[this->nSpecies_per_Wall];
1425+
}
1426+
1427+
// Parse the values
1428+
for (unsigned short iMarker = 0; iMarker < this->size; iMarker++) {
1429+
unsigned short marker_idx = marker_indices[iMarker];
1430+
this->marker[iMarker].assign(option_value[marker_idx]);
1431+
1432+
// Parse species data for this marker
1433+
for (unsigned short iSpecies = 0; iSpecies < this->nSpecies_per_Wall; iSpecies++) {
1434+
unsigned short type_idx = marker_idx + 1 + 2 * iSpecies;
1435+
unsigned short val_idx = type_idx + 1;
1436+
1437+
// Check TYPE keyword
1438+
if (this->m.find(option_value[type_idx]) == m.end()) {
1439+
string str;
1440+
str.append(this->name);
1441+
str.append(": invalid option value ");
1442+
str.append(option_value[type_idx]);
1443+
str.append(". Check current SU2 options in config_template.cfg.");
1444+
return str;
1445+
}
1446+
1447+
Tenum val = this->m[option_value[type_idx]];
1448+
this->field[iMarker][iSpecies] = val;
1449+
1450+
istringstream ss_value(option_value[val_idx]);
1451+
if (!(ss_value >> this->value[iMarker][iSpecies])) {
1452+
return badValue("WallSpecies", this->name);
1453+
}
1454+
}
1455+
}
1456+
1457+
return "";
1458+
}
1459+
1460+
void SetDefault() override {
1461+
this->marker = nullptr;
1462+
this->field = nullptr;
1463+
this->value = nullptr;
1464+
this->size = 0; // There is no default value for list
1465+
this->nSpecies_per_Wall = 0;
1466+
}
1467+
};
1468+
13051469
template <class Tenum>
13061470
class COptionGiles : public COptionBase {
13071471
map<string, Tenum> m;

Common/src/CConfig.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,16 @@ void CConfig::addRiemannOption(const string name, unsigned short & nMarker_Riema
513513
option_map.insert(pair<string, COptionBase *>(name, val));
514514
}
515515

516+
template <class Tenum>
517+
void CConfig::addWallSpeciesOption(const string name, unsigned short & nMarker_Wall_Species, string * & Marker_Wall_Species,
518+
WALL_SPECIES_TYPE** & option_field, const map<string, Tenum> & enum_map,
519+
su2double** & value, unsigned short & nSpecies_per_Wall) {
520+
assert(option_map.find(name) == option_map.end());
521+
all_options.insert(pair<string, bool>(name, true));
522+
COptionBase* val = new COptionWallSpecies<Tenum>(name, nMarker_Wall_Species, Marker_Wall_Species, option_field, enum_map, value, nSpecies_per_Wall);
523+
option_map.insert(pair<string, COptionBase *>(name, val));
524+
}
525+
516526
template <class Tenum>
517527
void CConfig::addGilesOption(const string name, unsigned short & nMarker_Giles, string * & Marker_Giles, unsigned short* & option_field, const map<string, Tenum> & enum_map,
518528
su2double* & var1, su2double* & var2, su2double** & FlowDir, su2double* & relaxfactor1, su2double* & relaxfactor2) {
@@ -1621,6 +1631,11 @@ void CConfig::SetConfig_Options() {
16211631
/*!\brief MARKER_RIEMANN \n DESCRIPTION: Riemann boundary marker(s) with the following formats, a unit vector.
16221632
* \n OPTIONS: See \link Riemann_Map \endlink. The variables indicated by the option and the flow direction unit vector must be specified. \ingroup Config*/
16231633
addRiemannOption("MARKER_RIEMANN", nMarker_Riemann, Marker_Riemann, Kind_Data_Riemann, Riemann_Map, Riemann_Var1, Riemann_Var2, Riemann_FlowDir);
1634+
/*!\brief MARKER_WALL_SPECIES \n DESCRIPTION: Wall species boundary marker(s) with the following format:
1635+
* (marker_name, BC_TYPE, value, BC_TYPE, value, ...) where BC_TYPE is either FLUX (Neumann) or VALUE (Dirichlet).
1636+
* Each marker must specify the same number of species (N species per marker).
1637+
* \n OPTIONS: See \link Wall_Map \endlink. \ingroup Config*/
1638+
addWallSpeciesOption("MARKER_WALL_SPECIES", nMarker_Wall_Species, Marker_Wall_Species, Kind_Wall_Species, Wall_Map, Wall_SpeciesVal, nSpecies_per_Wall);
16241639
/*!\brief MARKER_GILES \n DESCRIPTION: Giles boundary marker(s) with the following formats, a unit vector. */
16251640
/* \n OPTIONS: See \link Giles_Map \endlink. The variables indicated by the option and the flow direction unit vector must be specified. \ingroup Config*/
16261641
addGilesOption("MARKER_GILES", nMarker_Giles, Marker_Giles, Kind_Data_Giles, Giles_Map, Giles_Var1, Giles_Var2, Giles_FlowDir, RelaxFactorAverage, RelaxFactorFourier);
@@ -5702,7 +5717,7 @@ void CConfig::SetPostprocessing(SU2_COMPONENT val_software, unsigned short val_i
57025717
/*--- Helper function that checks scalar variable bounds. ---*/
57035718
auto checkScalarBounds = [&](su2double scalar, const string& name, su2double lowerBound, su2double upperBound) {
57045719
if (scalar < lowerBound || scalar > upperBound)
5705-
SU2_MPI::Error(string("Variable: ") + name + string(", is out of bounds."), CURRENT_FUNCTION);
5720+
cout << "Value: " << scalar << " for " << name << " is out of bounds [" << lowerBound << "," << upperBound << "]." << endl;
57065721
};
57075722

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

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

9270+
su2double CConfig::GetWall_SpeciesVal(const string& val_marker, unsigned short iSpecies) const {
9271+
/*--- Search for the marker in the wall species list ---*/
9272+
for (unsigned short iMarker_Wall_Species = 0; iMarker_Wall_Species < nMarker_Wall_Species; iMarker_Wall_Species++) {
9273+
if (Marker_Wall_Species[iMarker_Wall_Species] == val_marker) {
9274+
return Wall_SpeciesVal[iMarker_Wall_Species][iSpecies];
9275+
}
9276+
}
9277+
/*--- If marker not found (MARKER_WALL_SPECIES=NONE), return zero flux ---*/
9278+
return 0.0;
9279+
}
9280+
9281+
WALL_SPECIES_TYPE CConfig::GetWall_SpeciesType(const string& val_marker, unsigned short iSpecies) const {
9282+
/*--- Search for the marker in the wall species list ---*/
9283+
for (unsigned short iMarker_Wall_Species = 0; iMarker_Wall_Species < nMarker_Wall_Species; iMarker_Wall_Species++) {
9284+
if (Marker_Wall_Species[iMarker_Wall_Species] == val_marker) {
9285+
return Kind_Wall_Species[iMarker_Wall_Species][iSpecies];
9286+
}
9287+
}
9288+
/*--- If marker not found (MARKER_WALL_SPECIES=NONE), return FLUX type (zero flux BC) ---*/
9289+
return WALL_SPECIES_TYPE::FLUX;
9290+
}
9291+
92539292
const su2double* CConfig::GetInlet_TurbVal(const string& val_marker) const {
92549293
/*--- If Turbulent Inlet is not provided for the marker, return free stream values. ---*/
92559294
for (auto iMarker = 0u; iMarker < nMarker_Inlet_Turb; iMarker++) {

SU2_CFD/include/drivers/CDriverBase.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,18 @@ class CDriverBase {
566566
main_geometry->SetCustomBoundaryHeatFlux(iMarker, iVertex, WallHeatFlux);
567567
}
568568

569+
/*!
570+
* \brief Set the wall normal scalar values at a vertex on a specified marker (MARKER_PYTHON_CUSTOM).
571+
* \note This can be the input of a scalar transport equation.
572+
* \param[in] iMarker - Marker identifier.
573+
* \param[in] iVertex - Vertex identifier.
574+
* \param[in] WallScalar - Value of the normal heat flux.
575+
*/
576+
inline void SetMarkerCustomScalar(unsigned short iMarker, unsigned long iVertex, vector<passivedouble> WallScalar) {
577+
auto* solver = solver_container[selected_zone][INST_0][MESH_0][SPECIES_SOL];
578+
solver->SetCustomBoundaryScalar(iMarker, iVertex, WallScalar);
579+
}
580+
569581
/*!
570582
* \brief Selects zone to be used for python driver operations.
571583
* \param[in] iZone - Zone identifier.

SU2_CFD/include/solvers/CSolver.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2856,6 +2856,16 @@ class CSolver {
28562856
unsigned long val_vertex,
28572857
unsigned short val_dim) const { return 0; }
28582858

2859+
2860+
/*!
2861+
* \brief Set the value of the customized normal scalar values/flux at a specified vertex on a specified marker.
2862+
* \param[in] val_marker - Marker value
2863+
* \param[in] val_vertex - Boundary vertex value
2864+
*/
2865+
inline virtual void SetCustomBoundaryScalar(unsigned short val_marker, unsigned long val_vertex,
2866+
vector<passivedouble> val_customBoundaryScalar) { }
2867+
2868+
28592869
/*!
28602870
* \brief A virtual member
28612871
* \param[in] val_marker - Surface marker where the total temperature is set.

0 commit comments

Comments
 (0)