Skip to content

Conversation

@lucas-carmo
Copy link
Contributor

@lucas-carmo lucas-carmo commented Sep 11, 2025

Purpose

This PR is not ready to merge yet due to some dependency issues that should be addressed soon

PR to release version 2.0.0. It brings two major new capabilities to the master branch:

  • Multibody and flexibility #86: RAFT can now model FOWTs made of rigid and/or flexible members, and those members can be connected by joints that allow for relative motions between them (only cantilever and ball joints are supported for now). In other words, RAFT used to solve for the 6-dof motions of a rigid FOWT, whereas now it solves for an arbitrary number of degrees of freedom.
  • Dynamic tensions on mooring lines #60: RAFT can now use the lumped-mass approach for mooring lines available in MoorPy. This greatly improves the predictions of dynamic mooring tensions in cases where mooring dynamics (inertia and damping) are important.

Type of change

What types of change is it?

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (non-backwards-compatible fix or feature)
  • Code style update (formatting, renaming)
  • Refactoring (no functional changes, no API changes)
  • Documentation update
  • Maintenance update
  • Other (please describe)

Testing

Included several tests and examples for the new capabilities, as described in their respective PRs

Checklist

  • I have run existing tests which pass locally with my changes
  • I have added new tests or examples that prove my fix is effective or that my feature works
  • I have added necessary documentation

lucas-carmo and others added 30 commits November 30, 2023 11:53
This is based on an algebraic approximation by Aranha and Pinto, "Dynamic tension in risers and mooring lines: an algebraic approximation for harmonic excitation".

This version is still for comparisons with MoorDyn, so there is a part of the code that is used to read a MD output file and use the motions from there. This will be removed after the validation is done.
This commit incorporates the dynamic mooring developments from MoorPy into RAFT. The solution of body dynamics in model.solveDynamics can now account not only for the stiffness induced by the moorings but also for the inertia, added mass, and damping. Currently, it works only with the code in MoorPy's "dynamics branch" (commit #4bddb152cbaf607ca24f0303f93ed10b6ce197de).

