Skip to content

Commit aaadbc8

Browse files
committed
Additional line performance improvements
1 parent 7fdc3c7 commit aaadbc8

File tree

5 files changed

+75
-172
lines changed

5 files changed

+75
-172
lines changed

bench/MDBench.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@ LineGetStateDeriv(benchmark::State& state, std::string input_file)
2121

2222
auto line = system.GetLines().front();
2323

24+
std::vector<moordyn::vec> vel{};
25+
std::vector<moordyn::vec> acc{};
2426
for (auto _ : state) {
25-
line->getStateDeriv();
27+
line->getStateDeriv(vel, acc);
2628
}
2729
}
2830
BENCHMARK_CAPTURE(LineGetStateDeriv,

source/Line.cpp

Lines changed: 66 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -666,18 +666,16 @@ Line::setPin(std::vector<real> p)
666666
}
667667

668668
void
669-
Line::setState(std::vector<vec> pos, std::vector<vec> vel)
669+
Line::setState(const std::vector<vec>& pos, const std::vector<vec>& vel)
670670
{
671671
if ((pos.size() != N - 1) || (vel.size() != N - 1)) {
672672
LOGERR << "Invalid input size" << endl;
673673
throw moordyn::invalid_value_error("Invalid input size");
674674
}
675675

676676
// set interior node positions and velocities based on state vector
677-
for (unsigned int i = 1; i < N; i++) {
678-
r[i] = pos[i - 1];
679-
rd[i] = vel[i - 1];
680-
}
677+
std::copy(pos.begin(), pos.end(), r.begin() + 1);
678+
std::copy(vel.begin(), vel.end(), rd.begin() + 1);
681679
}
682680

683681
void
@@ -769,8 +767,8 @@ Line::getEndSegmentMoment(EndPoints end_point, EndPoints rod_end_point) const
769767
return qEnd * EIEnd / dlEnd;
770768
}
771769

772-
std::pair<std::vector<vec>, std::vector<vec>>
773-
Line::getStateDeriv()
770+
void
771+
Line::getStateDeriv(std::vector<vec>& vel, std::vector<vec>& acc)
774772
{
775773
// NOTE:
776774
// Jose Luis Cercos-Pita: This is by far the most consuming function of the
@@ -802,6 +800,22 @@ Line::getStateDeriv()
802800
ldstr[i] = qs[i].dot(rd[i + 1] - rd[i]); // strain rate of segment
803801

804802
// V[i] = A * l[i]; // volume attributed to segment
803+
804+
if (nEApoints)
805+
E = getNonlinearE(lstr[i], l[i]);
806+
807+
if (lstr[i] > l[i]) {
808+
T[i] = E * A * (lstr[i] - l[i]) / l[i] * qs[i];
809+
} else {
810+
// cable can't "push" ...
811+
// or can it, if bending stiffness is nonzero? <<<<<<<<<
812+
T[i] = vec::Zero();
813+
}
814+
815+
// line internal damping force
816+
if (nCpoints)
817+
c = getNonlinearC(ldstr[i], l[i]);
818+
Td[i] = c * A * ldstr[i] / l[i] * qs[i];
805819
}
806820

807821
// calculate unit tangent vectors (q) for each internal node. note: I've
@@ -876,51 +890,9 @@ Line::getStateDeriv()
876890
}
877891
//============================================================================================
878892

879-
// calculate mass matrix
880-
for (unsigned int i = 0; i <= N; i++) {
881-
real m_i; // node mass
882-
real v_i; // node submerged volume
883-
884-
if (i == 0) {
885-
m_i = pi / 8. * d * d * l[0] * rho;
886-
v_i = 0.5 * F[0] * V[0];
887-
} else if (i == N) {
888-
m_i = pi / 8. * d * d * l[N - 1] * rho;
889-
v_i = 0.5 * F[i - 1] * V[i - 1];
890-
} else {
891-
m_i = pi / 8. * (d * d * rho * (l[i] + l[i - 1]));
892-
v_i = 0.5 * (F[i - 1] * V[i - 1] + F[i] * V[i]);
893-
}
894-
895-
// Make node mass matrix
896-
const mat I = mat::Identity();
897-
const mat Q = q[i] * q[i].transpose();
898-
M[i] = m_i * I + env->rho_w * v_i * (Can * (I - Q) + Cat * Q);
899-
}
900-
901893
// ============ CALCULATE FORCES ON EACH NODE
902894
// ===============================
903895

