Skip to content

Commit 094ecff

Browse files
authored
feat(core): Implementation of the Syrope model for polyester ropes
* Syrope model implementation * Optimization of the exponential working curve formula * Fixed wrong initial mean tension and wrong working when Tmean < Tmax * Documentation for Syrope extension * Test for Syrope model with slow loading * Three working curve formulas in one test * Formatting * Renamed the input file for the Syrope test * Syrope test passed * Added a reference for the Syrope model * Removed bold texts in Syrope input description * Keep the Syrope reference in Chicago style as the others * Use (std::max) and (std::min) instead of std::max and std::min for Windows sake * #define _USE_MATH_DEFINES before including cmath * Disabled quadratic and exponential wc formulas, increased time step size and reduced IC duration * formatted test syrope.cpp * Put the references in chronological order * Moved the nonlinear stiffness inputs to the Additional MoorDyn Files * Read syrope working curve settings from a separate file * Read initial Tmax and Tmean for Syrope lines in the LINES section * Updated the test input files * Updated the docs for Syrope model * read Tmax and Tmean from a separate section instead from LINES section * Throw a warning if a SYROPE IC is present but Syrope is not used * Read Tmax and Tmean for Syrope lines from a separate section instead from LINES section * Updated the input files for test syrope * Updated documentation for Syrope IC inputs * Excluded the syrope test from memcheck * Removed Tmax0 and Tmean0 from LINES section
1 parent 3521d7f commit 094ecff

17 files changed

Lines changed: 1366 additions & 46 deletions

File tree

.github/workflows/memcheck.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,4 @@ jobs:
3636
- name: Test
3737
working-directory: ${{github.workspace}}/build
3838
# We are just testing in Linux
39-
run: ctest -C ${{env.BUILD_TYPE}} -T memcheck --output-on-failure -j ${{env.PROCESSES}} -E "(seafloor|time_schemes|wavekin|wilson|lowe_and_langley_2006)"
39+
run: ctest -C ${{env.BUILD_TYPE}} -T memcheck --output-on-failure -j ${{env.PROCESSES}} -E "(seafloor|time_schemes|wavekin|wilson|lowe_and_langley_2006|syrope)"

docs/inputs.rst

Lines changed: 82 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ There is not a limit on the number of lines you can write here.
266266
--------------------- MoorDyn Input File ------------------------------------
267267
MoorDyn v2 sample input file
268268
269+
.. _line-types-v2:
269270
Line Types
270271
^^^^^^^^^^
271272

@@ -285,7 +286,7 @@ The columns in order are as follows:
285286
- Diam – the volume-equivalent diameter of the line – the diameter of a cylinder having the same
286287
displacement per unit length (m)
287288
- MassDen – the mass per unit length of the line (kg/m)
288-
- EA – the line stiffness, product of elasticity modulus and cross-sectional area (N)
289+
- EA – the line stiffness, product of elasticity modulus and cross-sectional area (N), or nonlinear parameters (see descriptions below)
289290
- BA/-zeta – the line internal damping (measured in N-s) or, if a negative value is entered, the
290291
desired damping ratio (in fraction of critical) for the line type (and MoorDyn will set the BA
291292
of each line accordingly)
@@ -306,24 +307,13 @@ The columns in order are as follows:
306307
- cF - OPTIONAL - the center of the range of non-dimensional frequencies for the CF VIV synchronization model. If it is not
307308
provided and VIV is enabled (Cl > 0) then it is default to 0.18 to align with the the theory found :ref:`here <version2>`
308309

