-
Notifications
You must be signed in to change notification settings - Fork 530
Tight-coupling code documentation #3244
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| .. _glue-code: | ||
|
|
||
| Glue Code | ||
| ========= | ||
|
|
||
| The OpenFAST *glue code* is the layer of software that initializes each physics | ||
| module, manages the flow of data between them, orchestrates the time-stepping | ||
| loop, and—optionally—linearizes the assembled system. This section documents | ||
| the glue code from a user and module-developer perspective. | ||
|
|
||
| .. toctree:: | ||
| :maxdepth: 2 | ||
|
|
||
| overview | ||
| modvar | ||
| modglue | ||
| solver | ||
| linearization | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,269 @@ | ||
| .. _glue-code-linearization: | ||
|
|
||
| Linearization | ||
| ============= | ||
|
|
||
| OpenFAST can linearise the full multi-physics system about a periodic (or | ||
| static) operating point to produce continuous-time, first-order state-space | ||
| matrices of the form | ||
|
|
||
| .. math:: | ||
|
|
||
| \dot{\mathbf{x}} &= A\,\mathbf{x} + B\,\mathbf{u} \\ | ||
| \mathbf{y} &= C\,\mathbf{x} + D\,\mathbf{u} | ||
|
|
||
| together with the coupling matrices *dUdu* (input-to-input feed-through) and | ||
| *dUdy* (output-to-input coupling). The linearization engine lives in | ||
| ``modules/openfast-library/src/FAST_ModGlue.f90``. | ||
|
|
||
| .. contents:: | ||
| :local: | ||
| :depth: 2 | ||
|
|
||
| User inputs for linearization | ||
| ------------------------------ | ||
|
|
||
| The following parameters appear in the main OpenFAST input file (``*.fst``) | ||
| under the **Linearization** section. | ||
|
|
||
| .. list-table:: | ||
| :header-rows: 1 | ||
| :widths: 25 12 63 | ||
|
|
||
| * - Parameter | ||
| - Type | ||
| - Description | ||
| * - ``Linearize`` | ||
| - logical | ||
| - Master switch. Set to ``True`` to enable all linearization | ||
| functionality. When ``False`` all other linearization parameters are | ||
| ignored. | ||
| * - ``CalcSteady`` | ||
| - logical | ||
| - When ``True``, OpenFAST first runs the simulation forward until the | ||
| outputs at each target azimuth converge from one rotor revolution to the | ||
| next (steady-state trimming), then performs linearization at each | ||
| azimuth. When ``False``, linearization is performed at user-specified | ||
| absolute simulation times (``LinTimes``). | ||
| * - ``TrimCase`` | ||
| - integer | ||
| - Controller degree of freedom trimmed during ``CalcSteady`` to achieve | ||
| periodic steady state. | ||
|
|
||
| * ``1`` – yaw | ||
| * ``2`` – generator torque | ||
| * ``3`` – collective blade pitch | ||
| * - ``TrimTol`` | ||
| - real | ||
| - RMS convergence tolerance on normalised output error across one | ||
| rotor revolution. Trimming stops when the error falls below this | ||
| value. Typical value: ``1.0e-5``. | ||
| * - ``TrimGain`` | ||
| - real | ||
| - Proportional gain used by the built-in trim controller. | ||
| Units are rad/(rad/s) for yaw/pitch cases and N·m/(rad/s) for | ||
| the torque case. | ||
| * - ``Twr_Kdmp`` | ||
| - real | ||
| - Artificial tower damping coefficient (N/(m/s)) added during the | ||
| ``CalcSteady`` run to help damp transients and reach steady state | ||
| faster. Set to 0 to disable. | ||
| * - ``Bld_Kdmp`` | ||
| - real | ||
| - Artificial blade damping coefficient (N/(m/s)) during ``CalcSteady``. | ||
| * - ``NLinTimes`` | ||
| - integer | ||
| - Number of linearization time points per rotor revolution (or number of | ||
| equally spaced absolute time instants when ``CalcSteady=False``). | ||
| Must be ≥ 1. For a periodic model at least 12 azimuths are typically | ||
| needed to resolve the per-revolution variation. | ||
| * - ``LinTimes`` | ||
| - real array | ||
| - Absolute simulation times (seconds) at which to linearise when | ||
| ``CalcSteady=False``. Length must equal ``NLinTimes``. Ignored when | ||
| ``CalcSteady=True``. | ||
| * - ``LinInputs`` | ||
| - integer | ||
| - Controls which input variables appear in the **B** and **D** matrices. | ||
|
|
||
| * ``0`` (``LIN_NONE``) – no inputs; produces state matrix only. | ||
| * ``1`` (``LIN_STANDARD``) – inputs flagged ``VF_Linearize`` by the | ||
| module (default set by each module's ``InitVars``). | ||
| * ``2`` (``LIN_ALL``) – all module inputs including debug ones. | ||
| * - ``LinOutputs`` | ||
| - integer | ||
| - Controls which output variables appear in the **C** and **D** matrices. | ||
|
|
||
| * ``0`` (``LIN_NONE``) – no outputs. | ||
| * ``1`` (``LIN_STANDARD``) – ``WriteOutput`` channels only | ||
| (``VF_WriteOut`` flag). | ||
| * ``2`` (``LIN_ALL``) – all module outputs. | ||
| * - ``LinOutJac`` | ||
| - logical | ||
| - When ``True`` (requires ``LinInputs=LinOutputs=2``), the full module | ||
| Jacobian matrices are written to the linearization output file for | ||
| debugging. | ||
| * - ``LinOutMod`` | ||
| - logical | ||
| - When ``True``, per-module ``.lin`` files are written in addition to the | ||
| full-system file. | ||
|
|
||
| Module support for linearization | ||
| ---------------------------------- | ||
|
|
||
| Modules that appear in the linearization variable ordering (set in | ||
| ``ModGlue_Init``) are: | ||
|
|
||
| InflowWind → SeaState → ServoDyn → ElastoDyn → BeamDyn → AeroDyn → | ||
| HydroDyn → SubDyn → MAP++ → MoorDyn | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does ExtPtfm now support linearization as well? |
||
|
|
||
| A module that is not in this ordered list causes a fatal error if | ||
| ``Linearize=True``. | ||
|
|
||
| Variable selection | ||
| ------------------ | ||
|
|
||
| During ``ModGlue_Init``, the ``VF_Linearize`` flag is applied to variables | ||
| according to the ``LinInputs`` and ``LinOutputs`` settings: | ||
|
|
||
| * **States (x)**: the ``VF_Linearize`` flag is always set on all continuous | ||
| state variables of every participating module. | ||
| * **Inputs (u)**: | ||
|
|
||
| * ``LIN_NONE`` → flag cleared on all input variables. | ||
| * ``LIN_STANDARD`` → keeps whatever ``VF_Linearize`` flag was set in the | ||
| module's ``InitVars``; module developers choose the *standard* input set. | ||
| * ``LIN_ALL`` → flag set on all input variables. | ||
| * Variables with ``VF_NoLin`` always have ``VF_Linearize`` cleared, | ||
| regardless of the above setting. | ||
|
|
||
| * **Outputs (y)**: | ||
|
|
||
| * ``LIN_NONE`` → flag cleared on all output variables. | ||
| * ``LIN_STANDARD`` → flag set only on outputs that also carry ``VF_WriteOut``. | ||
| * ``LIN_ALL`` → flag set on all output variables. | ||
| * Variables with ``VF_NoLin`` are always excluded. | ||
|
|
||
| The combined variable set is assembled into a ``ModGlueType`` named ``Lin`` | ||
| via ``ModGlue_CombineModules``. | ||
|
|
||
| Steady-state trimming (``CalcSteady``) | ||
| --------------------------------------- | ||
|
|
||
| When ``CalcSteady=True``, ``ModGlue_CalcSteady`` is called at each time step | ||
| to detect periodicity: | ||
|
|
||
| 1. The module outputs tagged ``VF_Linearize`` (excluding ``VF_WriteOut``) are | ||
| collected into a buffer indexed by azimuth angle. | ||
| 2. After each complete revolution the outputs at each of the ``NLinTimes`` | ||
| azimuth targets are compared against the previous revolution via the | ||
| normalised RMS error: | ||
|
|
||
| .. math:: | ||
|
|
||
| \varepsilon = \sqrt{\frac{1}{N} \sum_{i=1}^{N} | ||
| \left(\frac{y_i^{\rm current} - y_i^{\rm previous}}{r_i}\right)^2} | ||
|
|
||
| where :math:`r_i = \max(y_{i,\rm max} - y_{i,\rm min},\, 0.01)` is the | ||
| output range from the current revolution (with a floor to avoid division | ||
| by near-zero). | ||
|
|
||
| 3. When :math:`\varepsilon < \texttt{TrimTol}`, ``FoundSteady=True`` and | ||
| linearization at all ``NLinTimes`` azimuths proceeds automatically. | ||
|
|
||
| 4. If the simulation reaches within approximately two revolutions of ``TMax`` | ||
| without converging, a warning is issued and linearization is forced. | ||
|
|
||
| The azimuth interpolation between buffer samples uses the extrapolation | ||
| routines from ``MV_ExtrapInterp`` (supports constant, linear, and quadratic | ||
| schemes depending on the number of available samples). | ||
|
|
||
| linearization at an operating point | ||
| ------------------------------------- | ||
|
|
||
| ``ModGlue_Linearize_OP`` assembles the full-system matrices at a single | ||
| operating point (time / azimuth): | ||
|
|
||
| 1. **Module Jacobians**: for each module, | ||
| ``FAST_JacobianPInput`` and ``FAST_JacobianPContState`` are called to | ||
| compute the per-module sub-matrices *dYdu*, *dXdu*, *dYdx*, *dXdx* by | ||
| central-difference finite differentiation. The perturbation magnitudes are | ||
| taken from each variable's ``Perturb`` field (see :ref:`glue-code-modvar`). | ||
|
|
||
| 2. **Operating point extraction**: ``FAST_GetOP`` packs the current states, | ||
| inputs, and outputs into the linearization arrays | ||
| (``ModGlue%Lin%x``, ``%u``, ``%y``). | ||
|
|
||
| 3. **Coupling matrices**: the input-output coupling matrices *dUdu* and *dUdy* | ||
| are assembled from the mesh-mapping Jacobians to account for the fact that | ||
| some module inputs are functions of other modules' outputs. | ||
|
|
||
| 4. **Full-system assembly**: the per-module sub-matrices are placed into the | ||
| combined glue-level matrices using the ``iGlu`` index ranges stored in | ||
| each ``ModVarType``. | ||
|
|
||
| 5. **Output**: ``ModGlue_CalcWriteLinearMatrices`` writes the ``.lin`` file | ||
| containing: | ||
|
|
||
| * Operating point values (**x_op**, **u_op**, **y_op**) | ||
| * linearization channel names (from ``LinNames``) | ||
| * Derivative order indicators (``VF_DerivOrder1``, ``VF_DerivOrder2``) | ||
| * Rotating-frame flags (``VF_RotFrame``) | ||
| * Full-system matrices **A**, **B**, **C**, **D**, **dUdu**, **dUdy** | ||
| * Per-module matrices (if ``LinOutMod=True``) | ||
| * Full Jacobians (if ``LinOutJac=True``) | ||
|
|
||
| Output file format | ||
| ------------------- | ||
|
|
||
| Each linearization call produces a file named | ||
| ``<RootName>.<N>.lin`` where *N* is the linearization index (1 … ``NLinTimes``). | ||
| The file is a plain-text ASCII file that can be read by the | ||
| `openfast_io <https://github.com/OpenFAST/openfast_io>`_ Python library or the | ||
| `pyFAST <https://github.com/OpenFAST/pyFAST>`_ post-processing tools. | ||
|
|
||
| Key fields in the file header: | ||
|
|
||
| * ``Rotor_Speed`` – rotor speed at linearization time (RPM) | ||
| * ``Azimuth`` – blade-1 azimuth at linearization time (deg) | ||
|
|
||
| Variable naming conventions | ||
| ---------------------------- | ||
|
|
||
| In linearization output files each channel label follows the pattern: | ||
|
|
||
| ``<ModAbbr> <MeshName> <Field> [, component [, node [, unit]]]`` | ||
|
|
||
| Examples: | ||
|
|
||
| * ``ED BlPitch1, rad`` – ElastoDyn individual blade-1 pitch state | ||
| * ``AD B1N001Fx force, node 1, N`` – AeroDyn blade 1 node 1 X-force input | ||
| * ``BD_1 B1TipTDxr translation displacement, node 10, m`` – BeamDyn instance 1 | ||
|
|
||
| Module developers should ensure that the ``Name`` argument to ``MV_AddVar`` / | ||
| ``MV_AddMeshVar`` and the entries in ``LinNames`` follow this convention for | ||
| consistency with post-processing tools. | ||
|
|
||
| Module developer responsibilities | ||
| ----------------------------------- | ||
|
|
||
| To participate in linearization a module must: | ||
|
|
||
| 1. Call ``MV_AddVar`` / ``MV_AddMeshVar`` with appropriate ``VF_Linearize`` | ||
| flags and supply ``LinNames`` for all variables that may appear in the | ||
| standard linearization set. | ||
|
|
||
| 2. Implement ``<Mod>_JacobianPInput`` and ``<Mod>_JacobianPContState`` | ||
| subroutines (or supply analytical Jacobians through the registry). The | ||
| glue code calls these via the ``FAST_JacobianPInput`` / | ||
| ``FAST_JacobianPContState`` wrappers in ``FAST_Funcs.f90``. | ||
|
|
||
| 3. Implement ``<Mod>_GetOP`` (via the registry) to extract the operating-point | ||
| values of states, inputs, and outputs. | ||
|
|
||
| 4. Mark variables that should **not** participate in linearization with | ||
| ``VF_NoLin``. | ||
|
|
||
| 5. Mark variables in the rotating reference frame with ``VF_RotFrame`` so that | ||
| multi-blade coordinate (MBC) transformations applied by post-processing | ||
| tools are aware of these variables. | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would this documentation better fit under "Developer Documentation". As it is now, it is a mix of developer and user documentation, but mostly developer documentation.