904-
// loop through the segments
905-
for (unsigned int i = 0; i < N; i++) {
906-
// line tension
907-
if (nEApoints > 0)
908-
E = getNonlinearE(lstr[i], l[i]);
909-
910-
if (lstr[i] / l[i] > 1.0) {
911-
T[i] = E * A * (lstr[i] - l[i]) / l[i] * qs[i];
912-
} else {
913-
// cable can't "push" ...
914-
// or can it, if bending stiffness is nonzero? <<<<<<<<<
915-
T[i] = vec::Zero();
916-
}
917-
918-
// line internal damping force
919-
if (nCpoints > 0)
920-
c = getNonlinearC(ldstr[i], l[i]);
921-
Td[i] = c * A * ldstr[i] / l[i] * qs[i];
922-
}
923-
924896
// Bending loads
925897
// first zero out the forces from last run
926898
for (unsigned int i = 0; i <= N; i++) {
@@ -1092,95 +1064,76 @@ Line::getStateDeriv()
10921064
}
10931065
}
10941066

1067+
// This mostly just simplifies the code, but also sometimes helps the
1068+
// compiler avoid repeated pointer lookup.
1069+
const real rho_w = env->rho_w;
1070+
const real g = env->g;
1071+
10951072
// loop through the nodes
10961073
for (unsigned int i = 0; i <= N; i++) {
1097-
W[i][0] = W[i][1] = 0.0;
1074+
// Nodes are considered to have a line length of half the length of the
1075+
// line on either side.
1076+
const real length_left = i == 0 ? 0.0 : l[i - 1];
1077+
const real length_right = i == N ? 0.0 : l[i];
1078+
const real length = 0.5 * (length_left + length_right);
1079+
const real submergence_left = i == 0 ? 0.0 : F[i - 1];
1080+
const real submergence_right = i == N ? 0.0 : F[i];
1081+
// Submerged length is half the submerged length of the neighboring
1082+
// segments
1083+
const real submerged_length = 0.5 * (length_left * submergence_left +
1084+
length_right * submergence_right);
1085+
1086+
const real submerged_volume = submerged_length * A;
1087+
1088+
const real m_i = A * length * rho; // node mass
1089+
const real v_i = submerged_volume; // node submerged volume
1090+
1091+
// Make node mass matrix
1092+
const mat I = mat::Identity();
1093+
const mat Q = q[i] * q[i].transpose();
1094+
// calculate mass matrix
1095+
M[i] = m_i * I + rho_w * v_i * (Can * (I - Q) + Cat * Q);
1096+
10981097
// submerged weight (including buoyancy)
1099-
if (i == 0)
1100-
W[i][2] = 0.5 * A * (l[i] * (rho - F[i] * env->rho_w)) * (-env->g);
1101-
else if (i == N)
1102-
W[i][2] = 0.5 * A * (l[i - 1] * (rho - F[i - 1] * env->rho_w)) *
1103-
(-env->g); // missing the "W[i][2] =" previously!
1104-
else
1105-
W[i][2] = 0.5 * A *
1106-
(l[i] * (rho - F[i] * env->rho_w) +
1107-
l[i - 1] * (rho - F[i - 1] * env->rho_w)) *
1108-
(-env->g);
1098+
W[i][0] = W[i][1] = 0.0;
1099+
W[i][2] = -g * (m_i - v_i * rho_w);
11091100

11101101
// relative flow velocity over node
11111102
const vec vi = U[i] - rd[i];
11121103
// tangential relative flow component
11131104
// <<<<<<< check sign since I've reversed q
1114-
const moordyn::real vql = vi.dot(q[i]);
1105+
const real vql = vi.dot(q[i]);
11151106
const vec vq = vql * q[i];
11161107
// transverse relative flow component
11171108
const vec vp = vi - vq;
11181109

1119-
const moordyn::real vq_mag = vq.norm();
1120-
const moordyn::real vp_mag = vp.norm();
1110+
const real vq_mag = vq.norm();
1111+
const real vp_mag = vp.norm();
11211112

1113+
const real shared_part = 0.5 * rho_w * d * submerged_length;
11221114
// transverse drag
1123-
if (i == 0)
1124-
Dp[i] = 0.25 * vp_mag * env->rho_w * Cdn * d * (F[i] * l[i]) * vp;
1125-
else if (i == N)
1126-
Dp[i] = 0.25 * vp_mag * env->rho_w * Cdn * d *
1127-
(F[i - 1] * l[i - 1]) * vp;
1128-
else
1129-
Dp[i] = 0.25 * vp_mag * env->rho_w * Cdn * d *
1130-
(F[i] * l[i] + F[i - 1] * l[i - 1]) * vp;
1131-
1115+
Dp[i] = vp_mag * Cdn * shared_part * vp;
11321116
// tangential drag
1133-
if (i == 0)
1134-
Dq[i] =
1135-
0.25 * vq_mag * env->rho_w * Cdt * pi * d * (F[i] * l[i]) * vq;
1136-
else if (i == N)
1137-
Dq[i] = 0.25 * vq_mag * env->rho_w * Cdt * pi * d *
1138-
(F[i - 1] * l[i - 1]) * vq;
1139-
else
1140-
Dq[i] = 0.25 * vq_mag * env->rho_w * Cdt * pi * d *
1141-
(F[i] * l[i] + F[i - 1] * l[i - 1]) * vq;
1117+
Dq[i] = vq_mag * Cdt * pi * shared_part * vq;
11421118

1143-
// tangential component of fluid acceleration
11441119
// <<<<<<< check sign since I've reversed q
1145-
const moordyn::real aql = Ud[i].dot(q[i]);
1120+
const real aql = Ud[i].dot(q[i]);
11461121
const vec aq = aql * q[i];
11471122
// normal component of fluid acceleration
11481123
const vec ap = Ud[i] - aq;
11491124

11501125
// transverse Froude-Krylov force
1151-
if (i == 0)
1152-
Ap[i] = env->rho_w * (1. + Can) * 0.5 * (F[i] * V[i]) * ap;
1153-
else if (i == N)
1154-
Ap[i] = env->rho_w * (1. + Can) * 0.5 * (F[i - 1] * V[i - 1]) * ap;
1155-
else
1156-
Ap[i] = env->rho_w * (1. + Can) * 0.5 *
1157-
(F[i] * V[i] + F[i - 1] * V[i - 1]) * ap;
1126+
Ap[i] = rho_w * (1. + Can) * submerged_volume * ap;
11581127
// tangential Froude-Krylov force
1159-
if (i == 0)
1160-
Aq[i] = env->rho_w * (1. + Cat) * 0.5 * (F[i] * V[i]) * aq;
1161-
else if (i == N)
1162-
Aq[i] = env->rho_w * (1. + Cat) * 0.5 * (F[i - 1] * V[i - 1]) * aq;
1163-
else
1164-
Aq[i] = env->rho_w * (1. + Cat) * 0.5 *
1165-
(F[i] * V[i] + F[i - 1] * V[i - 1]) * aq;
1128+
Aq[i] = rho_w * (1. + Cat) * submerged_volume * aq;
11661129

11671130
// bottom contact (stiffness and damping, vertical-only for now) -
11681131
// updated for general case of potentially anchor or fairlead end in
11691132
// contact
11701133
const real waterDepth = getWaterDepth(r[i][0], r[i][1]);
11711134
if (r[i][2] < waterDepth) {
1172-
if (i == 0)
1173-
B[i][2] =
1174-
((waterDepth - r[i][2]) * env->kb - rd[i][2] * env->cb) *
1175-
0.5 * d * (l[i]);
1176-
else if (i == N)
1177-
B[i][2] =
1178-
((waterDepth - r[i][2]) * env->kb - rd[i][2] * env->cb) *
1179-
0.5 * d * (l[i - 1]);
1180-
else
1181-
B[i][2] =
1182-
((waterDepth - r[i][2]) * env->kb - rd[i][2] * env->cb) *
1183-
0.5 * d * (l[i - 1] + l[i]);
1135+
B[i][2] = ((waterDepth - r[i][2]) * env->kb - rd[i][2] * env->cb) *
1136+
d * (length);
11841137

11851138
// new rough-draft addition of seabed friction
11861139
real FrictionMax =
@@ -1223,44 +1176,16 @@ Line::getStateDeriv()
12231176
Bs[i] + Pb[i];
12241177
}
12251178

1226-
// if (t > 5)
1227-
// {
1228-
// cout << " in getStateDeriv of line " << number << endl;
1229-
//
1230-
// B[0][0] = 0.001; // meaningless
1231-
// }
1232-
12331179
// loop through internal nodes and compute the accelerations
1234-
std::vector<vec> u, a;
1235-
u.reserve(N - 1);
1236-
a.reserve(N - 1);
1180+
vel.reserve(N - 1);
1181+
acc.reserve(N - 1);
12371182
for (unsigned int i = 1; i < N; i++) {
1238-
// double M_out[9];
1239-
// double F_out[3];
1240-
// for (int I=0; I<3; I++)
1241-
// { F_out[I] = Fnet[i][I];
1242-
// for (int J=0; J<3; J++) M_out[3*I + J] = M[i][I][J];
1243-
// }
1244-
1245-
// solve for accelerations in [M]{a}={f} using LU decomposition
1246-
// double LU[9]; // serialized matrix that will
1247-
// hold LU matrices combined Crout(3, M_out, LU); //
1248-
// perform LU decomposition on mass matrix double acc[3]; //
1249-
// acceleration vector to solve for solveCrout(3, LU, F_out, acc);
1250-
// // solve for acceleration vector
1251-
1252-
// LUsolve3(M[i], acc, Fnet[i]);
1253-
1254-
// Solve3(M[i], acc, (const double*)Fnet[i]);
1255-
12561183
// For small systems it is usually faster to compute the inverse
12571184
// of the matrix. See
12581185
// https://eigen.tuxfamily.org/dox/group__TutorialLinearAlgebra.html
1259-
a.push_back(M[i].inverse() * Fnet[i]);
1260-
u.push_back(rd[i]);
1186+
acc[i - 1] = M[i].inverse() * Fnet[i];
1187+
vel[i - 1] = rd[i];
12611188
}
1262-
1263-
return make_pair(u, a);
12641189
};
12651190