309-
Note: Non-linear values for the stiffness (EA) are an option in MoorDyn. For this, a file name can be provided instead of a number. This file
310-
must be located in the same folder as the main MoorDyn input file for MoorDyn-C or for MoorDyn-F
311-
in the same folder as the executable calling MoorDyn-F, unless a path is specified. Such file is a
312-
tabulated file with 3 header lines and then a strain column and a tension column separated by a blank space:
313-
314-
.. code-block:: none
315-
316-
----Polyester----
317-
Strain Tension
318-
(-) (N)
319-
0.0 0.0
320-
... ...
321-
322310
Note: MoorDyn has the ability to model the viscoelastic properties of synthetic lines in two ways. The first method, from work linked in the
323311
:ref:`theory section <theory>`, allows a user to specify a bar-separated constant dynamic and static stiffness. The second method allows the user
324312
to provide a constant static stiffness and two terms to determine the dynamic stiffness as a linear function of mean load. The equation is:
325-
`EA_d = EA_Dc + EA_D_Lm * mean_load` where `EA_D_Lm` is the slope of the load-stiffness curve. Both of these methods allow users to provide static
326-
and dynamic damping coefficients as values separated by |. While the static damping can be described as a fraction of critical, the dynamic damping
313+
`EA_d = EA_Dc + EA_D_Lm * mean_load` where `EA_D_Lm` is the slope of the load-stiffness curve. This method can be used standalone,
314+
and is also part of the Syrope model described in :ref:`Syrope Model for Polyester Lines <syrope-model-polyester-lines>`.
315+
Both of these methods allow users to provide static and dynamic damping coefficients as values separated by |.
316+
While the static damping can be described as a fraction of critical, the dynamic damping
327317
needs to be input as a value. Example inputs are below:
328318
329319
.. code-block:: none
@@ -497,9 +487,9 @@ The columns are as follows:
497487
- UnstrLen - the unstretched length of the line
498488
- NumSegs - how many segments the line is discretized into (it will have NumSegs+1 nodes total,
499489
including its two end nodes)
500-
- LineOutputs - any data to be output in a dedicated output file for that line.
490+
- LineOutputs - any data to be output in a dedicated output file for that line.
501491

502-
This last entry expects a string of one or more characters without spaces, each character
492+
This `LineOutputs` entry expects a string of one or more characters without spaces, each character
503493
activating a given output property. A placeholder character such as “-” should be used if no
504494
outputs are wanted. Ten output properties are currently possible:
505495

@@ -1008,6 +998,80 @@ data.
1008998
5000 0.15 0.0
1009999
--------------------- need this line ------------------
10101000
1001+
Nonlinear Stiffness (EA) Inputs
1002+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1003+
Non-linear values for the stiffness (EA) are an option in MoorDyn. For this, a file name can be provided instead of a number. This file
1004+
must be located in the same folder as the main MoorDyn input file for MoorDyn-C or for MoorDyn-F
1005+
in the same folder as the executable calling MoorDyn-F, unless a path is specified. Such file is a
1006+
tabulated file with 3 header lines and then a strain column and a tension column separated by a blank space:
1007+
1008+
.. code-block:: none
1009+
1010+
----Polyester----
1011+
Strain Tension
1012+
(-) (N)
1013+
0.0 0.0
1014+
... ...
1015+
1016+
.. _syrope-model-polyester-lines:
1017+
Syrope Model for Polyester Lines
1018+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1019+
MoorDyn supports the Syrope material model for polyester ropes. In this formulation, the
1020+
tension–strain response is nonlinear and load-path dependent, meaning the unloading and
1021+
reloading curves differ. See additional details in the :ref:`theory section <theory>`
1022+
and the references therein.
1023+
1024+
To enable the Syrope model for a given line type, specify the EA field using three
1025+
bar-separated entries, analogous to the load-dependent dynamic stiffness method described in :ref:`Line Types <line-types-v2>`.
1026+
To indicate Syrope, the first entry must start with ``SYROPE:``, followed by the name (or path)
1027+
of a Syrope config file defining the working curves. The second and third entries are
1028+
``EA_Dc`` and ``EA_D_Lm`` (as in the load-dependent dynamic stiffness method in :ref:`Line Types <line-types-v2>`). Static and dynamic
1029+
damping may be provided in BA as ``BA_s|BA_d`` (same convention as above).
1030+
1031+
Example:
1032+
1033+
.. code-block:: none
1034+
1035+
TypeName Diam Mass/m EA BA
1036+
(name) (m) (kg/m) (N) (N-s)
1037+
poly ... ... SYROPE:syrope.dat|EA_Dc|EA_D_Lm BA_s|BA_d
1038+
1039+
The file ``syrope.dat`` defines
1040+
1041+
- OWC: a tabulated nonlinear original working curve
1042+
- WCType: the working-curve type (options: ``LINEAR``, ``QUADRATIC``, ``EXP``)
1043+
- k1: the first coefficient for the working curve formula (sets the strain offset where mean tension is zero)
1044+
- k2: the second coefficient for the working curve formula (sets the curve shape)
1045+
1046+
One example of such file is shown below.
1047+
1048+
.. code-block:: none
1049+
1050+
../owc.dat OWC Original working curve lookup table path, relative to the MoorDyn input file
1051+
LINEAR WCType Working curve formula: LINEAR, QUADRATIC, or EXP
1052+
0.25 k1 First parameter defining the working curve shape
1053+
1.00 k2 Second parameter defining the working curve shape
1054+
1055+
The ``owc.dat`` file follows the same format as the tabulated non-linear stiffness files described
1056+
above (three header lines, then columns for strain and tension).
1057+
1058+
Initial conditions are specified for the Syrope lines in a separate ``SYROPE IC`` section placed after the ``LINES`` section.
1059+
1060+
- Line(s) - the Syrope line number(s). This may be a single line number or a comma-separated list of line numbers. If non-Syrope lines are included, they are ignored and a warning is raised.
1061+
- Tmax0 – the initial highest mean tension experienced by the line prior to the current time (N)
1062+
- Tmean0 – the initial mean tension (N)
1063+
1064+
One example of the ``SYROPE IC`` section is shown below.
1065+
1066+
.. code-block:: none
1067+
1068+
---------------------- SYROPE IC --------------------------------------
1069+
Line(s) Tmax0 Tmean0
1070+
(-) (N) (N)
1071+
7,8,9 3.53e6 1.18e6
1072+
1073+
In general, ``Tmax0 >= Tmean0``.
1074+
10111075
MoorDyn-F with FAST.Farm - Inputs
10121076
-------------------------------
10131077