Still WIP. Need to verify and debug.
- The values of the tension computed with the lumped mass approach (which includes dynamic amplification) at the extremities of the line are now saved to  the results dictionary
- Changed the values of moorMod. Now
moorMod = 0 is quasi static (before it was 1)
moorMod = 1 is dynamic
moorMod = 2 is dynamic but with the stiffness matrix from the quasi-static approach
- Damping due to moorings, which is obtained from linearizing the quadratic drag along the lines, is now evaluated iteratively depending on FOWT motion (only for mooring systems within each fowt, not array level)
- The lumped mass approach can now be used for array level mooring systems, including shared moorings
- New helper function "getLineEndsRAO" to avoid code repetition
Due to the lumped mass approach, we now convert all lines to subsystem before computing the dynamic tensions in mooring lines. That required changing the true values of VolturnUS-S_farm because this example includes multisegment lines
Due to the lumped mass capability (which is not currently tested), we now convert mooring lines to subsystem before computing tensions. That changes the size of  the arrays stored in model.results['case_metrics'][iCase]['array_mooring'][metric] used in test_analyzeCases(), as the 7 lines of the test case become 5 due to aggregating composite lines into a single subsystem.
Dynamic tensions on mooring lines
I forgot to update the .toml for release v1.3.1 and it was a lot of work to fix it. So I thought it better to add a little reminder so that we don't forget to do it again.
- solveStatics() and solveEigen() were using the quasi-static approach to compute the stiffness matrix regardless of moorMod. Now it follows the same as solveDynamics (moorMod=1: quasi static' moorMod=2: lumped mass; moorMod=3 lumped mass except for stiffness matrix, which uses the quasi-static approach)
- Had forgotten to update the overhang in the example with the lumped mass approach to follow the new convention (i.e. negative overhang is a upwind turbine)
- Added the frequency vector to the results dictionary
- Added tests using moorMod=1 and moorMod=2 (lumped mass approach for mooring lines)
- The lumped mass capability is currently on the MoorPy dev branch. Since we develop MoorPy and RAFT in parallel, it makes sense for GitHub actions to use MoorPy-dev for RAFT-dev
I test github actions on a separate fork with Ubuntu only, and I forgot to add MacOS and Windows back to CI_RAFT.yml before pushing. Putting them back.
- Added `test_calcQTF_slenderBody` in `test_fowt.py` that checks the QTFs computed with RAFT
- Modified tests/VolturnUS-S.yaml to compute the QTFs using the slender-body approximation and to use the MCF correction
- Besides the new QTF test, this commit affects the true values of test_analyzeCases (in test_model.py) and test_hydroExcitation (in test_fowt.py) for the test case VolturnUS-S.yaml. This is because the MCF correction affects the first-order loads and the second-order loads affect the response of the FOWT
- Made these two parameters attributes of the Model class, and can now
  be read in from the "settings" section of the RAFT yaml. Default 0.
  Updated docs as well.
- 'Q' output from CCBlade was in the 'pitch' spot and 'My' output from CCBlade was in the 'roll' spot - these should be flipped

- Also updating the default vapor pressure when calculating cavitation
- Also setting the currentMod = 1 when there is no mooring dictionary in the design dictionary (few cases)
This reverts commit 293801513e3015f45062d0748ba24a2c1ee10328.
This included updating true values of tests that were affected by bug fixes in rc1.3.2 but which were not included in that branch (e.g. tests with lumped mass moorings using the VolturnUS semi)
- Moved the moorMod switch out of the MoorPy System object and into the
  RAFT objects to avoid burying it.
- A couple adjustments for more consistent handling of cases whether
  a mooring section is provided in the RAFT input YAML.
- This helps for a couple less typical use cases.
-changes reinitialize to set
-changes fi.run() instead of claculate_wake
-changes to plotting functions
Some recent code changes in commit 9fdc8ee lead to errors when the system does not have FOWT-level moorings. For instance, the tests with shared moorings weren't passing. Now they should pass
lucas-carmo and others added 28 commits July 23, 2025 13:36
We were missing the contribution of the internal force acting on nodes whose dofs were reduced. For example, the weight of a flexible tower acting on the base node, when the dofs of the base node were reduced using the dofs of another node.
Modified calcHydroLinearization and calcDragExcitation (in both Member and FOWT classes) to fit in the new multibody/structural paradigm. In the Member class, this involves accounting for flexible members; in the FOWT class, this involves computing the forces in full dofs and then use fowt.T to convert the forces to the reduced set of dofs
model.solveDynamics() now solves the equations of motion in the reduced dofs of each FOWT. There are still some important modifications to do, in particular moorings and second order loads, but these can be dealt with later. Also, the function still doesn't work for arrays of turbines with fowt.nDOF != 6.

Updated true values of test_model.py::test_analyzeCases() due to new method to compute tower top acceleration
- Forgot some debug variables in member.computeInertiaMatrix_FE(). Also, now saving the inertia matrix of the member at member levels instead of just returning it

- We're not storing node's dynamic displacement at node level, but keeping node.Xi commented out in case we change our mind in the future
We were modifying the state of `self` in the function and not returning it to the original state. Changed the procedure to make sure that `self` remains the same
This is one of the main steps to make solveDynamics() work with flexible structures. Seems to be working!
For flexible towers, the tower base loads are now computed based on the finite-element stiffness matrix of the member. For rigid towers, the procedure is the same as before.

In the future, we could compute the loads on the joints and keep a single workflow for computing the tower based loads of both types of tower.
Added a circular beam and a rectangular beam to test_member.py. They are tested using previously existing test functions and a new test_StiffnessMatrix_FE() function, which is used to verify the structural stiffness matrix of beam members
- In fowt.setPosition(), changed the computation of fowt.r6 to use the same method as in fowt.setNodesPosition()
- QTFs computed using the slender body do not work for FOWTs with nDOF > 6 yet, so skipping that case in fowt.calcQTF_slenderBody()
- The software was throwing an error when computing the tower base moment for a FOWT with rigid and flexible/multibody floater because of the dimensions of the aerodynamic force vector
- Had forgotten to implement model.solveEigen() for platforms with nDOF > 6. Did the same modifications as we had done in fowt.solveEigen().
- Included a test case 'VolturnUS-S-flexible.yaml' which is the VolturnUS semi-submersible with flexible tower and flexible pontoons. It is used in test_fowt.py and test_model.py
- Most of the test functions in test_fowt.py had their True values specified directly in the .py file. This was fine because the FOWT always had 6 dofs, so arrays had a reasonable size. Now that we support FOWTs with an arbitrary number of dofs, it's unfeasible to keep all true values in text format. For this reason, this commit modifies all functions in test_fowt.py to use true values loaded from a pickle file. Didn't do that in test_model.py because it is reasonable to focus in a subset of results (for example, 10 first eigenmodes instead of all)
- also removing tests/15_RAFT_rect. This folder is created by one of the tests and was uploaded to the repo in a previous commit by mistake
Had a lot of temporary code, especially for plotting. Unnecessary code was removed. Useful plotting code was moved from temporary plotting functions to the main plotting functions.
test_model.py::test_solveStaticsWave() seems to be failing due to numerical differences between my machine and github actions. Because this test case does not have mean wave drift, some values are very small in some dofs. Adopting a larger tolerance, which is still quite restrict, for this test only
- Added a comment showing how to run /examples/VolturnUS-S_example.yaml with a flexible tower
- Added /examples/VolturnUS-S-flexible_example.yaml to exemplify cases with flexible floaters, which require the new input deck `joints`
- Noticed that the tower of tests\test_data\VolturnUS-S-flexible.yaml had unrealistically large Young and shear moduli. I was checking if using very stiff materials would result in the same as a perfectly rigid tower, but forgot to change those values back to something more reasonable after that
Multibody and flexibility
Now moorMod options correspond to the following:

- `moorMod=0`: quasi-static stiffness-only model (i.e., the only mooring model that was available in RAFT before)
- `moorMod=1`: body dynamics is solved using the quasi-static stiffness-only model, but mooring line tensions are computed using a lumped-mass approach that accounts for mooring line stiffness, inertia, added mass, and damping
- `moorMod=2`: both body dynamics and mooring line tensions are computed using the lumped mass approach. With that option, mooring lines affect floater dynamics not only through stiffness but also through inertia, hydrodynamic added mass, and hydrodynamic damping (from linearized quadratic drag)

This change is due to some feedback on the previous options and the usefulness of the option that now corresponds to moorMod=1 (i.e. solve body dynamics like before but improve prediction of mooring line tensions), which was missing before.
Some tests had a very fine frequency discretization that only makes sense for real analyses. Reduced that discretization to run tests faster.

Also added frequency vector to the pickle files with the true values to make it easier to plot the response, which is helpful to debug or check new true values when something changes. Needed that to compare results with the new frequency discretization against the results with the previous discretization.

Also the plots were using angular frequencies but xlabel was in Hz. The plots are properly in Hz now.
- After MoorPy's v1.2.0, GitHub actions does not need to use MoorPy's dev branch anymore
- Updated toml file to correspond to the new version. Also updated list of maintainers
- Pretty small change in test_fowt.py that doesn't change anything (just moving a variable that was being rewritten to the same value inside a loop)
@lucas-carmo lucas-carmo merged commit d2c59cd into master Sep 22, 2025
14 checks passed
@lucas-carmo lucas-carmo deleted the dev branch September 23, 2025 17:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants