Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
af019ab
KeepParallelPool (#1418)
pm-gusmano Mar 10, 2025
df67d5e
Merge pull request #1436 from WEC-Sim/main
akeeste Mar 11, 2025
b25c833
build Body from hydro structure directly (#1421)
degoeden Mar 25, 2025
8ef1c94
elevationToSpectrum.m Function Enhancements (#1423)
pm-gusmano Mar 28, 2025
2970db9
Excitation spread fix dev (#1454)
dforbush2 Apr 3, 2025
e72c915
Dev: fix badBEMIOFix_fcn (#1447)
dforbush2 Apr 3, 2025
7ded496
Variable hydro improvements (#1411)
akeeste Apr 30, 2025
21bfcfb
ParaView feature for multiple mooring connections #1440 (#1455)
kmruehl May 13, 2025
1368234
Bug fix for drag and nonhydro body block mass (#1464)
akeeste May 13, 2025
b504699
QTF Standing (Newman) Approximation (#1461)
MShabara May 15, 2025
382828b
Enable Variable Mass (#1465)
jtgrasb May 15, 2025
cbe1ee7
Fix mask for flex body (#1468)
jtgrasb May 15, 2025
e8b3602
Merge branch 'main' of https://github.com/WEC-Sim/WEC-Sim into dev
jtgrasb May 15, 2025
f6595e2
Bug fix in BodyClass and minor change in BEMIO (#1472)
MShabara May 16, 2025
6df131e
Radiation damping load extrapolation (#1476)
TianyuanWangi May 21, 2025
afeb73d
Modified sign convention when a cable pretension is defined (#1478)
ttran18 May 30, 2025
d6d87e1
Pulling bugfix PR #1473 into dev (#1480)
kmruehl May 30, 2025
6841be8
Update variable mass implementation and add documentation (#1494)
jtgrasb Jul 8, 2025
448b115
bug fix for nonhydro and drag body mass (#1499)
akeeste Jul 8, 2025
af272a1
Irregular CIC test for OSWEC (#1484)
jleonqu Jul 11, 2025
a18a614
Body Library Refactoring (#1474)
akeeste Jul 16, 2025
88ff32c
Refactor badBemioFix_fcn (#1489)
akeeste Jul 23, 2025
0839dcf
Adds the QTF rotations feature (#1511)
MShabara Jul 23, 2025
97c44e3
Universal PTO joint (#1466)
akeeste Jul 24, 2025
440b635
`waveClass` Constructor Improvements (#1515)
pm-gusmano Jul 28, 2025
5b3f21b
Updated MOST source code (#1470)
akeeste Jul 28, 2025
307a6d3
add rate transition for extrapFrad (#1518)
akeeste Jul 30, 2025
40fb6a4
OSWEC Test Case - Irregular Waves (#1516)
jleonqu Jul 30, 2025
3afabae
clear extra most variant subsystem variables in stopwecsim
akeeste Aug 6, 2025
7c3623f
Fixes a bug with the linear force calc within the nonlinear FK (#1527)
MShabara Aug 8, 2025
2d4703f
Fix spread NL (#1528)
jtgrasb Aug 8, 2025
95ee73f
fix paraview waves (#1525)
jtgrasb Aug 8, 2025
d8a113f
[BUG] Add back MoorDyn blocks (removed by #1470) (#1522)
jtgrasb Aug 9, 2025
54e974a
Fix for the elevation plot when multiple wave classes are defined (#1…
MShabara Aug 13, 2025
a118f28
merge main into dev
akeeste Aug 13, 2025
2723da1
fix bug in flex body mask (#1536)
akeeste Aug 20, 2025
eddcfd2
Fix wave current velocity (#1540)
akeeste Aug 23, 2025
7750c09
update version numbers in conf.py, simulationClass.m
akeeste Aug 25, 2025
c5d3ac1
Merge pull request #1541 from WEC-Sim/dev
akeeste Aug 25, 2025
6486308
update matlab versions tested
akeeste Feb 5, 2026
5e5d1c5
add r2021a test
akeeste Feb 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ _What file(s) cause the error? Identify the WEC-Sim file(s) that cause the error
_How can we reproduce the error? Describe the steps to reproduce the error._

**Expected behavior**
_What is the excepeted behavior? Describe the expected behavior._
_What is the expected behavior? Describe the expected behavior._

**Screenshots:**
_Provide relevant screenshots to help explain the problem. For example, a screenshot of the error message from the MATLAB command window._
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/run-tests-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-22.04, windows-latest]
release: [R2023a, R2023b, R2024a, R2024b]
release: [R2020b, R2021a, R2021b, R2022a, R2024b]
name: ${{ matrix.release }} on ${{ matrix.os }}
steps:
- name: Check out repository
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ examples/**/**/*.png
!/tests/**/**/regularSS_org.mat
!/tests/**/**/irregularSS_org.mat
!/tests/**/**/irregularCIC_org.mat
!/tests/**/**/irregularSpread_OSWEC_org.mat
!/tests/**/**/RegYaw_org.mat
!/tests/**/**/IrrYaw_org.mat

Expand Down
68 changes: 51 additions & 17 deletions docs/_include/added_mass.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ shown in the manipulation of the governing equation below:

.. math::

M\ddot{X_i} &= \Sigma F(t,\omega) - A\ddot{X_i} \\
(M+A)\ddot{X_i} &= \Sigma F(t,\omega) \\
M_{adjusted}\ddot{X_i} &= \Sigma F(t,\omega)
M\ddot{X_i} &= \Sigma F(t,\omega) + m\overrightarrow{g} - A\ddot{X_i} \\
(M+A)\ddot{X_i} &= \Sigma F(t,\omega) + m\overrightarrow{g} \\
M_{adjusted}\ddot{X_i} &= \Sigma F(t,\omega) + m\overrightarrow{g}

where :math:`F_{am} = -A\ddot{X_i}` is the added mass component of the radiation force that is pulled out of the force summation for manipulation,
:math:`M` is the mass matrix, :math:`A` is the single frequency or infinite frequency added mass, and subscript :math:`i` represents the timestep being solved for.
Expand All @@ -42,6 +42,10 @@ The core issue with this combined mass formulation is that Simscape Multibody, a
For example, a rigid body can't have one mass for surge motion and another mass for heave motion.
Simscape rigid bodies only have one translational mass, a 1x3 moment of inertia matrix, and 1x3 product of inertia matrix.

Note that the body mass used to define the gravitational force is not adjusted as gravity does not act on any added mass contributions.
The gravity force will always depend on the unadjusted body mass.
The gravity force is lumped with the sum of remaining forces in the rest of this section for simplicity.

WEC-Sim's Implementation
^^^^^^^^^^^^^^^^^^^^^^^^^

Expand All @@ -54,7 +58,7 @@ There is a 1-1 mapping between the body's inertia tensor and rotational added ma
These added mass coefficients are entirely lumped with the body's inertia.
Additionally, the surge-surge (1,1), sway-sway (2,2), heave-heave (3,3) added mass coefficients correspond to the translational mass of the body, but must be treated identically.

WEC-Sim implements this added mass treatment by adding a change in mass matrix ($$dM$$) to both sides of the equation, creating both a modified added mass matrix and a modified body mass matrix:
WEC-Sim implements this added mass treatment by adding a change in mass matrix (:math:`dM`) to both sides of the equation, creating both a modified added mass matrix and a modified body mass matrix:

.. math::

Expand Down Expand Up @@ -105,7 +109,7 @@ The resultant definition of the body mass matrix and added mass matrix are then:
Though the components of added mass and body mass are manipulated in WEC-Sim, the total system is unchanged.
This manipulation does not affect the governing equations of motion, only the implementation.

The fraction of translational added mass that is moved into the body mass is determined by ``body(iBod).adjMassFactor``, whose default value is :math:`2.0`.
The scale of translational added mass that is moved into the body mass is determined by ``body(iBod).adjMassFactor``, whose default value is :math:`2.0`.
Advanced users may change this weighting factor in the ``wecSimInuptFile`` to create the most robust simulation possible.
To see its effects, set ``body(iB).adjMassFactor = 0`` and see if simulations become unstable.

Expand All @@ -121,12 +125,7 @@ This will convert the algebraic loop equation of motion to a solvable one:
M_{adjusted}\ddot{X_i} &= \Sigma F(t,\omega) - A_{adjusted}\ddot{X}_{i - (1 - 10^{-7}/dt)} \\

Body-to-body Interactions
"""""""""""""""""""""""""""
F = A * acc
first dimension/index = down, 2nd = across
non b2b: A = [6x6], acc = [6x1],
b2b: A = [6x12], acc = [12x1] in order of body numbers regardless of the current body number

""""""""""""""""""""""""""
The above implementation extends readily to the case where there are body interactions to account for.
In this example, we assume there are two bodies with body interaction.
Then the right hand side added mass and acceleration matrices above are (without generalized modes)
Expand All @@ -152,12 +151,47 @@ Working with the Added Mass Implementation
"""""""""""""""""""""""""""""""""""""""""""

WEC-Sim's added mass implementation should not affect a user's modeling workflow.
WEC-Sim handles the manipulation and restoration of the mass and forces in the bodyClass functions ``adjustMassMatrix()`` called by ``initializeWecSim`` and ``restoreMassMatrix``, ``storeForceAddedMass`` called by ``postProcessWecSim``.
However viewing ``body.mass, body.inertia, body,inertiaProducts, body.hydroForce.hf*.fAddedMass`` between calls to ``initializeWecSim`` and ``postProcessWecSim`` will not show the input file definitions.
Users can get the manipulated mass matrix, added mass coefficients, added mass force and total force from ``body.hydroForce.hf*.storage`` after the simulation.
However, in the rare case that a user wants to manipulate the added mass force *during* a simulation, the change in mass, :math:`dM` above, must be taken into account. Refer to how ``body.calculateForceAddedMass()`` calculates the entire added mass force in WEC-Sim post-processing.

.. Note:: If applying the method in ``body.calculateForceAddedMass()`` *during* the simulation, the negative of ``dM`` must be taken: :math:`dM = -dM`. This must be accounted for because the definitions of mass, inertia, etc and their stored values are flipped between simulation and post-processing.
WEC-Sim handles the manipulation and restoration of the mass and forces in the bodyClass functions ``bodyClass.adjustMassMatrix()`` called by ``initializeWecSim`` and ``bodyClass.restoreMassMatrix()``, ``bodyClass.storeForceAddedMass()`` called by ``postProcessWecSim``.
However viewing ``body.hydroForce.hf*.fAddedMass`` between calls to ``initializeWecSim`` and ``postProcessWecSim`` will not show the values from the BEM dataset.
See the following table for the variables containing both unadjusted and adjusted parameters after the simulation:

.. list-table:: Nominal and adjusted mass parameters
:widths: 25 37 37
:header-rows: 1

* - Parameter
- Nominal value
- Adjusted value
* - Mass
- ``body.mass``, ``body.hydroForce.hf*.mass``, ``body.variableHydro.mass``
- ``body.hydroForce.hf*.adjustedMass``
* - Inertia
- ``body.inertia``, ``body.variableHydro.inertia``
- ``body.hydroForce.hf*.adjustedInertia``
* - Inertia Products
- ``body.inertiaProducts``, ``body.variableHydro.inertiaProducts``
- ``body.hydroForce.hf*.adjustedInertiaProducts``
* - Added mass coefficients
- ``body.hydroForce.hf*.hydroForce_fAddedMass``
- ``body.hydroForce.hf*.storage.hydroForce_fAddedMass``
* - Added mass force timeseries
- ``output.bodies(*).forceAddedMass``
- ``body.hydroForce.hf*.storage.output_forceAddedMass``
* - Total force timeseries
- ``output.bodies(*).forceTotal``
- ``body.hydroForce.hf*.storage.output_forceTotal``

The nominal (*unadjusted*) body mass is stored in ``body.hydroForce.hf*.mass``.
This nominal value is retained during the simulation because it is required for the calculation of the gravitational force.
However, in the case that a user wants to view the added mass force *during* a simulation (typically during debugging in a failed simulation),
the change in mass, :math:`dM` above, must be taken into account.
Refer to how ``body.calculateForceAddedMass()`` calculates the entire added mass force in WEC-Sim post-processing.

When using variable hydrodynamics, the added mass matrix and mass matrix can change with the varying state.
In the above derivation, all values of :math:`dM`, mass matrix, inertia matrix, added mass force, and the resultant
adjusted mass and added mass matrices are calculated for each hydrodynamic dataset.
Note that varying any part of the body mass matrix with variable hydro requires using a special simscape block.
Refer to the variable hydrodynamics applications.

.. Note::
Depending on the wave formulation used, :math:`A` can either be a function of wave frequency :math:`A(\omega)`, or equal to the added mass at infinite wave frequency :math:`A_{\infty}`
5 changes: 4 additions & 1 deletion docs/_include/mooring.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,10 @@ lines and each line may have multiple nodes. The number of MoorDyn lines and nod
each line should be defined as (``mooring(i).moorDynLines = <Number of mooring lines>``)
and (``mooring(i).moorDynNodes(iLine) = <Number of mooring nodes in line>`` - only used
for ParaView visualization), respectively and should match the number of lines and nodes
specified in the MoorDyn input file.
specified in the MoorDyn input file. The order of the lines should also be the same
between the WEC-Sim and MoorDyn input files (i.e., for a model with two MoorDyn
connections, all lines corresponding to ``mooring(1)`` should be defined in the
MoorDyn input file before the lines for ``mooring(2)``).

A mooring folder that includes a MoorDyn input file (``lines.txt``) is required
in the simulation folder. The body and corresponding mooring attachment points are
Expand Down
11 changes: 6 additions & 5 deletions docs/_include/pto.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,15 @@ these limits if an inadequate spring and/or damping coefficient is specified,
acting instead as a soft motion constraint. More detail on this implementation
can be found in the `Simscape documentation <https://www.mathworks.com/help/physmod/sm/ref/prismaticjoint.html#mw_316368a1-4b9e-4cfb-86e0-9abdd0c4d7a8>`_.
To specify joint or actuation stroke limits for a PTO, the following parameters
must be specified in ``wecSimInputFile.m``
must be specified in ``wecSimInputFile.m``::

:code: `pto(i).hardStops.upperLimitSpecify = 'on'`
:code: `pto(i).hardStops.lowerLimitSpecify = 'on'`
pto(i).hardStops.upperLimitSpecify = 'on'
pto(i).hardStops.lowerLimitSpecify = 'on'

to enable upper and lower stroke limits, respectively. The specifics of the

The specifics of the
limit and the acting forces at the upper and lower limits are described in turn
by
by::

pto(i).hardStops.upperLimitBound
pto(i).hardStops.upperLimitStiffness
Expand Down
51 changes: 49 additions & 2 deletions docs/_include/variable_hydro.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ User defined logic and user selected signals determine
when the state changes. The Variable Hydrodynamics feature does not determine
a specific scenario, state, signal, or discretization required.

For a case which varies the mass of the body, the body library link in the Simulink
model will need to be broken and the default File Solid : Body Properties block
replaced with the General Variable Mass block. See the variable hydro WEC-Sim
Application.

Example
""""""""

Expand Down Expand Up @@ -58,7 +63,17 @@ every body in a simulation. To implement variable hydrodynamics for a given body
``body(1) = bodyClass({'H5FILE_1.h5','H5FILE_2.h5','H5FILE_3.h5','H5FILE_4.h5','H5FILE_5.h5');``

If only one H5 file is used to initialize a body object, variable hydrodynamics
will not be used, regardless of the ``option`` flag below.
will not be used, regardless of the ``option`` flag below.

For variable mass cases, a vector can also be used for the variable hydrodynamics mass,
inertia, and inertia products:

``body(1).variableHydro.mass = [mass1, mass2, mass3, mass4, mass5];``

If no mass vector is specified but ``body(1).mass`` is set to equilibrium, the data from H5
files will be used to calculate the variable mass based on displaced volume and water density.
However, the full inertia vector (``body(1).variableHydro.inertia``) will still need to be
specified or else it will be assumed to be constant and equal to ``body(1).inertia``.

2. Enable Variable Hydrodynamics
Set the ``body.variableHydro.option`` flag to enable variable hydrodynamics:
Expand Down Expand Up @@ -108,7 +123,39 @@ every body in a simulation. To implement variable hydrodynamics for a given body
* FIR Filter radiation calculations
* Generalized body modes
* Non-hydrodynamic and drag bodies
* Conditions that require a variable mass, center of gravity, or center of buoyancy
* Nonlinear hydrodynamics is not compatible when using a case with variable mass.

Impulse Response Function with Variable Hydrodynamics
"""""""""""""""""""""""""""""""""""""""""""""""""""""
The convolution integral formulation of the radiation force is typically defined by

.. math::

F_{rad}(t)=-A_{\infty}\ddot{X}-\intop_{0}^{t}K_{r}(t-\tau)\dot{X}(\tau)d\tau

The :ref:`cic_theory` section gives additional details on this representation of the radiation force.
Note that :math:`K_r` is a function of time and can change as the state varies when using variable hydrodynamics.
For example, if the state switches from "A" to "B" between times :math:`t_1, t_2`, then :math:`K_r(t-t_1)=K_{r,A}(t-t_1)` is from a different hydrodynamic dataset
than :math:`K_{r,B}(t-t_2)`. To account for this change in the impulse response function history, a surface of IRF coefficients is created and
stored in ``body.variableHydro.radiationIrfSurface``.
This 4D surface has dimensionsions of time, influenced degree of freedom, radiating degree of freedom, and varying state.
At each time step, ``convolutionIntegralSurface`` is called to evaluate the radiation force.
The time history of the varying state's index is used to select the appropriate :math:`K_r` coefficients given the time and state at that time.
The resulting 3D surface is then convolved with the velocity history and summed across the radiating degrees of freedom to give the radiation force at that time.

The two figures below show an example of how the radiation IRF varies across a state for the case of a single heaving cube whose base opens and closes.
The flaps of the base split in half and are fully closed at 0 degrees and fully open at 90 degrees.
The contour of IRF surface in heave illustrates how significantly the IRF coefficients can change with a varying state.

.. figure:: /_static/images/variable_hydro_irf.png
:width: 500pt
:figwidth: 500pt
:align: center

.. figure:: /_static/images/variable_hydro_irf_surface.png
:width: 500pt
:figwidth: 500pt
:align: center

Application
""""""""""""
Expand Down
Binary file modified docs/_static/images/WEC-Sim_Lib_pto.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/images/variable_hydro_irf.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
# built documents.
#
# The short X.Y version.
version = 'v6.1.2'
version = 'v7.0.0'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
4 changes: 2 additions & 2 deletions docs/developer/advanced_features.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ structure:

* ``h5File``
* Instead of initializing the body class with one string
(one H5 file name), a cell array of strings can be passed, e.g.
* body(1) = bodyClass({'H5FILE_1.h5','H5FILE_2.h5','H5FILE_3.h5');
(one H5 file name), a cell array of strings can be passed, e.g
``body(1) = bodyClass({'H5FILE_1.h5','H5FILE_2.h5','H5FILE_3.h5');``
* ``hydroData``
* Each H5 file is processed into a hydroData structure. All structs are
concatenated into ``hydroData`` which is now an array of structures instead
Expand Down
Loading
Loading