@@ -2468,6 +2468,9 @@ su2double CGeometry::GetSurfaceArea(const CConfig* config, unsigned short val_ma
24682468}
24692469
24702470void CGeometry::ComputeModifiedSymmetryNormals (const CConfig* config) {
2471+ const su2double MIN_AREA = 1e-12 ; // minimum area to consider a normal valid
2472+ const su2double PARALLEL_TOLERANCE = 0.001 ; // min. angle between symm. planes to consider them non-parallel.
2473+
24712474 /* Check how many symmetry planes there are and use the first (lowest ID) as the basis to orthogonalize against.
24722475 * All nodes that are shared by multiple symmetries have to get a corrected normal. */
24732476
@@ -2558,6 +2561,8 @@ void CGeometry::ComputeModifiedSymmetryNormals(const CConfig* config) {
25582561 /* --- Loop over previous symmetries and if this point shares them, make this normal orthogonal to them.
25592562 * It's ok if we normalize merged normals against themselves, we get 0 area and this becomes a no-op. ---*/
25602563
2564+ std::vector<size_t > parallelMarkers; // Track markers with nearly-parallel normals
2565+
25612566 for (size_t j = 0 ; j < i; ++j) {
25622567 const auto jMarker = symMarkers[j];
25632568 const auto jVertex = nodes->GetVertex (iPoint, jMarker);
@@ -2567,14 +2572,48 @@ void CGeometry::ComputeModifiedSymmetryNormals(const CConfig* config) {
25672572 GetNormal (jMarker, jVertex, jNormal);
25682573
25692574 const su2double proj = GeometryToolbox::DotProduct (int (MAXNDIM), jNormal.data (), iNormal.data ());
2575+ const su2double angleDiff = std::abs (1.0 - std::abs (proj));
2576+
2577+ // Check if normals are nearly parallel (within ~2.5 degrees)
2578+ // cos(2.5°) ≈ 0.999, so (1 - cos(2.5°)) ≈ 0.001
2579+ if (angleDiff < PARALLEL_TOLERANCE) {
2580+ // These normals are nearly parallel - average them instead of orthogonalizing
2581+ parallelMarkers.push_back (j);
2582+ for (auto iDim = 0ul ; iDim < MAXNDIM; ++iDim) iNormal[iDim] += jNormal[iDim];
2583+ continue ;
2584+ }
2585+
25702586 for (auto iDim = 0ul ; iDim < MAXNDIM; ++iDim) iNormal[iDim] -= proj * jNormal[iDim];
25712587 }
25722588
2589+ /* --- If we found parallel markers, average and store the result for all involved markers ---*/
2590+ if (!parallelMarkers.empty ()) {
2591+ // Normalize the averaged normal
2592+ const su2double avgArea = GeometryToolbox::Norm (int (MAXNDIM), iNormal.data ());
2593+ if (avgArea > MIN_AREA) {
2594+ for (auto iDim = 0ul ; iDim < MAXNDIM; ++iDim) iNormal[iDim] /= avgArea;
2595+
2596+ // Store the averaged normal for the current marker
2597+ symmetryNormals[iMarker][iVertex] = iNormal;
2598+
2599+ // Also update all parallel markers with the same averaged normal
2600+ for (const auto j : parallelMarkers) {
2601+ const auto jMarker = symMarkers[j];
2602+ const auto jVertex = nodes->GetVertex (iPoint, jMarker);
2603+ if (jVertex >= 0 ) {
2604+ symmetryNormals[jMarker][jVertex] = iNormal;
2605+ }
2606+ }
2607+ }
2608+ continue ; // Skip the normal orthogonalization path below
2609+ }
2610+
25732611 /* --- Normalize. If the norm is close to zero it means the normal is a linear combination of previous
25742612 * normals, in this case we don't need to store the corrected normal, using the original in the gradient
25752613 * correction will have no effect since previous corrections will remove components in this direction). ---*/
25762614 const su2double area = GeometryToolbox::Norm (int (MAXNDIM), iNormal.data ());
2577- if (area > 1e-12 ) {
2615+
2616+ if (area > MIN_AREA) {
25782617 for (auto iDim = 0ul ; iDim < MAXNDIM; ++iDim) iNormal[iDim] /= area;
25792618 symmetryNormals[iMarker][iVertex] = iNormal;
25802619 }
@@ -2591,16 +2630,14 @@ void CGeometry::ComputeSurfStraightness(const CConfig* config, bool print_on_scr
25912630 string Local_TagBound, Global_TagBound;
25922631
25932632 vector<su2double> Normal (nDim), UnitNormal (nDim), RefUnitNormal (nDim);
2594-
25952633 /* --- Assume now that this boundary marker is straight. As soon as one
2596- AreaElement is found that is not aligend with a Reference then it is
2597- certain that the boundary marker is not straight and one can stop
2598- searching. Another possibility is that this process doesn't own
2634+ AreaElement is found that is not aligned with a Reference then it
2635+ is certain that the boundary marker is not straight and one can
2636+ stop searching. Another possibility is that this process doesn't own
25992637 any nodes of that boundary, in that case we also have to assume the
2600- boundary is straight.
2601- Any boundary type other than SYMMETRY_PLANE or EULER_WALL gets
2602- the value false (or see cases specified in the conditional below)
2603- which could be wrong. ---*/
2638+ boundary is straight. Any boundary type other than SYMMETRY_PLANE or
2639+ EULER_WALL gets the value false (or see cases specified in the
2640+ conditional below) which could be wrong. ---*/
26042641 boundIsStraight.resize (nMarker);
26052642 fill (boundIsStraight.begin (), boundIsStraight.end (), true );
26062643
@@ -3902,11 +3939,13 @@ void CGeometry::ColorMGLevels(unsigned short nMGLevels, const CGeometry* const*
39023939 for (auto step = 0u ; step < iMesh; ++step) {
39033940 auto coarseMesh = geometry[iMesh - 1 - step];
39043941 if (step)
3905- for (auto iPoint = 0ul ; iPoint < coarseMesh->GetnPoint (); ++iPoint)
3942+ for (auto iPoint = 0ul ; iPoint < coarseMesh->GetnPoint (); ++iPoint) {
39063943 CoarseGridColor_ (iPoint, step) = CoarseGridColor_ (coarseMesh->nodes ->GetParent_CV (iPoint), step - 1 );
3944+ }
39073945 else
3908- for (auto iPoint = 0ul ; iPoint < coarseMesh->GetnPoint (); ++iPoint)
3946+ for (auto iPoint = 0ul ; iPoint < coarseMesh->GetnPoint (); ++iPoint) {
39093947 CoarseGridColor_ (iPoint, step) = color[coarseMesh->nodes ->GetParent_CV (iPoint)];
3948+ }
39103949 }
39113950 }
39123951}
0 commit comments