12661191
// write output file for line (accepts time parameter since retained time value

source/Line.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -816,7 +816,7 @@ class Line final : public io::IO, public NatFreqCFL
816816
* @see moordyn::Line::setEndState
817817
* @throws invalid_value_error If either @p r or @p u have wrong sizes
818818
*/
819-
void setState(std::vector<vec> r, std::vector<vec> u);
819+
void setState(const std::vector<vec>& r, const std::vector<vec>& u);
820820

821821
/** @brief Set the position and velocity of an end point
822822
* @param r Position
@@ -856,11 +856,11 @@ class Line final : public io::IO, public NatFreqCFL
856856
vec getEndSegmentMoment(EndPoints end_point, EndPoints rod_end_point) const;
857857

858858
/** @brief Calculate forces and get the derivative of the line's states
859-
* @return The velocities of the internal nodes (first) and the accelerations
860-
* of the internal nodes (second)
859+
* @param vel Where to store the velocities of the internal nodes
860+
* @param acc Where to store the accelerations of the internal nodes
861861
* @throws nan_error If nan values are detected in any node position
862862
*/
863-
std::pair<std::vector<vec>, std::vector<vec>> getStateDeriv();
863+
void getStateDeriv(std::vector<vec>& vel, std::vector<vec>& acc);
864864

