Implementation of generalized support structures in AeroDyn - #3311
Conversation
…match the existing tower model setup
…continuities) and blend member fields Several fixes to the generalized support structure (GS) influence models in AeroDyn, developed and validated today against the QuadRotor case: 1. Separate potential-flow and shadow contributions. CalculateGSInfluence now returns v_pot and v_shad independently instead of a single merged vector. This fixes (a) double-counting when both models are active (a single member gave v + |v|), and (b) a coordinate-dependent root-sum-square that destroyed the sign of the streamwise deficit and scrambled the transverse direction (dip appeared as a speed-up at the wrong azimuth). Shadow is now RSS of the signed local-frame deficit magnitudes applied along the vector-sum direction (frame independent). 2. Fix a spurious deep (~68%) deficit on the upwind rotor. In GSInfl_NearestPoint the axial offset was forced to zbar=0 at interior junctions and the axial direction used the point-mesh identity instead of the member axis, so the wide center column members injected a full doublet deficit ~190 m past their ends. The true zbar and member-axis z_hat are now used, so the abs(zbar)<1 guard correctly suppresses members the blade node is axially past. 3. Remove step-like discontinuities in the induced velocity. Apply the same cosine-squared taper as TwrInfl_NearestPoint at every GS member end (junction or free end), so each finite member's field decays smoothly (C1: zero value and slope) to zero at |zbar|=1 instead of switching on/off. 4. Replace the linear superposition of per-member potential-flow contributions with an influence-weighted partition-of-unity blend, V = sum_i w_i v_i / sum_i w_i, w_i = |v_i|^p (p = GSBlendExp = 6). Summing potential-flow solutions over-counts the induced velocity where members meet, producing a sharp junction notch. The blend is a convex combination, so it never exceeds the strongest single member (no double-counting), reduces to the single-member result in isolation, and requires no structure-topology logic. p=6 is the smallest even exponent that makes the weight (v.v)^(p/2) a polynomial (C-infinity) while keeping the worst-case collinear-joint dip below 5%. Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
F/ad gs 1
Move GSPotent, GSShadow, and GSAero from AD_InputFile into the GSInputFile registry type and read them directly in Init_GSParam, replacing the hardcoded baseline/Powles/noVIV defaults that made option 2 (Bak/Eames), GSShadow_none, and disabling GSAero unreachable. Update the input parser, SetParameters, CompAeroMaps override, and input validation to reference InputFileData%GS%*, and regenerate AeroDyn_Types. Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
…wake Document that the generalized support structure (GS) influence is not applied to the sector-averaged inflow (SetSectAvgInflow) or the OLAF/FVW wake wind (SetInputsForFVW), since there is no array/scalar GSInflArray analogous to TwrInflArray. Also clarify the GSInfl_NearestPoint option-2 nearest-node comment for curved/deflected members. Comments only; no behavior change. Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
The blade-node clearance output (BNClrnc) previously overwrote the tower clearance with the GS clearance when both influence models were active. Combine them so the output reports the minimum clearance across whichever models are active, keyed off array allocation (each clearance array is allocated only when its model is on). Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
- Store the nearest-member GS clearance in m%GSClrnc so the blade-node Clrnc output is populated; previously GSInfl passed a local scalar that was never written to m%GSClrnc and only held the last member's value - Reduce clearance as the minimum over all GS members (independent of DisturbInflow), matching the AeroDyn_IO reducer that reports the smallest tower/GS clearance - Remove dead commented-out outer member loops and dedent the bodies of GSInfl_NearestLine2Element and GSInfl_NearestPoint (both are called one member at a time) - Drop redundant iMem_min and merge the two associate blocks in GSInfl_NearestPoint; fix its defensive fallback to reference the passed-in member - Update the GSClrnc registry/type comment to reference the nearest GS member instead of the tower Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
…nd GSMotion meshes when SubDyn is not used.
Document the GSPotent/GSShadow/GSAero options and the GENERAL SUPPORT STRUCTURE joint/member input tables, including the MHK vertical-coordinate (MSL) datum convention and coupling behavior with SubDyn and the ElastoDyn platform. Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Claude <noreply@anthropic.com>
Document the tower potential-flow (TwrPotent baseline and Bak) and shadow (Powles, Eames) models, their superposition, and the tower-end handling (clearance-based exclusion capsule and cosine-squared axial taper). Clarify that the coordinate-scaling taper is exact cos^2 only for potential flow and note that the tower-shadow end treatment will be improved in the future. Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
Document the GS influence models as an extension of the tower models: per-member potential-flow and shadow evaluation reusing the tower expressions and end handling. Explain the rationale for the influence-weighted partition-of-unity combination of per-member potential-flow contributions (avoids joint double-counting, topology-free, reduces to the single-member/tower result) and the root-sum-square combination of shadow deficits. Note that the wake model may be unsuitable for strongly raked members and is expected to be improved to align the wake with the incident wind direction in the future. Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
Write the GS point mesh (with GSLoad drag force vectors as point data) in WrVTK_AllMeshes (VTK_Type=3). A single copy is written for the shared GS structure to avoid duplication in multirotor cases. Deferred from VTK_Type=1/2 and from driver VTK output until proper line-mesh visualization is added, to align with SubDyn. Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Claude <noreply@anthropic.com>
Add theory-manual sections for the tower cross-flow drag load (TwrAero) and the generalized support-structure drag load (GSAero), including the drag-force formulation, the point-mesh lumping used for the GS load, and a note that the GS provides drag only (buoyancy, added mass, and fluid inertia belong in HydroDyn) with a caution against double-counting drag between AeroDyn and HydroDyn. Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces a generalized support-structure (GS) capability in AeroDyn, enabling support-member drag loads and support-member influence/shadow effects on rotor inflow, with coupling/mapping handled between AeroDyn and SubDyn (or ED platform point when SubDyn is absent). It also extends OpenFAST glue-code VTK output and updates AeroDyn documentation to describe the new GS inputs and theory.
Changes:
- Add GS data types, parameters, input parsing, initialization, inflow evaluation, influence models, and GS drag load calculation in AeroDyn.
- Add glue-code mesh/load mappings for GS motion and loads between AeroDyn↔SubDyn and AeroDyn↔ED platform point mesh, plus VTK output for GS meshes.
- Update AeroDyn user/theory docs to document the new GS input sections and modeling approach.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| modules/subdyn/src/SubDyn_Types.f90 | Minor type/comment/line-number adjustment related to member node bookkeeping. |
| modules/openfast-library/src/FAST_Subs.f90 | Write a single GS VTK output (avoids duplicates in multirotor cases). |
| modules/openfast-library/src/FAST_Mapping.f90 | Add GS motion/load mappings between AD and SD / ED platform point mesh. |
| modules/aerodyn/src/AeroDyn.f90 | Core GS implementation: init, inflow, influence, drag loads, and Jacobian plumbing. |
| modules/aerodyn/src/AeroDyn_Types.f90 | Add GS-related types/fields and serialization support; update AD data-loc indices. |
| modules/aerodyn/src/AeroDyn_Registry.txt | Register GS constants and new GS typedefs/fields for code generation/registry. |
| modules/aerodyn/src/AeroDyn_IO.f90 | Parse new GS input sections; adjust clearance output behavior; add GS summary file writer. |
| modules/aerodyn/src/AeroDyn_Inflow_Types.f90 | Add ADI registry plumbing for new GSMotion/GSLoad meshes. |
| docs/source/user/aerodyn/theory.rst | Add/expand theory documentation for tower influence and new generalized support structure models. |
| docs/source/user/aerodyn/input.rst | Document new GS input sections, coupling behavior, and summary/clearance outputs. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
jjonkman
left a comment
There was a problem hiding this comment.
I'm excited to see this feature incorporated into AeroDyn. Please find a few minor comments on the documentation below.
…puts Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Claude <noreply@anthropic.com>
…d inflow Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Claude <noreply@anthropic.com>
…nabled Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Claude <noreply@anthropic.com>
jjonkman
left a comment
There was a problem hiding this comment.
Thank you for addressing my review comments!
… cut-off of tower shadow effect
Previously the generalized support-structure (GS) inflow influence was applied only in RotCalcOutput. The state-derivative, constraint-residual, and linearization paths gated GS behind an absent optional argument, so GS influence was silently dropped from BEMT/DBEMT/UA state marching, the induction (phi) constraint solve, and the input/state/constraint Jacobians -- while the tower influence was applied unconditionally. Thread GSInflow into RotCalcConstrStateResidual and RotCalcContStateDeriv, and forward it from AD_UpdateStates, AD_CalcConstrStateResidual, and the dYdu/dXdu/dXdx/dZdz Jacobian blocks. Also thread it into the remaining operating-point setup/init calls (frozen-wake induction, BEMT_InitStates state initialization, and the UpdatePhi/ValidPhi guess) so those match the GS-inclusive nonlinear model. In dXdu, recompute GSInflow_perturb via AD_CalcWind_GS for parity with the dYdu block, and hoist the RotInflow/GS perturbation copies above the dYdu block so both loops have allocated perturbation copies (fixes a latent RotInflow_perturb allocation gap when dXdu is requested without dYdu). Now that every call site supplies it, make GSInflow a mandatory argument in SetInputs, SetDisturbedInflow, RotCalcConstrStateResidual, and RotCalcContStateDeriv (removing the now-redundant present() guard), and position it immediately after RotInflow to match RotCalcOutput and the RotJacobianP* routines. Any future path that omits GS inflow now fails to compile rather than silently dropping it. Also apply GS influence to the OLAF/FVW lifting-line disturbed inflow (SetInputsForFVW), so unsteady airfoil aerodynamics see the GS-disturbed inflow regardless of Wake_Mod. Document the remaining limitation (GS not applied to the OLAF wake-convection wind) in the theory manual. Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Claude <noreply@anthropic.com>
…change Update the documented AeroDyn primary example and the API change log for the new generalized support-structure (GS) influence model. - ad_primary_example.dat: add GSPotent/GSShadow/GSAero switches after TwrAero and the required "General support structure joints" and "General support structure members" sections (with 0 counts and their header/units lines) so the documented example parses with the current reader. - api_change.rst (v5.1.0): document the new GS switches and the two new sections in the "Added in OpenFAST 5.1.0" table, mirroring the multi-line table layout used for other module sections. Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Claude <noreply@anthropic.com>
…y zero Add input validation for the generalized support-structure (GS) model in ValidateInputData: - Range-check GSPotent (0/1/2) and GSShadow (0/1/2), mirroring the existing GSAero and tower switch checks. - Require strictly positive GS member diameters (GSMDia1/GSMDia2) when GSPotent or GSShadow is enabled, preventing a 2.0/GSDiam division by zero in the GS potential-flow/shadow influence routines. - Enforce 0.05 < GSMTI1/GSMTI2 < 1 (fatal) with a >0.4 unphysical warning when the Eames GS shadow model is selected, preventing a GSTI division by zero (mirrors the Eames tower-shadow limits). - Warn when a GS model is enabled (GSPotent, GSShadow, or GSAero) but no GS members are defined (NumGSMembers=0), so the GS model being disabled is no longer silent. Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Claude <noreply@anthropic.com>
Addresses the error-handling issues raised in the PR review (section 6.7): - AD_PrintSum_GS call in AD_Init passed the accumulated ErrStat/ErrMsg as the routine's INTENT(OUT) args, clobbering prior warnings and testing stale error state; now uses ErrStat2/ErrMsg2. - AD_JacobianPInput, AD_JacobianPContState and AD_JacobianPConstrState called AD_CalcWind_GS immediately after AD_CalcWind_Rotor with a single status check; AD_CalcWind_GS resets ErrStat to none, silently dropping a rotor wind error. Added an intermediate check between the two calls. - AD_JacobianPInput leaked RotInflow_perturb and GSInflow_perturb (created with MESH_NEWCOPY, never destroyed); both are now destroyed in cleanup(). - AD_PrintSum_GS initializes its INTENT(OUT) ErrStat/ErrMsg before the early return on NMembers<=0. - Removed the unused y argument and unused YAML import from AD_PrintSum_GS. Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Claude <noreply@anthropic.com>
…ive path The continuous-state-derivative operating-point path in FAST_GetOP called RotCalcContStateDeriv without the now-mandatory GSInflow argument, so the BEMT state derivative used an inflow that omitted the generalized support structure disturbance (and would fail to compile once GSInflow was made mandatory). - FAST_GetOP: compute GS inflow via AD_CalcWind_GS (chaining StartNode after the rotor wind calc) and pass m%Inflow(iInput)%GSInflow to RotCalcContStateDeriv. - AeroDyn: make AD_CalcWind_GS public so the glue code can call it, mirroring the already-public AD_CalcWind_Rotor. Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Claude <noreply@anthropic.com>
Two review follow-ups for the generalized support structure (GS) feature: - ExternalInflow (§6.5b): Init_ExtInfw sized nNodesVel from hub/blades/tower/ nacelle/tailfin only, so the GS nodes that AD_CalcWind_GS appends to the shared wind-point sequence were uncounted. Under CompInflow=2 the point-field query silently returns zero inflow on the GS nodes (and shifts any OLAF wake-point indices). ExternalInflow does not export GS node positions to CFD nor map velocities back, so raise a fatal error when GS is active with ExternalInflow instead of running with bad inflow. - OLAF wake BoxExceedAllow (§6.6): add an in-code comment explaining that BoxExceedAllow=.true. on the MHK+SeaState WaveField wake-point query matches the existing InflowWind branch, so far-wake OLAF particles that drift out of the current/wave grid extrapolate instead of aborting the run. Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Claude <noreply@anthropic.com>
…test GSMotion no longer registers the Orientation field in the mesh or in the linearization variables; the GS influence and aero models use only translational position and velocity. Also documents that the shared GS structure is sampled once from rotor 1 and reused for all rotors. Bumps the r-test pointer so the MHK_RM1_Floating_Tank-scaled fixture disables the tower model (TwrPotent=0, TwrShadow=0, TwrAero=False). The AeroDyn C-binding rejects tower/GS options, so py_wavetank_test1 could not initialize; disabling tower matches both the wavetank and full OpenFAST baselines. Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Claude <noreply@anthropic.com>
This PR is ready to merge.
Feature or improvement description
This PR adds generalized support structures in AeroDyn, allowing the flow-induced loads on the support structures and the influence on the rotors to be modeled (effect on OLAF wake will be implemented in the future). The motion and loads mapping for the generalized support structures is between AeroDyn and SubDyn (instead of ElastoDyn).
This PR is still a work-in-progress:
and OLAF wakeand OLAF wakeAdd new AeroDyn output channels(deferred)Two new input sections for the generalized support structures have been added to the AeroDyn input file just before the
Outputssection. The first section allows the user to specify the coordinates of a list ofNumGSJointsjoints. The second section defines a list ofNumGSMemberssupport members.For each member in this second table, the user needs to specify the starting and ending joints of each member by referencing the
GSJointIDin the previous joint table. The user also needs to specify the diameter, drag coefficient, and turbulence intensity (for the Eames wake deficit model) at the starting and ending joints. If different values are provided, AeroDyn assumes a linear variation of each parameter along the member. Finally, the user needs to specify the maximum element lengthGSMDivfor the discretization of each member. AeroDyn will discretize each member into elements of equal length not greater thanGSMDiv.The format of the new input sections are provided below. Note that the generalized support structure affects all rotors and does not need to be defined for each rotor separately.
Implementation details and theory can be found in the updated AeroDyn user and theory documentation. Note that the previously incomplete documentation on the tower influence models was also expanded to provide a foundation for the generalized support structure influence model.
Based on VTK visualization, motion and load mesh mapping between AeroDyn generalized support structure and SubDyn is working correctly. Both mesh node positions and force vectors are in alignment.
Impacted areas of the software
AeroDyn, Glue-code, openfast_io, docs
Generative AI usage
Co-authored-by: Microsoft Copilot [copilot@microsoft.com]
Co-authored-by: Anthropic Claude [claude@anthropic.com]
Test results, if applicable
The changes made to the AeroDyn input file require updating the r-tests.