MoorDyn
QSlines.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2022, Matt Hall
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice,
8  * this list of conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * 3. Neither the name of the copyright holder nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <cmath>
47 
48 #include <iostream>
49 #include <vector>
50 
51 using namespace std;
52 
54 int longwinded = 0;
55 
84 template<typename T>
85 int
86 Catenary(T XF,
87  T ZF,
88  T L,
89  T EA,
90  T W,
91  T CB,
92  T Tol,
93  T* HFout,
94  T* VFout,
95  T* HAout,
96  T* VAout,
97  unsigned int Nnodes,
98  vector<T>& s,
99  vector<T>& X,
100  vector<T>& Z,
101  vector<T>& Te)
102 {
103  if (longwinded == 1)
104  cout << "In Catenary. XF is " << XF << " and ZF is " << ZF << endl;
105 
106  // these are temporary and put to the pointers above with the "out" suffix
107  T HF, VF, HA, VA;
108 
109  if (longwinded == 1)
110  cout << "hi" << endl;
111 
112  // Checking inverted points at line ends: from catenary.py in MoorPy
113  bool reverseFlag;
114  if (ZF < 0.0) { // True if the fairlead has passed below its anchor
115  ZF = -ZF;
116  reverseFlag = true;
117  if (longwinded == 1)
118  cout << " Warning from catenary: "
119  << "Anchor point is above the fairlead point" << endl;
120  } else
121  reverseFlag = false;
122 
123  // Maximum stretched length of the line with seabed interaction beyond which
124  // the line would have to double-back on itself; here the line forms an "L"
125  // between the anchor and fairlead (i.e. it is horizontal along the seabed
126  // from the anchor, then vertical to the fairlead) (meters)
127  T LMax;
128 
129  if (W > 0.0) // .TRUE. when the line will sink in fluid
130  {
131  // Compute the maximum stretched length of the line with seabed
132  // interaction beyond which the line would have to double-back on
133  // itself; here the line forms an "L" between the anchor and fairlead
134  // (i.e. it is horizontal along the seabed from the anchor, then
135  // vertical to the fairlead)
136  LMax = XF - EA / W + sqrt((EA / W) * (EA / W) + 2.0 * ZF * EA / W);
137  if ((L >= LMax) && (CB >= 0.0)) {
138  // .TRUE. if the line is as long or longer than its maximum possible
139  // value with seabed interaction
140  if (longwinded == 1)
141  cout << "Warning from Catenary: "
142  << "Unstretched line length too large." << endl
143  << " d (horiz) is " << XF << " and h (vert) is "
144  << ZF << " and L is " << L << endl;
145  return -1;
146  }
147  }
148 
149  // Initialize some commonly used terms that don't depend on the iteration:
150  T WL = W * L;
151  T WEA = W * EA;
152  T LOvrEA = L / EA;
153  T CBOvrEA = CB / EA;
154  // Smaller tolerances may take more iterations, so choose a maximum
155  // inversely proportional to the tolerance
156  unsigned int MaxIter = (unsigned int)(1.0 / Tol);
157 
158  // more initialization
159  bool FirstIter = true; // Initialize iteration flag
160 
161  // Partial derivative of the calculated horizontal distance with respect to
162  // the horizontal fairlead tension (m/N): dXF(HF,VF)/dHF
163  T dXFdHF;
164  // Partial derivative of the calculated horizontal distance with respect to
165  // the vertical fairlead tension (m/N): dXF(HF,VF)/dVF
166  T dXFdVF;
167  // Partial derivative of the calculated vertical distance with respect to
168  // the horizontal fairlead tension (m/N): dZF(HF,VF)/dHF
169  T dZFdHF;
170  // Partial derivative of the calculated vertical distance with respect to
171  // the vertical fairlead tension (m/N): dZF(HF,VF)/dVF
172  T dZFdVF;
173  // Error function between calculated and known horizontal distance (meters):
174  // XF(HF,VF) - XF
175  T EXF;
176  // Error function between calculated and known vertical distance (meters):
177  // ZF(HF,VF) - ZF
178  T EZF;
179 
180  // Determinant of the Jacobian matrix (m^2/N^2)
181  T DET;
182  // Increment in HF predicted by Newton-Raphson (N)
183  T dHF;
184  // Increment in VF predicted by Newton-Raphson (N)
185  T dVF;
186 
187  // = HF/W
188  T HFOvrW;
189  // = HF/WEA
190  T HFOvrWEA;
191  // Catenary parameter used to generate the initial guesses of the horizontal
192  // and vertical tensions at the fairlead for the Newton-Raphson
193  // iteration (-)
194  T Lamda0;
195  // = L - VF/W
196  T LMinVFOvrW;
197  // = s[I]/EA
198  T sOvrEA;
199  // = SQRT( 1.0 + VFOvrHF2 )
200  T SQRT1VFOvrHF2;
201  // = SQRT( 1.0 + VFMinWLOvrHF2 )
202  T SQRT1VFMinWLOvrHF2;
203  // = SQRT( 1.0 + VFMinWLsOvrHF*VFMinWLsOvrHF )
204  T SQRT1VFMinWLsOvrHF2;
205  // = VF - WL
206  T VFMinWL;
207  // = VFMinWL/HF
208  T VFMinWLOvrHF;
209  // = VFMinWLOvrHF*VFMinWLOvrHF
210  T VFMinWLOvrHF2;
211  // = VFMinWL + Ws
212  T VFMinWLs;
213  // = VFMinWLs/HF
214  T VFMinWLsOvrHF;
215  // = VF/HF
216  T VFOvrHF;
217  // = VFOvrHF*VFOvrHF
218  T VFOvrHF2;
219  // = VF/WEA
220  T VFOvrWEA;
221  // = W*s[I]
222  T Ws;
223  // = XF*XF
224  T XF2;
225  // = ZF*ZF
226  T ZF2;
227 
228  // insertion - to get HF and VF initial guesses (FAST normally uses previous
229  // time step)
230  XF2 = XF * XF;
231  ZF2 = ZF * ZF;
232 
233  if (L <= sqrt(XF2 + ZF2)) {
234  //.TRUE. if the current mooring line is taut
235  Lamda0 = 0.2;
236  } else {
237  // The current mooring line must be slack and not vertical
238  Lamda0 = sqrt(3.0 * ((L * L - ZF2) / XF2 - 1.0));
239  }
240 
241  HF = abs(0.5 * W * XF / Lamda0);
242  VF = 0.5 * W * (ZF / tanh(Lamda0) + L);
243 
244  /*
245  ! To avoid an ill-conditioned situation, ensure that the initial guess for
246  ! HF is not less than or equal to zero. Similarly, avoid the problems
247  ! associated with having exactly vertical (so that HF is zero) or exactly
248  ! horizontal (so that VF is zero) lines by setting the minimum values
249  ! equal to the tolerance. This prevents us from needing to implement
250  ! the known limiting solutions for vertical or horizontal lines (and thus
251  ! complicating this routine):
252  */
253 
254  HF = max(HF, Tol);
255  XF = max(XF, Tol);
256  ZF = max(ZF, Tol);
257 
258  // Solve the analytical, static equilibrium equations for a catenary (or
259  // taut) mooring line with seabed interaction:
260 
261  // Begin Newton-Raphson iteration:
262  for (unsigned int I = 1; I <= MaxIter; I++) {
263  // Initialize some commonly used terms that depend on HF and VF:
264  HFOvrWEA = HF / WEA;
265  VFOvrWEA = VF / WEA;
266  VFOvrHF = VF / HF;
267  VFOvrHF2 = VFOvrHF * VFOvrHF;
268  SQRT1VFOvrHF2 = sqrt(1.0 + VFOvrHF2);
269  // These variables below need to be located in for loop, otherwise
270  // catenary solver fails
271  VFMinWL = VF - WL;
272  HFOvrW = HF / W;
273  LMinVFOvrW = L - VF / W;
274  VFMinWLOvrHF = VFMinWL / HF;
275  VFMinWLOvrHF2 = VFMinWLOvrHF * VFMinWLOvrHF;
276  SQRT1VFMinWLOvrHF2 = sqrt(1.0 + VFMinWLOvrHF2);
277 
278  // Compute the error functions (to be zeroed) and the Jacobian matrix
279  // (these depend on the anticipated configuration of the mooring
280  // line):
281  if ((CB < 0.0) || (W < 0.0) || (VFMinWL > 0.0)) {
282  // .TRUE. when no portion of the line rests on the seabed
283  EXF = (log(VFOvrHF + SQRT1VFOvrHF2) -
284  log(VFMinWLOvrHF + SQRT1VFMinWLOvrHF2)) *
285  HFOvrW +
286  LOvrEA * HF - XF;
287  EZF = (SQRT1VFOvrHF2 - SQRT1VFMinWLOvrHF2) * HFOvrW +
288  LOvrEA * (VF - 0.5 * WL) - ZF;
289  dXFdHF = (log(VFOvrHF + SQRT1VFOvrHF2) -
290  log(VFMinWLOvrHF + SQRT1VFMinWLOvrHF2)) /
291  W -
292  ((VFOvrHF + VFOvrHF2 / SQRT1VFOvrHF2) /
293  (VFOvrHF + SQRT1VFOvrHF2) -
294  (VFMinWLOvrHF + VFMinWLOvrHF2 / SQRT1VFMinWLOvrHF2) /
295  (VFMinWLOvrHF + SQRT1VFMinWLOvrHF2)) /
296  W +
297  LOvrEA;
298  dXFdVF =
299  ((1.0 + VFOvrHF / SQRT1VFOvrHF2) / (VFOvrHF + SQRT1VFOvrHF2) -
300  (1.0 + VFMinWLOvrHF / SQRT1VFMinWLOvrHF2) /
301  (VFMinWLOvrHF + SQRT1VFMinWLOvrHF2)) /
302  W;
303  dZFdHF = (SQRT1VFOvrHF2 - SQRT1VFMinWLOvrHF2) / W -
304  (VFOvrHF2 / SQRT1VFOvrHF2 -
305  VFMinWLOvrHF2 / SQRT1VFMinWLOvrHF2) /
306  W;
307  dZFdVF =
308  (VFOvrHF / SQRT1VFOvrHF2 - VFMinWLOvrHF / SQRT1VFMinWLOvrHF2) /
309  W +
310  LOvrEA;
311  } else if (-CB * VFMinWL < HF) {
312  // .TRUE. when a portion of the line rests on the seabed and the
313  // anchor tension is nonzero
314  EXF = log(VFOvrHF + SQRT1VFOvrHF2) * HFOvrW -
315  0.5 * CBOvrEA * W * LMinVFOvrW * LMinVFOvrW + LOvrEA * HF +
316  LMinVFOvrW - XF;
317  EZF = (SQRT1VFOvrHF2 - 1.0) * HFOvrW + 0.5 * VF * VFOvrWEA - ZF;
318 
319  dXFdHF = log(VFOvrHF + SQRT1VFOvrHF2) / W -
320  ((VFOvrHF + VFOvrHF2 / SQRT1VFOvrHF2) /
321  (VFOvrHF + SQRT1VFOvrHF2)) /
322  W +
323  LOvrEA;
324  dXFdVF =
325  ((1.0 + VFOvrHF / SQRT1VFOvrHF2) / (VFOvrHF + SQRT1VFOvrHF2)) /
326  W +
327  CBOvrEA * LMinVFOvrW - 1.0 / W;
328  dZFdHF = (SQRT1VFOvrHF2 - 1.0 - VFOvrHF2 / SQRT1VFOvrHF2) / W;
329  dZFdVF = (VFOvrHF / SQRT1VFOvrHF2) / W + VFOvrWEA;
330  } else {
331  // A portion of the line must rest on the seabed and the anchor
332  // tension is zero
333  EXF =
334  log(VFOvrHF + SQRT1VFOvrHF2) * HFOvrW -
335  0.5 * CBOvrEA * W *
336  (LMinVFOvrW * LMinVFOvrW -
337  (LMinVFOvrW - HFOvrW / CB) * (LMinVFOvrW - HFOvrW / CB)) +
338  LOvrEA * HF + LMinVFOvrW - XF;
339  EZF = (SQRT1VFOvrHF2 - 1.0) * HFOvrW + 0.5 * VF * VFOvrWEA - ZF;
340  dXFdHF = log(VFOvrHF + SQRT1VFOvrHF2) / W -
341  ((VFOvrHF + VFOvrHF2 / SQRT1VFOvrHF2) /
342  (VFOvrHF + SQRT1VFOvrHF2)) /
343  W +
344  LOvrEA - (LMinVFOvrW - HFOvrW / CB) / EA;
345  dXFdVF =
346  ((1.0 + VFOvrHF / SQRT1VFOvrHF2) / (VFOvrHF + SQRT1VFOvrHF2)) /
347  W +
348  HFOvrWEA - 1.0 / W;
349  dZFdHF = (SQRT1VFOvrHF2 - 1.0 - VFOvrHF2 / SQRT1VFOvrHF2) / W;
350  dZFdVF = (VFOvrHF / SQRT1VFOvrHF2) / W + VFOvrWEA;
351  }
352 
353  // Compute the determinant of the Jacobian matrix and the incremental
354  // tensions predicted by Newton-Raphson:
355  DET = dXFdHF * dZFdVF - dXFdVF * dZFdHF;
356 
357  // This is the incremental change in horizontal tension at the fairlead
358  // as predicted by Newton-Raphson
359  dHF = (-dZFdVF * EXF + dXFdVF * EZF) / DET;
360  // This is the incremental change in vertical tension at the fairlead as
361  // predicted by Newton-Raphson
362  dVF = (dZFdHF * EXF - dXFdHF * EZF) / DET;
363 
364  // ! Reduce dHF by factor (between 1 at I = 1 and 0 at I = MaxIter) that
365  // reduces linearly with iteration count to ensure that we converge on a
366  // solution even in the case were we obtain a nonconvergent cycle about
367  // the correct solution (this happens, for example, if we jump to
368  // quickly between a taut and slack catenary)
369  dHF = dHF * (1.0 - Tol * I);
370  // ! Reduce dHF by factor (between 1 at I = 1 and 0 at I = MaxIter) that
371  // reduces linearly with iteration count to ensure that we converge on a
372  // solution even in the case were we obtain a nonconvergent cycle about
373  // the correct solution (this happens, for example, if we jump to
374  // quickly between a taut and slack catenary)
375  dVF = dVF * (1.0 - Tol * I);
376 
378  // than or equal to zero by having a lower limit of Tol*HF [NOTE: the
379  // value of dHF = ( Tol - 1.0 )*HF comes from: HF = HF + dHF = Tol*HF
380  // when dHF = ( Tol - 1.0 )*HF]
381  dHF = max(dHF, (T)(Tol - 1.0) * HF);
382 
383  // Check if we have converged on a solution, or restart the iteration,
384  // or abort if we cannot find a solution:
385  if ((abs(dHF) <= abs(Tol * HF)) && (abs(dVF) <= abs(Tol * VF))) {
386  // .TRUE. if we have converged; stop iterating!
387  // [The converge tolerance, Tol, is a fraction of tension]
388  break;
389  }
390 
391  else if ((I == MaxIter) && FirstIter) {
392  // .TRUE. if we've iterated MaxIter-times for the first time, try a
393  // new set of ICs;
394  /*
395  ! Perhaps we failed to converge because our initial guess was too
396  far off. ! (This could happen, for example, while linearizing a
397  model via large ! pertubations in the DOFs.) Instead, use
398  starting values documented in: ! Peyrot, Alain H. and Goulois, A.
399  M., "Analysis Of Cable Structures," ! Computers & Structures, Vol.
400  10, 1979, pp. 805-813: ! NOTE: We don't need to check if the current
401  mooring line is exactly ! vertical (i.e., we don't need to
402  check if XF == 0.0), because XF is ! limited by the tolerance
403  above.
404  */
405 
406  XF2 = XF * XF;
407  ZF2 = ZF * ZF;
408 
409  if (L <= sqrt(XF2 + ZF2)) {
410  //.TRUE. if the current mooring line is taut
411  Lamda0 = 0.2;
412  } else {
413  // The current mooring line must be slack and not vertical
414  Lamda0 = sqrt(3.0 * ((L * L - ZF2) / XF2 - 1.0));
415  }
416 
417  // ! As above, set the lower limit of the guess value of HF to the
418  // tolerance
419  HF = max((T)abs(0.5 * W * XF / Lamda0), Tol);
420  VF = 0.5 * W * (ZF / tanh(Lamda0) + L);
421 
422  // Restart Newton-Raphson iteration:
423  I = 0;
424  FirstIter = false;
425  dHF = 0.0;
426  dVF = 0.0;
427  }
428 
429  else if ((I == MaxIter) && (!FirstIter)) {
430  // .TRUE. if we've iterated as much as we can take without finding a
431  // solution; Abort
432  if (longwinded == 1)
433  cout << "Reached max iterations without finding solution, "
434  << "aborting catenary solver ..." << endl;
435  return -1;
436  }
437 
438  // Increment fairlead tensions and iterate...
439  HF = HF + dHF;
440  VF = VF + dVF;
441  }
442 
443  /*
444  ! We have found a solution for the tensions at the fairlead!
445  ! Now compute the tensions at the anchor and the line position and tension
446  ! at each node (again, these depend on the configuration of the mooring
447  ! line):
448  */
449 
450  if ((CB < 0.0) || (W < 0.0) || (VFMinWL > 0.0)) {
451  // .TRUE. when no portion of the line rests on the seabed
452  // Anchor tensions:
453  HA = HF;
454  VA = VFMinWL;
455 
457  for (unsigned int I = 0; I < Nnodes; I++) {
458  if ((s[I] < 0.0) || (s[I] > L)) {
459  if (longwinded == 1)
460  cout << "Warning from Catenary: "
461  << "All line nodes must be located between the anchor "
462  << "and fairlead (inclusive) in routine Catenary()"
463  << endl;
464  return -1;
465  }
466 
467  // Initialize some commonly used terms that depend on s[I]
468  Ws = W * s[I];
469  VFMinWLs = VFMinWL + Ws;
470  VFMinWLsOvrHF = VFMinWLs / HF;
471  sOvrEA = s[I] / EA;
472  SQRT1VFMinWLsOvrHF2 = sqrt(1.0 + VFMinWLsOvrHF * VFMinWLsOvrHF);
473 
474  X[I] = (log(VFMinWLsOvrHF + SQRT1VFMinWLsOvrHF2) -
475  log(VFMinWLOvrHF + SQRT1VFMinWLOvrHF2)) *
476  HFOvrW +
477  sOvrEA * HF;
478  Z[I] = (SQRT1VFMinWLsOvrHF2 - SQRT1VFMinWLOvrHF2) * HFOvrW +
479  sOvrEA * (VFMinWL + 0.5 * Ws);
480  Te[I] = sqrt(HF * HF + VFMinWLs * VFMinWLs);
481  }
482  } else if (-CB * VFMinWL < HF) {
483  // .TRUE. when a portion of the line rests on the seabed and the anchor
484  // tension is nonzero
485 
486  // Anchor tensions:
487  HA = HF + CB * VFMinWL;
488  VA = 0.0;
489 
490  // Line position and tension at each node:
491  for (unsigned int I = 0; I < Nnodes; I++) {
492  if ((s[I] < 0.0) || (s[I] > L)) {
493  if (longwinded == 1)
494  cout << "Warning from Catenary: "
495  << "All line nodes must be located between the anchor "
496  << "and fairlead (inclusive) in routine Catenary()"
497  << endl;
498  return -1;
499  }
500 
501  // Initialize some commonly used terms that depend on s[I]
502  Ws = W * s[I];
503  VFMinWLs = VFMinWL + Ws;
504  VFMinWLsOvrHF = VFMinWLs / HF;
505  sOvrEA = s[I] / EA;
506  SQRT1VFMinWLsOvrHF2 = sqrt(1.0 + VFMinWLsOvrHF * VFMinWLsOvrHF);
507 
508  if (s[I] <= LMinVFOvrW) {
509  // .TRUE. if this node rests on the seabed and the tension is
510  // nonzero
511  X[I] = s[I] + sOvrEA * (HF + CB * VFMinWL + 0.5 * Ws * CB);
512  Z[I] = 0.0;
513  Te[I] = HF + CB * VFMinWLs;
514  } else {
515  // LMinVFOvrW < s <= L ! This node must be above the seabed
516  X[I] = log(VFMinWLsOvrHF + SQRT1VFMinWLsOvrHF2) * HFOvrW +
517  sOvrEA * HF + LMinVFOvrW -
518  0.5 * CB * VFMinWL * VFMinWL / WEA;
519  Z[I] = (-1.0 + SQRT1VFMinWLsOvrHF2) * HFOvrW +
520  sOvrEA * (VFMinWL + 0.5 * Ws) +
521  0.5 * VFMinWL * VFMinWL / WEA;
522  Te[I] = sqrt(HF * HF + VFMinWLs * VFMinWLs);
523  }
524  }
525 
526  } else {
527  // 0.0 < HF <= -CB*VFMinWL ! A portion of the line must rest on the
528  // seabed and the anchor tension is zero
529 
530  // Anchor tensions:
531  HA = 0.0;
532  VA = 0.0;
533 
534  // Line position and tension at each node:
535  for (unsigned int I = 0; I < Nnodes; I++) {
536  if ((s[I] < 0.0) || (s[I] > L)) {
537  if (longwinded == 1)
538  cout << "Warning from Catenary: "
539  << "All line nodes must be located between the anchor "
540  << "and fairlead (inclusive) in routine Catenary()"
541  << endl;
542  return -1;
543  }
544 
545  // Initialize some commonly used terms that depend on s[I]
546  Ws = W * s[I];
547  VFMinWLs = VFMinWL + Ws;
548  VFMinWLsOvrHF = VFMinWLs / HF;
549  sOvrEA = s[I] / EA;
550  SQRT1VFMinWLsOvrHF2 = sqrt(1.0 + VFMinWLsOvrHF * VFMinWLsOvrHF);
551 
552  if (s[I] <= LMinVFOvrW - HFOvrW / CB) {
553  // .TRUE. if this node rests on the seabed and the tension is
554  // zero
555  X[I] = s[I];
556  Z[I] = 0.0;
557  Te[I] = 0.0;
558  } else if (s[I] <= LMinVFOvrW) {
559  // .TRUE. if this node rests on the seabed and the tension is
560  // nonzero
561  X[I] = s[I] - (LMinVFOvrW - 0.5 * HFOvrW / CB) * HF / EA +
562  sOvrEA * (HF + CB * VFMinWL + 0.5 * Ws * CB) +
563  0.5 * CB * VFMinWL * VFMinWL / WEA;
564  Z[I] = 0.0;
565  Te[I] = HF + CB * VFMinWLs;
566  } else {
567  // LMinVFOvrW < s <= L ! This node must be above the seabed
568  X[I] = log(VFMinWLsOvrHF + SQRT1VFMinWLsOvrHF2) * HFOvrW +
569  sOvrEA * HF + LMinVFOvrW -
570  (LMinVFOvrW - 0.5 * HFOvrW / CB) * HF / EA;
571  Z[I] = (-1.0 + SQRT1VFMinWLsOvrHF2) * HFOvrW +
572  sOvrEA * (VFMinWL + 0.5 * Ws) +
573  0.5 * VFMinWL * VFMinWL / WEA;
574  Te[I] = sqrt(HF * HF + VFMinWLs * VFMinWLs);
575  }
576  }
577  }
578 
579  *HFout = HF;
580  *VFout = VF;
581  *HAout = HA;
582  *VAout = VA;
583 
584  if (reverseFlag) { // return values to normal
585  reverse(s.begin(), s.end());
586  reverse(X.begin(), X.end());
587  reverse(Z.begin(), Z.end());
588  reverse(Te.begin(), Te.end());
589  for (unsigned int I = 0; I < Nnodes; I++) {
590  s[I] = L - s[I];
591  X[I] = XF - X[I];
592  Z[I] = Z[I] - ZF;
593  }
594  ZF = -ZF;
595  }
596 
597  return 1;
598 }
int longwinded
switch to turn on excessive output for locating crashes
Definition: QSlines.hpp:54
int Catenary(T XF, T ZF, T L, T EA, T W, T CB, T Tol, T *HFout, T *VFout, T *HAout, T *VAout, unsigned int Nnodes, vector< T > &s, vector< T > &X, vector< T > &Z, vector< T > &Te)
Positions and tensions of a single mooring line.
Definition: QSlines.hpp:86