865865
// void initiateStep(vector<double> &rFairIn, vector<double> &rdFairIn,
866866
// double time);

source/State.hpp

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,6 @@ template<typename T, typename V = T>
5050
class StateVar
5151
{
5252
public:
53-
/// @brief Costructor
54-
StateVar() {}
55-
56-
/// @brief Destructor
57-
~StateVar() {}
58-
5953
/// The position
6054
T pos;
6155
/// The velocity
@@ -108,12 +102,6 @@ template<class T, class V = T>
108102
class StateVarDeriv
109103
{
110104
public:
111-
/// @brief Constructor
112-
StateVarDeriv() {}
113-
114-
/// @brief Destructor
115-
~StateVarDeriv() {}
116-
117105
/// The velocity
118106
T vel;
119107
/// The acceleration
@@ -261,12 +249,6 @@ typedef StateVarDeriv<XYZQuat, vec6> DBodyStateDt;
261249
class MoorDynState
262250
{
263251
public:
264-
/// @brief Constructor
265-
MoorDynState() {}
266-
267-
/// @brief Destructor
268-
~MoorDynState() {}
269-
270252
/// The states of the lines
271253
std::vector<LineState> lines;
272254

@@ -321,12 +303,6 @@ class MoorDynState
321303
class DMoorDynStateDt
322304
{
323305
public:
324-
/// @brief Constructor
325-
DMoorDynStateDt() {}
326-
327-
/// @brief Destructor
328-
~DMoorDynStateDt() {}
329-
330306
/// The state derivatives of the lines
331307
std::vector<DLineStateDt> lines;
332308

source/Time.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ TimeSchemeBase<NSTATE, NDERIV>::CalcStateDeriv(unsigned int substep)
9898
for (unsigned int i = 0; i < lines.size(); i++) {
9999
if (!_calc_mask.lines[i])
100100
continue;
101-
std::tie(rd[substep].lines[i].vel, rd[substep].lines[i].acc) =
102-
lines[i]->getStateDeriv();
101+
lines[i]->getStateDeriv(rd[substep].lines[i].vel,
102+
rd[substep].lines[i].acc);
103103
}
104104

105105
for (unsigned int i = 0; i < points.size(); i++) {

0 commit comments

Comments
 (0)