Skip to content

Commit daa5cf6

Browse files
authored
Merge pull request #3244 from deslaughter/tc_docs
Tight-coupling code documentation
2 parents ffdbd28 + 3964d19 commit daa5cf6

File tree

14 files changed

+2037
-565
lines changed

14 files changed

+2037
-565
lines changed

docs/source/dev/glue-code/ModVar.svg

Lines changed: 0 additions & 558 deletions
This file was deleted.

docs/source/user/general.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ of publications, presentations, and past studies on the subject.
4747
Glue Code and Mesh Mapping
4848
**************************
4949

50+
For current documentation on the glue code structure, module variable API,
51+
solver, and linearization see :ref:`glue-code`.
52+
5053
- `FAST Modular Wind Turbine CAE Tool: Nonmatching Spatial and Temporal Meshes <https://www.nrel.gov/docs/fy14osti/60742.pdf>`_
5154
- `FAST Modular Framework for Wind Turbine Simulation: New Algorithms and Numerical Examples <https://dx.doi.org/10.2514/6.2015-1461>`_
5255
- :download:`Predictor-Corrector Approach <../../OtherSupporting/ProposedPCApproach_Rev4.docx>`

docs/source/user/glue-code/ModVar.svg

Lines changed: 572 additions & 0 deletions
Loading
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
.. _glue-code:
2+
3+
Glue Code
4+
=========
5+
6+
The OpenFAST *glue code* is the layer of software that initializes each physics
7+
module, manages the flow of data between them, orchestrates the time-stepping
8+
loop, and—optionally—linearizes the assembled system. This section documents
9+
the glue code from a user and module-developer perspective.
10+
11+
.. toctree::
12+
:maxdepth: 2
13+
14+
overview
15+
modvar
16+
modglue
17+
solver
18+
linearization
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
.. _glue-code-linearization:
2+
3+
Linearization
4+
=============
5+
6+
OpenFAST can linearise the full multi-physics system about a periodic (or
7+
static) operating point to produce continuous-time, first-order state-space
8+
matrices of the form
9+
10+
.. math::
11+
12+
\dot{\mathbf{x}} &= A\,\mathbf{x} + B\,\mathbf{u} \\
13+
\mathbf{y} &= C\,\mathbf{x} + D\,\mathbf{u}
14+
15+
together with the coupling matrices *dUdu* (input-to-input feed-through) and
16+
*dUdy* (output-to-input coupling). The linearization engine lives in
17+
``modules/openfast-library/src/FAST_ModGlue.f90``.
18+
19+
.. contents::
20+
:local:
21+
:depth: 2
22+
23+
User inputs for linearization
24+
------------------------------
25+
26+
The following parameters appear in the main OpenFAST input file (``*.fst``)
27+
under the **Linearization** section.
28+
29+
.. list-table::
30+
:header-rows: 1
31+
:widths: 25 12 63
32+
33+
* - Parameter
34+
- Type
35+
- Description
36+
* - ``Linearize``
37+
- logical
38+
- Master switch. Set to ``True`` to enable all linearization
39+
functionality. When ``False`` all other linearization parameters are
40+
ignored.
41+
* - ``CalcSteady``
42+
- logical
43+
- When ``True``, OpenFAST first runs the simulation forward until the
44+
outputs at each target azimuth converge from one rotor revolution to the
45+
next (steady-state trimming), then performs linearization at each
46+
azimuth. When ``False``, linearization is performed at user-specified
47+
absolute simulation times (``LinTimes``).
48+
* - ``TrimCase``
49+
- integer
50+
- Controller degree of freedom trimmed during ``CalcSteady`` to achieve
51+
periodic steady state.
52+
53+
* ``1`` – yaw
54+
* ``2`` – generator torque
55+
* ``3`` – collective blade pitch
56+
* - ``TrimTol``
57+
- real
58+
- RMS convergence tolerance on normalised output error across one
59+
rotor revolution. Trimming stops when the error falls below this
60+
value. Typical value: ``1.0e-5``.
61+
* - ``TrimGain``
62+
- real
63+
- Proportional gain used by the built-in trim controller.
64+
Units are rad/(rad/s) for yaw/pitch cases and N·m/(rad/s) for
65+
the torque case.
66+
* - ``Twr_Kdmp``
67+
- real
68+
- Artificial tower damping coefficient (N/(m/s)) added during the
69+
``CalcSteady`` run to help damp transients and reach steady state
70+
faster. Set to 0 to disable.
71+
* - ``Bld_Kdmp``
72+
- real
73+
- Artificial blade damping coefficient (N/(m/s)) during ``CalcSteady``.
74+
* - ``NLinTimes``
75+
- integer
76+
- Number of linearization time points per rotor revolution (or number of
77+
equally spaced absolute time instants when ``CalcSteady=False``).
78+
Must be ≥ 1. For a periodic model at least 12 azimuths are typically
79+
needed to resolve the per-revolution variation.
80+
* - ``LinTimes``
81+
- real array
82+
- Absolute simulation times (seconds) at which to linearise when
83+
``CalcSteady=False``. Length must equal ``NLinTimes``. Ignored when
84+
``CalcSteady=True``.
85+
* - ``LinInputs``
86+
- integer
87+
- Controls which input variables appear in the **B** and **D** matrices.
88+
89+
* ``0`` (``LIN_NONE``) – no inputs; produces state matrix only.
90+
* ``1`` (``LIN_STANDARD``) – inputs flagged ``VF_Linearize`` by the
91+
module (default set by each module's ``InitVars``).
92+
* ``2`` (``LIN_ALL``) – all module inputs including debug ones.
93+
* - ``LinOutputs``
94+
- integer
95+
- Controls which output variables appear in the **C** and **D** matrices.
96+
97+
* ``0`` (``LIN_NONE``) – no outputs.
98+
* ``1`` (``LIN_STANDARD``) – ``WriteOutput`` channels only
99+
(``VF_WriteOut`` flag).
100+
* ``2`` (``LIN_ALL``) – all module outputs.
101+
* - ``LinOutJac``
102+
- logical
103+
- When ``True`` (requires ``LinInputs=LinOutputs=2``), the full module
104+
Jacobian matrices are written to the linearization output file for
105+
debugging.
106+
* - ``LinOutMod``
107+
- logical
108+
- When ``True``, per-module ``.lin`` files are written in addition to the
109+
full-system file.
110+
111+
Module support for linearization
112+
----------------------------------
113+
114+
Modules that appear in the linearization variable ordering (set in
115+
``ModGlue_Init``) are:
116+
117+
InflowWind → SeaState → ServoDyn → ElastoDyn → BeamDyn → AeroDyn →
118+
HydroDyn → SubDyn → MAP++ → MoorDyn
119+
120+
A module that is not in this ordered list causes a fatal error if
121+
``Linearize=True``.
122+
123+
Variable selection
124+
------------------
125+
126+
During ``ModGlue_Init``, the ``VF_Linearize`` flag is applied to variables
127+
according to the ``LinInputs`` and ``LinOutputs`` settings:
128+
129+
* **States (x)**: the ``VF_Linearize`` flag is always set on all continuous
130+
state variables of every participating module.
131+
* **Inputs (u)**:
132+
133+
* ``LIN_NONE`` → flag cleared on all input variables.
134+
* ``LIN_STANDARD`` → keeps whatever ``VF_Linearize`` flag was set in the
135+
module's ``InitVars``; module developers choose the *standard* input set.
136+
* ``LIN_ALL`` → flag set on all input variables.
137+
* Variables with ``VF_NoLin`` always have ``VF_Linearize`` cleared,
138+
regardless of the above setting.
139+
140+
* **Outputs (y)**:
141+
142+
* ``LIN_NONE`` → flag cleared on all output variables.
143+
* ``LIN_STANDARD`` → flag set only on outputs that also carry ``VF_WriteOut``.
144+
* ``LIN_ALL`` → flag set on all output variables.
145+
* Variables with ``VF_NoLin`` are always excluded.
146+
147+
The combined variable set is assembled into a ``ModGlueType`` named ``Lin``
148+
via ``ModGlue_CombineModules``.
149+
150+
Steady-state trimming (``CalcSteady``)
151+
---------------------------------------
152+
153+
When ``CalcSteady=True``, ``ModGlue_CalcSteady`` is called at each time step
154+
to detect periodicity:
155+
156+
1. The module outputs tagged ``VF_Linearize`` (excluding ``VF_WriteOut``) are
157+
collected into a buffer indexed by azimuth angle.
158+
2. After each complete revolution the outputs at each of the ``NLinTimes``
159+
azimuth targets are compared against the previous revolution via the
160+
normalised RMS error:
161+
162+
.. math::
163+
164+
\varepsilon = \sqrt{\frac{1}{N} \sum_{i=1}^{N}
165+
\left(\frac{y_i^{\rm current} - y_i^{\rm previous}}{r_i}\right)^2}
166+
167+
where :math:`r_i = \max(y_{i,\rm max} - y_{i,\rm min},\, 0.01)` is the
168+
output range from the current revolution (with a floor to avoid division
169+
by near-zero).
170+
171+
3. When :math:`\varepsilon < \texttt{TrimTol}`, ``FoundSteady=True`` and
172+
linearization at all ``NLinTimes`` azimuths proceeds automatically.
173+
174+
4. If the simulation reaches within approximately two revolutions of ``TMax``
175+
without converging, a warning is issued and linearization is forced.
176+
177+
The azimuth interpolation between buffer samples uses the extrapolation
178+
routines from ``MV_ExtrapInterp`` (supports constant, linear, and quadratic
179+
schemes depending on the number of available samples).
180+
181+
linearization at an operating point
182+
-------------------------------------
183+
184+
``ModGlue_Linearize_OP`` assembles the full-system matrices at a single
185+
operating point (time / azimuth):
186+
187+
1. **Module Jacobians**: for each module,
188+
``FAST_JacobianPInput`` and ``FAST_JacobianPContState`` are called to
189+
compute the per-module sub-matrices *dYdu*, *dXdu*, *dYdx*, *dXdx* by
190+
central-difference finite differentiation. The perturbation magnitudes are
191+
taken from each variable's ``Perturb`` field (see :ref:`glue-code-modvar`).
192+
193+
2. **Operating point extraction**: ``FAST_GetOP`` packs the current states,
194+
inputs, and outputs into the linearization arrays
195+
(``ModGlue%Lin%x``, ``%u``, ``%y``).
196+
197+
3. **Coupling matrices**: the input-output coupling matrices *dUdu* and *dUdy*
198+
are assembled from the mesh-mapping Jacobians to account for the fact that
199+
some module inputs are functions of other modules' outputs.
200+
201+
4. **Full-system assembly**: the per-module sub-matrices are placed into the
202+
combined glue-level matrices using the ``iGlu`` index ranges stored in
203+
each ``ModVarType``.
204+
205+
5. **Output**: ``ModGlue_CalcWriteLinearMatrices`` writes the ``.lin`` file
206+
containing:
207+
208+
* Operating point values (**x_op**, **u_op**, **y_op**)
209+
* linearization channel names (from ``LinNames``)
210+
* Derivative order indicators (``VF_DerivOrder1``, ``VF_DerivOrder2``)
211+
* Rotating-frame flags (``VF_RotFrame``)
212+
* Full-system matrices **A**, **B**, **C**, **D**, **dUdu**, **dUdy**
213+
* Per-module matrices (if ``LinOutMod=True``)
214+
* Full Jacobians (if ``LinOutJac=True``)
215+
216+
Output file format
217+
-------------------
218+
219+
Each linearization call produces a file named
220+
``<RootName>.<N>.lin`` where *N* is the linearization index (1 … ``NLinTimes``).
221+
The file is a plain-text ASCII file that can be read by the
222+
`openfast_io <https://github.com/OpenFAST/openfast_io>`_ Python library or the
223+
`pyFAST <https://github.com/OpenFAST/pyFAST>`_ post-processing tools.
224+
225+
Key fields in the file header:
226+
227+
* ``Rotor_Speed`` – rotor speed at linearization time (RPM)
228+
* ``Azimuth`` – blade-1 azimuth at linearization time (deg)
229+
230+
Variable naming conventions
231+
----------------------------
232+
233+
In linearization output files each channel label follows the pattern:
234+
235+
``<ModAbbr> <MeshName> <Field> [, component [, node [, unit]]]``
236+
237+
Examples:
238+
239+
* ``ED BlPitch1, rad`` – ElastoDyn individual blade-1 pitch state
240+
* ``AD B1N001Fx force, node 1, N`` – AeroDyn blade 1 node 1 X-force input
241+
* ``BD_1 B1TipTDxr translation displacement, node 10, m`` – BeamDyn instance 1
242+
243+
Module developers should ensure that the ``Name`` argument to ``MV_AddVar`` /
244+
``MV_AddMeshVar`` and the entries in ``LinNames`` follow this convention for
245+
consistency with post-processing tools.
246+
247+
Module developer responsibilities
248+
-----------------------------------
249+
250+
To participate in linearization a module must:
251+
252+
1. Call ``MV_AddVar`` / ``MV_AddMeshVar`` with appropriate ``VF_Linearize``
253+
flags and supply ``LinNames`` for all variables that may appear in the
254+
standard linearization set.
255+
256+
2. Implement ``<Mod>_JacobianPInput`` and ``<Mod>_JacobianPContState``
257+
subroutines (or supply analytical Jacobians through the registry). The
258+
glue code calls these via the ``FAST_JacobianPInput`` /
259+
``FAST_JacobianPContState`` wrappers in ``FAST_Funcs.f90``.
260+
261+
3. Implement ``<Mod>_GetOP`` (via the registry) to extract the operating-point
262+
values of states, inputs, and outputs.
263+
264+
4. Mark variables that should **not** participate in linearization with
265+
``VF_NoLin``.
266+
267+
5. Mark variables in the rotating reference frame with ``VF_RotFrame`` so that
268+
multi-blade coordinate (MBC) transformations applied by post-processing
269+
tools are aware of these variables.

0 commit comments

Comments
 (0)