docs/references.rst

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,16 @@ Overview of MoorDyn v2 (bodies, rods, and line failures):
8282
`Hall, Matthew, “MoorDyn V2: New Capabilities in Mooring System Components and Load Cases.” In Proceedings of the ASME 2020 39th International
8383
Conference on Ocean, Offshore and Arctic Engineering. virtual conference, 2020. <https://www.nrel.gov/docs/fy20osti/76555.pdf>`_
8484

85-
Seabed friction and bathymetry approach used in v2:
86-
87-
`Housner, Stein, Ericka Lozon, Bruce Martin, Dorian Brefort, and Matthew Hall, “Seabed Bathymetry and Friction Modeling in MoorDyn.” Journal of
88-
Physics: Conference Series 2362, no. 1, Nov 2022: 012018. <https://doi.org/10.1088/1742-6596/2362/1/012018>`_
89-
9085
Implementation of bending stiffness modeling for power cables:
9186

9287
`Hall, Matthew, Senu Sirnivas, and Yi-Hsiang Yu, “Implementation and Verification of Cable Bending Stiffness in MoorDyn.” In ASME 2021 3rd International Offshore Wind
9388
Technical Conference, V001T01A011. Virtual, Online: American Society of Mechanical Engineers, 2021. <https://doi.org/10.1115/IOWTC2021-3565>`_
9489

90+
Seabed friction and bathymetry approach used in v2:
91+
92+
`Housner, Stein, Ericka Lozon, Bruce Martin, Dorian Brefort, and Matthew Hall, “Seabed Bathymetry and Friction Modeling in MoorDyn.” Journal of
93+
Physics: Conference Series 2362, no. 1, Nov 2022: 012018. <https://doi.org/10.1088/1742-6596/2362/1/012018>`_
94+
9595
Non-linear line stiffness:
9696

9797
`Lozon, Ericka, Matthew Hall, Paul McEvoy, Seojin Kim, and Bradley Ling, “Design and Analysis of a Floating-Wind Shallow-Water Mooring System
@@ -122,6 +122,10 @@ Modeling of Bi-stable Nonlinear Energy Sinks in MoorDyn (most recent description
122122
`Anargyros Michaloliakos, Wei-Ying Wong, Ryan Davies, Malakonda Reddy Lekkala, Matthew Hall, Lei Zuo, Alexander F. Vakakis, "Stabilizing dynamic subsea power cables using
123123
Bi-stable nonlinear energy sinks", Ocean Engineering, vol. 334, August 2025. <https://doi.org/10.1016/j.oceaneng.2025.121613>`_
124124

125+
Syrope model for polyester ropes:
126+
127+
`Wei, Zhilong, Harry B. Bingham, and Yanlin Shao. 2026. “ESOMOOR D5.1: Extended Moordyn Solver and Validation Report”. Technical University of Denmark. <https://doi.org/10.11583/DTU.31408806>`_
128+
125129
The Fortran version of MoorDyn is available as a module inside of OpenFAST:
126130

127131
https://openfast.readthedocs.io/en/main/

source/Line.cpp

Lines changed: 128 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,50 @@ Line::getNonlinearBA(real ld_stretched, real l_unstretched) const
118118
return Yi / Xi;
119119
}
120120

