Skip to content

Commit 77fed34

Browse files
Correction of symmetry plane implementation (#2194)
* Correct symmetry plane and Euler wall * Correct gradients for symmetry plane and Euler wall --------- Co-authored-by: Pedro Gomes <[email protected]> Co-authored-by: Pedro Gomes <[email protected]>
1 parent 1044ccc commit 77fed34

File tree

72 files changed

+1560
-1431
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+1560
-1431
lines changed

Common/include/geometry/CGeometry.hpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,10 @@ class CGeometry {
240240
unsigned long* nVertex{nullptr}; /*!< \brief Number of vertex for each marker. */
241241
unsigned long* nElem_Bound{nullptr}; /*!< \brief Number of elements of the boundary. */
242242
string* Tag_to_Marker{nullptr}; /*!< \brief Names of boundary markers. */
243-
vector<bool>
244-
bound_is_straight; /*!< \brief Bool if boundary-marker is straight(2D)/plane(3D) for each local marker. */
243+
244+
/*!< \brief Corrected normals on nodes with shared symmetry markers. */
245+
vector<std::unordered_map<unsigned long, std::array<su2double, MAXNDIM>>> symmetryNormals;
246+
245247
vector<su2double> SurfaceAreaCfgFile; /*!< \brief Total Surface area for all markers. */
246248

247249
/*--- Partitioning-specific variables ---*/
@@ -819,6 +821,12 @@ class CGeometry {
819821
*/
820822
inline virtual void SetBoundControlVolume(const CConfig* config, unsigned short action) {}
821823

824+
/*!
825+
* \brief Computes modified normals at intersecting symmetry planes.
826+
* \param[in] config - Definition of the particular problem.
827+
*/
828+
void ComputeModifiedSymmetryNormals(const CConfig* config);
829+
822830
/*!
823831
* \brief A virtual member.
824832
* \param[in] config_filename - Name of the file where the tecplot information is going to be stored.
@@ -936,9 +944,10 @@ class CGeometry {
936944
/*!
937945
* \brief A virtual member.
938946
* \param[in] fine_grid - Geometrical definition of the problem.
947+
* \param[in] config - Definition of the particular problem.
939948
* \param[in] action - Allocate or not the new elements.
940949
*/
941-
inline virtual void SetBoundControlVolume(const CGeometry* fine_grid, unsigned short action) {}
950+
inline virtual void SetBoundControlVolume(const CGeometry* fine_grid, const CConfig* config, unsigned short action) {}
942951

943952
/*!
944953
* \brief A virtual member.
@@ -1005,15 +1014,6 @@ class CGeometry {
10051014
*/
10061015
su2double GetSurfaceArea(const CConfig* config, unsigned short val_marker) const;
10071016

1008-
/*!
1009-
* \brief Check if a boundary is straight(2D) / plane(3D) for EULER_WALL and SYMMETRY_PLANE
1010-
* only and store the information in bound_is_straight. For all other boundary types
1011-
* this will return false and could therfore be wrong. Used ultimately for BC_Slip_Wall.
1012-
* \param[in] config - Definition of the particular problem.
1013-
* \param[in] print_on_screen - Boolean whether to print result on screen.
1014-
*/
1015-
void ComputeSurf_Straightness(CConfig* config, bool print_on_screen);
1016-
10171017
/*!
10181018
* \brief Find and store all vertices on a sharp corner in the geometry.
10191019
* \param[in] config - Definition of the particular problem.

Common/include/geometry/CMultiGridGeometry.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,10 @@ class CMultiGridGeometry final : public CGeometry {
104104
/*!
105105
* \brief Set boundary vertex structure of the agglomerated control volume.
106106
* \param[in] fine_grid - Geometrical definition of the problem.
107+
* \param[in] config - Definition of the particular problem.
107108
* \param[in] action - Allocate or not the new elements.
108109
*/
109-
void SetBoundControlVolume(const CGeometry* fine_grid, unsigned short action) override;
110+
void SetBoundControlVolume(const CGeometry* fine_grid, const CConfig* config, unsigned short action) override;
110111

111112
/*!
112113
* \brief Set a representative coordinates of the agglomerated control volume.

Common/include/geometry/CPhysicalGeometry.hpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,10 +208,13 @@ class CPhysicalGeometry final : public CGeometry {
208208
* \brief Routine to launch non-blocking sends and recvs amongst all processors.
209209
* \param[in] bufSend - Buffer of data to be sent.
210210
* \param[in] nElemSend - Array containing the number of elements to send to other processors in cumulative storage
211-
* format. \param[in] sendReq - Array of MPI send requests. \param[in] bufRecv - Buffer of data to be received.
211+
* format.
212+
* \param[in] sendReq - Array of MPI send requests.
213+
* \param[in] bufRecv - Buffer of data to be received.
212214
* \param[in] nElemSend - Array containing the number of elements to receive from other processors in cumulative
213-
* storage format. \param[in] sendReq - Array of MPI recv requests. \param[in] countPerElem - Pieces of data per
214-
* element communicated.
215+
* storage format.
216+
* \param[in] sendReq - Array of MPI recv requests.
217+
* \param[in] countPerElem - Pieces of data per element communicated.
215218
*/
216219
void InitiateCommsAll(void* bufSend, const int* nElemSend, SU2_MPI::Request* sendReq, void* bufRecv,
217220
const int* nElemRecv, SU2_MPI::Request* recvReq, unsigned short countPerElem,

Common/include/geometry/dual_grid/CPoint.hpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -314,10 +314,8 @@ class CPoint {
314314
* \return Index of the vertex.
315315
*/
316316
inline long GetVertex(unsigned long iPoint, unsigned long iMarker) const {
317-
if (Boundary(iPoint))
318-
return Vertex[iPoint][iMarker];
319-
else
320-
return -1;
317+
if (Boundary(iPoint)) return Vertex[iPoint][iMarker];
318+
return -1;
321319
}
322320

323321
/*!
@@ -369,7 +367,7 @@ class CPoint {
369367
inline bool GetPhysicalBoundary(unsigned long iPoint) const { return PhysicalBoundary(iPoint); }
370368

371369
/*!
372-
* \brief Set if a point belong to the boundary.
370+
* \brief Set if a point belong to the solid wall boundary.
373371
* \param[in] iPoint - Index of the point.
374372
* \param[in] boundary - <code>TRUE</code> if the point belong to the physical boundary; otherwise <code>FALSE</code>.
375373
*/

Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,13 @@ class CCGNSMeshReaderFVM : public CMeshReaderFVM {
121121
* \brief Routine to launch non-blocking sends and recvs amongst all processors.
122122
* \param[in] bufSend - Buffer of data to be sent.
123123
* \param[in] nElemSend - Array containing the number of elements to send to other processors in cumulative storage
124-
* format. \param[in] sendReq - Array of MPI send requests. \param[in] bufRecv - Buffer of data to be received.
124+
* format.
125+
* \param[in] sendReq - Array of MPI send requests.
126+
* \param[in] bufRecv - Buffer of data to be received.
125127
* \param[in] nElemSend - Array containing the number of elements to receive from other processors in cumulative
126-
* storage format. \param[in] sendReq - Array of MPI recv requests. \param[in] countPerElem - Pieces of data per
127-
* element communicated.
128+
* storage format.
129+
* \param[in] sendReq - Array of MPI recv requests.
130+
* \param[in] countPerElem - Pieces of data per element communicated.
128131
*/
129132
void InitiateCommsAll(void* bufSend, const int* nElemSend, SU2_MPI::Request* sendReq, void* bufRecv,
130133
const int* nElemRecv, SU2_MPI::Request* recvReq, unsigned short countPerElem,

Common/src/geometry/CGeometry.cpp

Lines changed: 65 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -2338,7 +2338,7 @@ void CGeometry::UpdateGeometry(CGeometry** geometry_container, CConfig* config)
23382338
/*--- Update the control volume structures ---*/
23392339

23402340
geometry_container[iMesh]->SetControlVolume(geometry_container[iMesh - 1], UPDATE);
2341-
geometry_container[iMesh]->SetBoundControlVolume(geometry_container[iMesh - 1], UPDATE);
2341+
geometry_container[iMesh]->SetBoundControlVolume(geometry_container[iMesh - 1], config, UPDATE);
23422342
geometry_container[iMesh]->SetCoord(geometry_container[iMesh - 1]);
23432343
}
23442344

@@ -2453,123 +2453,71 @@ su2double CGeometry::GetSurfaceArea(const CConfig* config, unsigned short val_ma
24532453
return 0.0;
24542454
}
24552455

2456-
void CGeometry::ComputeSurf_Straightness(CConfig* config, bool print_on_screen) {
2457-
bool RefUnitNormal_defined;
2458-
unsigned short iDim, iMarker, iMarker_Global, nMarker_Global = config->GetnMarker_CfgFile();
2459-
unsigned long iVertex;
2460-
constexpr passivedouble epsilon = 1.0e-6;
2461-
su2double Area;
2462-
string Local_TagBound, Global_TagBound;
2463-
2464-
vector<su2double> Normal(nDim), UnitNormal(nDim), RefUnitNormal(nDim);
2465-
2466-
/*--- Assume now that this boundary marker is straight. As soon as one
2467-
AreaElement is found that is not aligend with a Reference then it is
2468-
certain that the boundary marker is not straight and one can stop
2469-
searching. Another possibility is that this process doesn't own
2470-
any nodes of that boundary, in that case we also have to assume the
2471-
boundary is straight.
2472-
Any boundary type other than SYMMETRY_PLANE or EULER_WALL gets
2473-
the value false (or see cases specified in the conditional below)
2474-
which could be wrong. ---*/
2475-
bound_is_straight.resize(nMarker);
2476-
fill(bound_is_straight.begin(), bound_is_straight.end(), true);
2477-
2478-
/*--- Loop over all local markers ---*/
2479-
for (iMarker = 0; iMarker < nMarker; iMarker++) {
2480-
Local_TagBound = config->GetMarker_All_TagBound(iMarker);
2481-
2482-
/*--- Marker has to be Symmetry or Euler. Additionally marker can't be a
2483-
moving surface and Grid Movement Elasticity is forbidden as well. All
2484-
other GridMovements are rigid. ---*/
2485-
if ((config->GetMarker_All_KindBC(iMarker) == SYMMETRY_PLANE ||
2486-
config->GetMarker_All_KindBC(iMarker) == EULER_WALL) &&
2487-
!config->GetMarker_Moving_Bool(Local_TagBound) && !config->GetMarker_Deform_Mesh_Bool(Local_TagBound)) {
2488-
/*--- Loop over all global markers, and find the local-global pair via
2489-
matching unique string tags. ---*/
2490-
for (iMarker_Global = 0; iMarker_Global < nMarker_Global; iMarker_Global++) {
2491-
Global_TagBound = config->GetMarker_CfgFile_TagBound(iMarker_Global);
2492-
if (Local_TagBound == Global_TagBound) {
2493-
RefUnitNormal_defined = false;
2494-
iVertex = 0;
2495-
2496-
while (bound_is_straight[iMarker] && iVertex < nVertex[iMarker]) {
2497-
vertex[iMarker][iVertex]->GetNormal(Normal.data());
2498-
UnitNormal = Normal;
2499-
2500-
/*--- Compute unit normal. ---*/
2501-
Area = 0.0;
2502-
for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim] * Normal[iDim];
2503-
Area = sqrt(Area);
2504-
2505-
/*--- Negate for outward convention. ---*/
2506-
for (iDim = 0; iDim < nDim; iDim++) UnitNormal[iDim] /= -Area;
2507-
2508-
/*--- Check if unit normal is within tolerance of the Reference unit normal.
2509-
Reference unit normal = first unit normal found. ---*/
2510-
if (RefUnitNormal_defined) {
2511-
for (iDim = 0; iDim < nDim; iDim++) {
2512-
if (abs(RefUnitNormal[iDim] - UnitNormal[iDim]) > epsilon) {
2513-
bound_is_straight[iMarker] = false;
2514-
break;
2515-
}
2516-
}
2517-
} else {
2518-
RefUnitNormal = UnitNormal; // deep copy of values
2519-
RefUnitNormal_defined = true;
2520-
}
2456+
void CGeometry::ComputeModifiedSymmetryNormals(const CConfig* config) {
2457+
/* Check how many symmetry planes there are and use the first (lowest ID) as the basis to orthogonalize against.
2458+
* All nodes that are shared by multiple symmetries have to get a corrected normal. */
2459+
symmetryNormals.resize(nMarker);
2460+
std::vector<unsigned short> symMarkers;
25212461

2522-
iVertex++;
2523-
} // while iVertex
2524-
} // if Local == Global
2525-
} // for iMarker_Global
2526-
} else {
2527-
/*--- Enforce default value: false ---*/
2528-
bound_is_straight[iMarker] = false;
2529-
} // if sym or euler ...
2530-
} // for iMarker
2531-
2532-
/*--- Communicate results and print on screen. ---*/
2533-
if (print_on_screen) {
2534-
/*--- Additional vector which can later be MPI::Allreduce(d) to pring the results
2535-
on screen as nMarker (local) can vary across ranks. Default 'true' as it can
2536-
happen that a local rank does not contain an element of each surface marker. ---*/
2537-
vector<bool> bound_is_straight_Global(nMarker_Global, true);
2538-
/*--- Match local with global tag bound and fill a Global Marker vector. ---*/
2539-
for (iMarker = 0; iMarker < nMarker; iMarker++) {
2540-
Local_TagBound = config->GetMarker_All_TagBound(iMarker);
2541-
for (iMarker_Global = 0; iMarker_Global < nMarker_Global; iMarker_Global++) {
2542-
Global_TagBound = config->GetMarker_CfgFile_TagBound(iMarker_Global);
2543-
2544-
if (Local_TagBound == Global_TagBound) bound_is_straight_Global[iMarker_Global] = bound_is_straight[iMarker];
2545-
2546-
} // for iMarker_Global
2547-
} // for iMarker
2548-
2549-
vector<int> Buff_Send_isStraight(nMarker_Global), Buff_Recv_isStraight(nMarker_Global);
2550-
2551-
/*--- Cast to int as std::vector<boolean> can be a special construct. MPI handling using <int>
2552-
is more straight-forward. ---*/
2553-
for (iMarker_Global = 0; iMarker_Global < nMarker_Global; iMarker_Global++)
2554-
Buff_Send_isStraight[iMarker_Global] = static_cast<int>(bound_is_straight_Global[iMarker_Global]);
2555-
2556-
/*--- Product of type <int>(bool) is equivalnt to a 'logical and' ---*/
2557-
SU2_MPI::Allreduce(Buff_Send_isStraight.data(), Buff_Recv_isStraight.data(), nMarker_Global, MPI_INT, MPI_PROD,
2558-
SU2_MPI::GetComm());
2559-
2560-
/*--- Print results on screen. ---*/
2561-
if (rank == MASTER_NODE) {
2562-
for (iMarker_Global = 0; iMarker_Global < nMarker_Global; iMarker_Global++) {
2563-
if (config->GetMarker_CfgFile_KindBC(config->GetMarker_CfgFile_TagBound(iMarker_Global)) == SYMMETRY_PLANE ||
2564-
config->GetMarker_CfgFile_KindBC(config->GetMarker_CfgFile_TagBound(iMarker_Global)) == EULER_WALL) {
2565-
cout << "Boundary marker " << config->GetMarker_CfgFile_TagBound(iMarker_Global) << " is";
2566-
if (!static_cast<bool>(Buff_Recv_isStraight[iMarker_Global])) cout << " NOT";
2567-
if (nDim == 2) cout << " a single straight." << endl;
2568-
if (nDim == 3) cout << " a single plane." << endl;
2569-
} // if sym or euler
2570-
} // for iMarker_Global
2571-
} // if rank==MASTER
2572-
} // if print_on_scren
2462+
for (auto iMarker = 0u; iMarker < nMarker; ++iMarker) {
2463+
if ((config->GetMarker_All_KindBC(iMarker) == SYMMETRY_PLANE) ||
2464+
(config->GetMarker_All_KindBC(iMarker) == EULER_WALL)) {
2465+
symMarkers.push_back(iMarker);
2466+
}
2467+
}
2468+
2469+
/*--- Loop over all markers and find nodes on symmetry planes that are shared with other symmetries. ---*/
2470+
/*--- The first symmetry does not need a corrected normal vector, hence start at 1. ---*/
2471+
for (size_t i = 1; i < symMarkers.size(); ++i) {
2472+
const auto iMarker = symMarkers[i];
2473+
2474+
for (auto iVertex = 0ul; iVertex < nVertex[iMarker]; iVertex++) {
2475+
const auto iPoint = vertex[iMarker][iVertex]->GetNode();
2476+
2477+
/*--- Halo points do not need to be considered. ---*/
2478+
if (!nodes->GetDomain(iPoint)) continue;
2479+
2480+
/*--- Get the vertex normal on the current symmetry. ---*/
2481+
std::array<su2double, MAXNDIM> iNormal = {};
2482+
vertex[iMarker][iVertex]->GetNormal(iNormal.data());
2483+
2484+
/*--- Loop over previous symmetries and if this point shares them, make this normal orthogonal to them. ---*/
2485+
bool isShared = false;
2486+
2487+
for (size_t j = 0; j < i; ++j) {
2488+
const auto jMarker = symMarkers[j];
2489+
const auto jVertex = nodes->GetVertex(iPoint, jMarker);
2490+
if (jVertex < 0) continue;
2491+
2492+
isShared = true;
2493+
2494+
std::array<su2double, MAXNDIM> jNormal = {};
2495+
const auto it = symmetryNormals[jMarker].find(jVertex);
2496+
2497+
if (it != symmetryNormals[jMarker].end()) {
2498+
jNormal = it->second;
2499+
} else {
2500+
vertex[jMarker][jVertex]->GetNormal(jNormal.data());
2501+
const su2double area = GeometryToolbox::Norm(nDim, jNormal.data());
2502+
for (auto iDim = 0u; iDim < nDim; iDim++) jNormal[iDim] /= area;
2503+
}
2504+
2505+
const auto proj = GeometryToolbox::DotProduct(nDim, jNormal.data(), iNormal.data());
2506+
for (auto iDim = 0u; iDim < nDim; iDim++) iNormal[iDim] -= proj * jNormal[iDim];
2507+
}
2508+
2509+
if (!isShared) continue;
2510+
2511+
/*--- Normalize. If the norm is close to zero it means the normal is a linear combination of previous
2512+
* normals, in this case we don't need to store the corrected normal, using the original in the gradient
2513+
* correction will have no effect since previous corrections will remove components in this direction). ---*/
2514+
const su2double area = GeometryToolbox::Norm(nDim, iNormal.data());
2515+
if (area > EPS) {
2516+
for (auto iDim = 0u; iDim < nDim; iDim++) iNormal[iDim] /= area;
2517+
symmetryNormals[iMarker][iVertex] = iNormal;
2518+
}
2519+
}
2520+
}
25732521
}
25742522

25752523
void CGeometry::ComputeSurf_Curvature(CConfig* config) {

0 commit comments

Comments
 (0)