Skip to content

Commit 99e6e54

Browse files
authored
Merge pull request #2406 from su2code/better_fea_symmetry
Remove axis-perpendicular restriction on FEA symmetry planes
2 parents e2ee3e7 + 64d8ff6 commit 99e6e54

File tree

4 files changed

+78
-39
lines changed

4 files changed

+78
-39
lines changed

Common/include/linear_algebra/CSysMatrix.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -805,10 +805,10 @@ class CSysMatrix {
805805
void EnforceSolutionAtNode(unsigned long node_i, const OtherType* x_i, CSysVector<OtherType>& b);
806806

807807
/*!
808-
* \brief Version of EnforceSolutionAtNode for a single degree of freedom.
808+
* \brief Similar to EnforceSolutionAtNode, but for 0 projection in a given direction.
809809
*/
810810
template <class OtherType>
811-
void EnforceSolutionAtDOF(unsigned long node_i, unsigned long iVar, OtherType x_i, CSysVector<OtherType>& b);
811+
void EnforceZeroProjection(unsigned long node_i, const OtherType* n, CSysVector<OtherType>& b);
812812

813813
/*!
814814
* \brief Sets the diagonal entries of the matrix as the sum of the blocks in the corresponding column.

Common/src/linear_algebra/CSysMatrix.cpp

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,36 +1027,59 @@ void CSysMatrix<ScalarType>::EnforceSolutionAtNode(const unsigned long node_i, c
10271027

10281028
template <class ScalarType>
10291029
template <class OtherType>
1030-
void CSysMatrix<ScalarType>::EnforceSolutionAtDOF(unsigned long node_i, unsigned long iVar, OtherType x_i,
1031-
CSysVector<OtherType>& b) {
1030+
void CSysMatrix<ScalarType>::EnforceZeroProjection(unsigned long node_i, const OtherType* n, CSysVector<OtherType>& b) {
10321031
for (auto index = row_ptr[node_i]; index < row_ptr[node_i + 1]; ++index) {
10331032
const auto node_j = col_ind[index];
10341033

1035-
/*--- Delete row iVar of block j on row i (bij) and ATTEMPT
1036-
* to delete column iVar block i on row j (bji). ---*/
1034+
/*--- Remove product components of block j on row i (bij) and ATTEMPT
1035+
* to remove solution components of block i on row j (bji).
1036+
* This is identical to symmetry correction applied to gradients
1037+
* but extended to the entire matrix. ---*/
10371038

10381039
auto bij = &matrix[index * nVar * nVar];
10391040
auto bji = GetBlock(node_j, node_i);
10401041

1041-
/*--- The "attempt" part. ---*/
1042+
/*--- Attempt to remove solution components. ---*/
1043+
ScalarType nbn{};
10421044
if (bji != nullptr) {
1043-
for (auto jVar = 0ul; jVar < nVar; ++jVar) {
1044-
/*--- Column product. ---*/
1045-
b[node_j * nVar + jVar] -= bji[jVar * nVar + iVar] * x_i;
1046-
/*--- Delete entries. ---*/
1047-
bji[jVar * nVar + iVar] = 0.0;
1045+
for (auto iVar = 0ul; iVar < nVar; ++iVar) {
1046+
ScalarType proj{};
1047+
for (auto jVar = 0ul; jVar < nVar; ++jVar) {
1048+
proj += bji[iVar * nVar + jVar] * PassiveAssign(n[jVar]);
1049+
}
1050+
for (auto jVar = 0ul; jVar < nVar; ++jVar) {
1051+
bji[iVar * nVar + jVar] -= proj * PassiveAssign(n[jVar]);
1052+
}
1053+
nbn += proj * PassiveAssign(n[iVar]);
10481054
}
10491055
}
10501056

1051-
/*--- Delete row. ---*/
1052-
for (auto jVar = 0ul; jVar < nVar; ++jVar) bij[iVar * nVar + jVar] = 0.0;
1057+
/*--- Product components. ---*/
1058+
for (auto jVar = 0ul; jVar < nVar; ++jVar) {
1059+
ScalarType proj{};
1060+
for (auto iVar = 0ul; iVar < nVar; ++iVar) {
1061+
proj += bij[iVar * nVar + jVar] * PassiveAssign(n[iVar]);
1062+
}
1063+
for (auto iVar = 0ul; iVar < nVar; ++iVar) {
1064+
bij[iVar * nVar + jVar] -= proj * PassiveAssign(n[iVar]);
1065+
}
1066+
}
10531067

1054-
/*--- Set the diagonal entry of the block to 1. ---*/
1055-
if (node_j == node_i) bij[iVar * (nVar + 1)] = 1.0;
1068+
/*--- This part doesn't have the "*2" factor because the product components
1069+
* were removed from the result of removing the solution components
1070+
* instead of from the original block (bji == bij). ---*/
1071+
if (node_i == node_j) {
1072+
for (auto iVar = 0ul; iVar < nVar; ++iVar) {
1073+
for (auto jVar = 0ul; jVar < nVar; ++jVar) {
1074+
bij[iVar * nVar + jVar] += PassiveAssign(n[iVar]) * nbn * PassiveAssign(n[jVar]);
1075+
}
1076+
}
1077+
}
10561078
}
10571079

1058-
/*--- Set known solution in rhs vector. ---*/
1059-
b(node_i, iVar) = x_i;
1080+
OtherType proj{};
1081+
for (auto iVar = 0ul; iVar < nVar; ++iVar) proj += b(node_i, iVar) * n[iVar];
1082+
for (auto iVar = 0ul; iVar < nVar; ++iVar) b(node_i, iVar) -= proj * n[iVar];
10601083
}
10611084