121+
void
122+
Line::setWorkingCurve(real Tmax)
123+
{
124+
// Check if Tmax is within the valid range
125+
if (Tmax < stiffYs.front() || Tmax > stiffYs.back()) {
126+
LOGERR << "Line " << lineId << ": Tmax value " << Tmax
127+
<< " is outside the working curve range [" << stiffYs.front()
128+
<< ", " << stiffYs.back() << "]." << endl;
129+
throw moordyn::invalid_value_error("Invalid Tmax for working curve");
130+
}
131+
// maximum and minimum strains for the working curve
132+
real eps_max = interp(stiffYs, stiffXs, Tmax);
133+
real eps_min = stiffXs.front() + k1 * (eps_max - stiffXs.front());
134+
135+
// For linear working curve, if k1 >= 1.0 (usually much larger than unity),
136+
// it is taken as the slope (or dimensional stiffness)
137+
if (syropeWCForm == SYROPE_LINEAR_WC && k1 >= 1.0)
138+
eps_min = eps_max - Tmax / k1;
139+
140+
for (unsigned int I = 0; I < nEApointsWC; I++) {
141+
// Normalize the strain points between eps_min and eps_max
142+
stiffxs_[I] = eps_min + (eps_max - eps_min) * I /
143+
(nEApointsWC - 1); // total strain
144+
real xi = (stiffxs_[I] - eps_min) / (eps_max - eps_min);
145+
146+
if (syropeWCForm == SYROPE_LINEAR_WC)
147+
stiffys_[I] = Tmax * xi;
148+
else if (syropeWCForm == SYROPE_QUADRATIC_WC)
149+
stiffys_[I] = Tmax * xi * (k2 * xi + (1.0 - k2));
150+
else if (syropeWCForm == SYROPE_EXP_WC)
151+
stiffys_[I] = Tmax * (1.0 - exp(k2 * xi)) / (1.0 - exp(k2));
152+
else {
153+
LOGERR << "Line " << lineId
154+
<< ": Invalid Syrope working curve formula " << syropeWCForm
155+
<< "." << endl;
156+
throw moordyn::invalid_value_error(
157+
"Invalid Syrope working curve formula");
158+
}
159+
160+
stiffzs_[I] = stiffxs_[I] -
161+
1.0 / vbeta * log(1.0 + vbeta / alphaMBL * stiffys_[I]);
162+
}
163+
}
164+
121165
void
122166
Line::setup(int number_in,
123167
LineProps* props,
@@ -158,16 +202,50 @@ Line::setup(int number_in,
158202
Cl = props->Cl;
159203
dF = props->dF;
160204
cF = props->cF;
205+
syropeWCForm = (syrope_wc_formula)props->SyropeWCForm;
206+
k1 = props->k1;
207+
k2 = props->k2;
161208

162209
// copy in nonlinear stress-strain data if applicable
163210
stiffXs.clear();
164211
stiffYs.clear();
212+
stiffZs.clear();
165213
nEApoints = props->nEApoints;
166214
for (unsigned int I = 0; I < nEApoints; I++) {
167215
stiffXs.push_back(props->stiffXs[I]);
168216
stiffYs.push_back(props->stiffYs[I]);
169217
}
170218

219+
// Compute the slow strain
220+
if (ElasticMod == ELASTIC_SYROPE) {
221+
for (unsigned int I = 0; I < nEApoints; I++) {
222+
stiffZs.push_back(
223+
props->stiffXs[I] -
224+
1.0 / vbeta * log(1.0 + vbeta / alphaMBL * props->stiffYs[I]));
225+
}
226+
227+
// Check if stiffZs is strictly increasing
228+
for (unsigned int I = 1; I < nEApoints; I++) {
229+
if (stiffZs[I] <= stiffZs[I - 1]) {
230+
LOGERR << "Line " << number
231+
<< ": The slow strain values for the Syrope model are "
232+
"not strictly increasing. Please check the "
233+
"stress-strain data provided."
234+
<< endl;
235+
throw moordyn::invalid_value_error(
236+
"Invalid slow strain data for Syrope model");
237+
}
238+
}
239+
240+
// Initialize working curve arrays
241+
stiffxs_.clear();
242+
stiffys_.clear();
243+
stiffzs_.clear();
244+
stiffxs_.assign(nEApointsWC, 0.0);
245+
stiffys_.assign(nEApointsWC, 0.0);
246+
stiffzs_.assign(nEApointsWC, 0.0);
247+
}
248+
171249
// Use the last entry on the lookup table. see Line::initialize()
172250
const real EA = nEApoints ? stiffYs.back() / stiffXs.back() : props->EA;
173251
NatFreqCFL::length(UnstrLen / N);
@@ -606,13 +684,24 @@ Line::initialize()
606684
// the segment. This is required here to initalize the state as non-zero,
607685
// which avoids an initial transient where the segment goes from unstretched
608686
// to stretched in one time step.
609-
if (ElasticMod != ELASTIC_CONSTANT) {
687+
if (ElasticMod != ELASTIC_CONSTANT && ElasticMod != ELASTIC_SYROPE) {
610688
for (unsigned int i = 0; i < N; i++) {
611689
lstr[i] = unitvector(qs[i], r[i], r[i + 1]);
612690
dl_1[i] = lstr[i] - l[i]; // delta l of the segment
613691
}
614692
}
615693

694+
// If using the Syrope model, initalize the deltaL_1 to slow stretch based
695+
// on the mean tension and the active working curve
696+
if (ElasticMod == ELASTIC_SYROPE) {
697+
for (unsigned int i = 0; i < N; i++) {
698+
lstr[i] = unitvector(qs[i], r[i], r[i + 1]);
699+
setWorkingCurve(Tmax[i]);
700+
dl_1[i] = interp(stiffys_, stiffzs_, Tmean[i]) *
701+
l[i]; // stretch instead of strain
702+
}
703+
}
704+
616705
// If using the VIV model, initalize as a distribution between 0 and 2pi for
617706
// inital phase of lift force to avoid initial transient
618707
if (Cl > 0)
@@ -1019,7 +1108,8 @@ Line::getStateDeriv(InstanceStateVarView drdt)
10191108
BA = getNonlinearBA(ldstr[i], l[i]);
10201109
Td[i] = BA * ldstr[i] / l[i] * qs[i];
10211110

1022-
} else {
1111+
} else if (ElasticMod == ELASTIC_VISCO_CTE ||
1112+
ElasticMod == ELASTIC_VISCO_MEAN) {
10231113
// viscoelastic model from
10241114
// https://asmedigitalcollection.asme.org/OMAE/proceedings/IOWTC2023/87578/V001T01A029/1195018
10251115
// note that dl_1[i] is the same as Line%dl_1 in MD-F. This is the
@@ -1094,6 +1184,42 @@ Line::getStateDeriv(InstanceStateVarView drdt)
10941184
// update state derivative for static stiffness stretch. The visco
10951185
// state is always the last element in the row.
10961186
drdt.row(i).tail<1>()[0] = ld_1[i];
1187+
} else if (ElasticMod == ELASTIC_SYROPE) {
1188+
const real dl = lstr[i] - l[i];
1189+
1190+
if (moordyn::EqualRealNos(Tmean[i], Tmax[i])) {
1191+
// on the original working curve
1192+
Tmean[i] = interp(stiffZs, stiffYs, dl_1[i] / l[i]);
1193+
if (dl >= 0.0)
1194+
T[i] = Tmean[i] * qs[i];
1195+
else
1196+
T[i] = vec::Zero();
1197+
1198+
ld_1[i] = ((dl - interp(stiffYs, stiffXs, Tmean[i]) * l[i]) *
1199+
(alphaMBL + vbeta * Tmean[i]) +
1200+
BA_D * ldstr[i]) /
1201+
(BA + BA_D);
1202+
drdt.row(i).tail<1>()[0] = ld_1[i];
1203+
Td[i] = ld_1[i] / l[i] * BA * qs[i];
1204+
} else { // on the working curve
1205+
Tmean[i] = interp(stiffzs_, stiffys_, dl_1[i] / l[i]);
1206+
if (dl >= 0.0)
1207+
T[i] = Tmean[i] * qs[i];
1208+
else
1209+
T[i] = vec::Zero();
1210+
1211+
ld_1[i] = ((dl - interp(stiffys_, stiffxs_, Tmean[i]) * l[i]) *
1212+
(alphaMBL + vbeta * Tmean[i]) +
1213+
BA_D * ldstr[i]) /
1214+
(BA + BA_D);
1215+
drdt.row(i).tail<1>()[0] = ld_1[i];
1216+
Td[i] = ld_1[i] / l[i] * BA * qs[i];
1217+
}
1218+
1219+
if (Tmean[i] > Tmax[i]) {
1220+
Tmax[i] = Tmean[i];
1221+
setWorkingCurve(Tmax[i]);
1222+
}
10971223
}
10981224
}
10991225

0 commit comments

Comments
 (0)