10621085
template <class ScalarType>
@@ -1203,8 +1226,7 @@ void CSysMatrix<ScalarType>::ComputePastixPreconditioner(const CSysVector<Scalar
12031226
#define INSTANTIATE_MATRIX(TYPE) \
12041227
template class CSysMatrix<TYPE>; \
12051228
template void CSysMatrix<TYPE>::EnforceSolutionAtNode(unsigned long, const su2double*, CSysVector<su2double>&); \
1206-
template void CSysMatrix<TYPE>::EnforceSolutionAtDOF(unsigned long, unsigned long, su2double, \
1207-
CSysVector<su2double>&); \
1229+
template void CSysMatrix<TYPE>::EnforceZeroProjection(unsigned long, const su2double*, CSysVector<su2double>&); \
12081230
INSTANTIATE_COMMS(TYPE)
12091231

12101232
#ifdef CODI_FORWARD_TYPE

SU2_CFD/src/solvers/CFEASolver.cpp

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,6 +1588,20 @@ void CFEASolver::BC_Clamped_Post(CGeometry *geometry, const CConfig *config, uns
15881588

15891589
}
15901590

1591+
namespace {
1592+
/*--- Helper for BC_Sym_Plane ---*/
1593+
template <typename Read, typename Write>
1594+
void SubtractProjection(unsigned short nDim, const su2double* n, const Read& read, const Write& write) {
1595+
su2double tmp[3] = {};
1596+
for (auto iDim = 0u; iDim < nDim; ++iDim) tmp[iDim] = read(iDim);
1597+
const su2double proj = DotProduct(nDim, tmp, n);
1598+
for (auto iDim = 0u; iDim < nDim; ++iDim) {
1599+
tmp[iDim] -= proj * n[iDim];
1600+
write(iDim, tmp[iDim]);
1601+
}
1602+
}
1603+
}
1604+
15911605
void CFEASolver::BC_Sym_Plane(CGeometry *geometry, const CConfig *config, unsigned short val_marker) {
15921606

15931607
if (geometry->GetnElem_Bound(val_marker) == 0) return;
@@ -1610,14 +1624,8 @@ void CFEASolver::BC_Sym_Plane(CGeometry *geometry, const CConfig *config, unsign
16101624
case 3: TriangleNormal(nodeCoord, normal); break;
16111625
case 4: QuadrilateralNormal(nodeCoord, normal); break;
16121626
}
1613-
1614-
auto axis = 0u;
1615-
for (auto iDim = 1u; iDim < MAXNDIM; ++iDim)
1616-
axis = (fabs(normal[iDim]) > fabs(normal[axis]))? iDim : axis;
1617-
1618-
if (fabs(normal[axis]) < 0.99*Norm(int(MAXNDIM),normal)) {
1619-
SU2_MPI::Error("The structural solver only supports axis-aligned symmetry planes.",CURRENT_FUNCTION);
1620-
}
1627+
const su2double area = Norm(int(MAXNDIM), normal);
1628+
for (auto iDim = 0u; iDim < MAXNDIM; ++iDim) normal[iDim] /= area;
16211629

16221630
/*--- Impose zero displacement perpendicular to the symmetry plane. ---*/
16231631

@@ -1627,20 +1635,29 @@ void CFEASolver::BC_Sym_Plane(CGeometry *geometry, const CConfig *config, unsign
16271635
const auto iPoint = geometry->vertex[val_marker][iVertex]->GetNode();
16281636

16291637
/*--- Set and enforce solution at current and previous time-step ---*/
1630-
nodes->SetSolution(iPoint, axis, 0.0);
1638+
#define SUBTRACT_PROJECTION(READ, WRITE) \
1639+
SubtractProjection(nDim, normal, [&](unsigned short iDim) { return nodes->READ(iPoint, iDim); }, \
1640+
[&](unsigned short iDim, const su2double& x) { nodes->WRITE(iPoint, iDim, x); });
1641+
SUBTRACT_PROJECTION(GetSolution, SetSolution)
16311642
if (dynamic) {
1632-
nodes->SetSolution_Vel(iPoint, axis, 0.0);
1633-
nodes->SetSolution_Accel(iPoint, axis, 0.0);
1634-
nodes->Set_Solution_time_n(iPoint, axis, 0.0);
1635-
nodes->SetSolution_Vel_time_n(iPoint, axis, 0.0);
1636-
nodes->SetSolution_Accel_time_n(iPoint, axis, 0.0);
1643+
SUBTRACT_PROJECTION(GetSolution_Vel, SetSolution_Vel)
1644+
SUBTRACT_PROJECTION(GetSolution_Accel, SetSolution_Accel)
1645+
SUBTRACT_PROJECTION(GetSolution_time_n, Set_Solution_time_n)
1646+
SUBTRACT_PROJECTION(GetSolution_Vel_time_n, SetSolution_Vel_time_n)
1647+
SUBTRACT_PROJECTION(GetSolution_Accel_time_n, SetSolution_Accel_time_n)
16371648
}
16381649

16391650
/*--- Set and enforce 0 solution for mesh deformation ---*/
1640-
nodes->SetBound_Disp(iPoint, axis, 0.0);
1641-
LinSysSol(iPoint, axis) = 0.0;
1642-
if (LinSysReact.GetLocSize() > 0) LinSysReact(iPoint, axis) = 0.0;
1643-
Jacobian.EnforceSolutionAtDOF(iPoint, axis, su2double(0.0), LinSysRes);
1651+
SUBTRACT_PROJECTION(GetBound_Disp, SetBound_Disp)
1652+
#undef SUBTRACT_PROJECTION
1653+
1654+
SubtractProjection(nDim, normal, [&](unsigned short iDim) { return LinSysSol(iPoint, iDim); },
1655+
[&](unsigned short iDim, const su2double& x) { LinSysSol(iPoint, iDim) = x; });
1656+
if (LinSysReact.GetLocSize() > 0) {
1657+
SubtractProjection(nDim, normal, [&](unsigned short iDim) { return LinSysReact(iPoint, iDim); },
1658+
[&](unsigned short iDim, const su2double& x) { LinSysReact(iPoint, iDim) = x; });
1659+
}
1660+
Jacobian.EnforceZeroProjection(iPoint, normal, LinSysRes);
16441661

16451662
}
16461663

TestCases/parallel_regression.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1233,7 +1233,7 @@ def main():
12331233
# For a thin disk with the inner and outer radius of this geometry, from
12341234
# "Formulas for Stress, Strain, and Structural Matrices", 2nd Edition, figure 19-4,
12351235
# the maximum stress is 165.6MPa, we get a Von Misses stress very close to that.
1236-
rotating_cylinder_fea.test_vals = [-6.005467, -5.615543, -5.615527, 38, -8.126591, 1.6457e8]
1236+
rotating_cylinder_fea.test_vals = [-6.861940, -6.835545, -6.895500, 22, -8.313847, 1.6502e+08]
12371237
test_list.append(rotating_cylinder_fea)
12381238

12391239
# Dynamic beam, 2d

0 commit comments

Comments
 (0)