Skip to content

Add User-defined wind documentation for InflowWind#3225

Draft
deslaughter wants to merge 3 commits intoOpenFAST:devfrom
deslaughter:user_defined_wind_docs
Draft

Add User-defined wind documentation for InflowWind#3225
deslaughter wants to merge 3 commits intoOpenFAST:devfrom
deslaughter:user_defined_wind_docs

Conversation

@deslaughter
Copy link
Collaborator

This PR is ready to be merged

Feature or improvement description

This PR adds documentation for how to use the user-defined wind option in InflowWind. Comments and examples were added to the code and a section was added to the ReadTheDocs describing the process.

Related issue, if one exists

Impacted areas of the software

InflowWind modules/inflowwind and documentation docs

Additional supporting information

This PR was mostly generated by Claude Sonnet 4.5 and then reviewed and edited.

Generative AI usage
Co-authored-by: Anthropic Claude claude@anthropic.com

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds developer-facing documentation and code templates to support implementing user-defined wind fields (WindType = 6) in InflowWind, including registry/type updates to carry user parameters and (optionally) time-series data.

Changes:

  • Extends registry/type definitions for User_InitInputType and UserFieldType (including pack/unpack/copy/destroy support).
  • Updates the WindType=6 code path to call UserField_GetVel() and improves template comments/error messages for user implementations.
  • Adds new ReadTheDocs content for user-defined wind fields and links it into the InflowWind docs index (plus an internal markdown guide).

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
modules/inflowwind/src/InflowWind_IO_Types.f90 Adds fields to User_InitInputType and updates copy/pack/unpack accordingly.
modules/inflowwind/src/InflowWind_IO.txt Documents and registers the new User_InitInputType fields.
modules/inflowwind/src/InflowWind_IO.f90 Expands IfW_User_Init template and sets WindType=6 metadata/summary output.
modules/inflowwind/src/IfW_FlowField_Types.f90 Extends UserFieldType with optional arrays/filename and updates lifecycle + serialization routines.
modules/inflowwind/src/IfW_FlowField.txt Documents and registers the new UserFieldType fields.
modules/inflowwind/src/IfW_FlowField.f90 Implements WindType=6 velocity evaluation loop via UserField_GetVel and adds detailed template docs.
modules/inflowwind/USER_DEFINED_WIND.md Adds an implementation guide for developers working directly in the source tree.
docs/source/user/inflowwind/user_defined.rst Adds RTD documentation page describing how to implement user-defined winds.
docs/source/user/inflowwind/index.rst Adds the new user_defined.rst page to the toctree.
docs/source/user/inflowwind/appendix.rst Adds download links intended to point to user-defined wind example files.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1124 to +1133
! Example: Set reference height (after regenerating types from registry)
! UF%RefHeight = InitInp%RefHt
UF%RefHeight = 0.0_ReKi ! Temporary: set to sensible default

! Example: Store filename if reading from file (after regenerating types)
! UF%FileName = InitInp%WindFileName

! Example: Allocate and read data arrays if needed
! if (len_trim(InitInp%WindFileName) > 0) then
! call ReadUserWindFile(InitInp%WindFileName, UF, TmpErrStat, TmpErrMsg)
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IfW_User_Init currently hard-codes UF%RefHeight to 0.0 and leaves the new InitInp fields unused. Since User_InitInputType now includes RefHt/WindFileName/NumDataColumns, it would be better to at least initialize UF%RefHeight from InitInp%RefHt (and set FileDat%FileName from InitInp%WindFileName) so programmatic callers can pass these values without further code edits.

Suggested change
! Example: Set reference height (after regenerating types from registry)
! UF%RefHeight = InitInp%RefHt
UF%RefHeight = 0.0_ReKi ! Temporary: set to sensible default
! Example: Store filename if reading from file (after regenerating types)
! UF%FileName = InitInp%WindFileName
! Example: Allocate and read data arrays if needed
! if (len_trim(InitInp%WindFileName) > 0) then
! call ReadUserWindFile(InitInp%WindFileName, UF, TmpErrStat, TmpErrMsg)
! Initialize reference height from input (after regenerating types from registry)
UF%RefHeight = InitInp%RefHt
! Store filename if reading from file (after regenerating types)
FileDat%FileName = InitInp%WindFileName
! Example: Allocate and read data arrays if needed
! if (len_trim(InitInp%WindFileName) > 0) then
! call ReadUserWindFile(InitInp%WindFileName, UF, TmpErrStat, TmpErrMsg)
! call ReadUserWindFile(InitInp%WindFileName, UF, TmpErrStat, TmpErrMsg)

Copilot uses AI. Check for mistakes.

! Example: Set reference height (after regenerating types from registry)
! UF%RefHeight = InitInp%RefHt
UF%RefHeight = 0.0_ReKi ! Temporary: set to sensible default
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UF is INTENT(OUT) here, but only UF%RefHeight is assigned. The newly added UF%FileName (and any future scalar fields) will be left undefined, which can lead to non-deterministic behavior when writing summaries or when packing/unpacking for restart. Please explicitly initialize new scalar members (e.g., set UF%FileName to an empty string and NumDataLines to 0) during initialization.

Suggested change
UF%RefHeight = 0.0_ReKi ! Temporary: set to sensible default
UF%RefHeight = 0.0_ReKi ! Temporary: set to sensible default
! Initialize additional scalar members to safe defaults to avoid
! leaving the INTENT(OUT) structure in a partially undefined state.
UF%FileName = "" ! No file associated by default
UF%NumDataLines = 0_IntKi ! No data lines by default

Copilot uses AI. Check for mistakes.
! ========= User_InitInputType =======
TYPE, PUBLIC :: User_InitInputType
REAL(SiKi) :: Dummy = 0.0_R4Ki !< User field initialization input dummy value [-]
CHARACTER(1024) :: WindFileName !< name of file containing user-defined wind data (if applicable) [-]
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User_InitInputType now contains a CHARACTER(1024) WindFileName with no default initialization. InflowWind_Init declares User_InitInput but never assigns its members before passing it into IfW_User_Init, so WindFileName can be undefined if a user starts using it. Consider default-initializing WindFileName to an empty string here to avoid reading uninitialized memory.

Suggested change
CHARACTER(1024) :: WindFileName !< name of file containing user-defined wind data (if applicable) [-]
CHARACTER(1024) :: WindFileName = '' !< name of file containing user-defined wind data (if applicable) [-]

Copilot uses AI. Check for mistakes.
cmake .. -DGENERATE_TYPES=ON
make

The build process automatically regenerates the ``*_Types.f90`` files from the ``.txt`` registry files.
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The build instructions here say to run cmake .. and make to regenerate *_Types.f90, but type generation is controlled by the CMake option GENERATE_TYPES (default is OFF). Update the instructions to include enabling type generation (e.g., configure with -DGENERATE_TYPES=ON) so readers actually regenerate the registry types.

Suggested change
The build process automatically regenerates the ``*_Types.f90`` files from the ``.txt`` registry files.
When configured with ``-DGENERATE_TYPES=ON``, the build process automatically regenerates the ``*_Types.f90`` files from the ``.txt`` registry files.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The -DGENERATE_TYPES=On flag is only for builds with cmake; Visual Studio does not. need this flag.

1. **No Acceleration Support**: User-defined wind fields do not currently support
acceleration calculations needed by some modules (e.g., MHK turbines).

2. **No Persistence**: Data must be recalculated if simulation is restarted.
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section claims there is "No Persistence" on restart, but InflowWind has Pack/UnPack support for FlowFieldType (including UserFieldType) via the generated types modules, so user-field data can be serialized/restored. Please revise this limitation to reflect the actual behavior (or scope it to cases where the user wind depends on external resources that cannot be packed).

Suggested change
2. **No Persistence**: Data must be recalculated if simulation is restarted.
2. **Persistence Scope**: State stored in ``FlowFieldType`` (including ``UserFieldType``) is
serialized and restored across restarts via the generated Pack/UnPack support. However, if
your user wind implementation depends on external resources or state that cannot be packed
(e.g., live sensor connections, external services, or files managed outside the packed
types), you are responsible for re-establishing or reloading those resources on restart.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe better to say "no persistence between simulations"

Comment on lines +336 to +338
call UserField_GetVel(FF%User, Time, Position(:, i), VelocityUVW(:, i), TmpErrStat, TmpErrMsg)
call SetErrStat(TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName)
if (ErrStat >= AbortErrLev) return
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the User_FieldType case, other flow-field types return zero velocity for points at/below ground (Position(3)<=0) instead of calling the field-specific getter. For consistency (and to avoid requiring every user implementation to special-case negative Z), consider mirroring that behavior here by skipping UserField_GetVel and returning zero when Position(3,i) <= 0.

Suggested change
call UserField_GetVel(FF%User, Time, Position(:, i), VelocityUVW(:, i), TmpErrStat, TmpErrMsg)
call SetErrStat(TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName)
if (ErrStat >= AbortErrLev) return
! For consistency with other field types, return zero velocity for points
! at or below ground (Z <= 0) instead of calling the user-defined getter.
if (Position(3, i) <= 0.0_ReKi) then
VelocityUVW(:, i) = 0.0_ReKi
else
call UserField_GetVel(FF%User, Time, Position(:, i), VelocityUVW(:, i), TmpErrStat, TmpErrMsg)
call SetErrStat(TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName)
if (ErrStat >= AbortErrLev) return
end if

Copilot uses AI. Check for mistakes.
Comment on lines +1735 to +1739
!! 2. Return velocity components in the global coordinate system (not rotated)
!! 3. Handle any spatial or temporal interpolation as needed
!! 4. Set appropriate error status if position/time is out of bounds
!!
!! Coordinate system:
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UserField_GetVel header comment says velocities should be returned in the "global coordinate system (not rotated)", but IfW_FlowField_GetVelAcc may rotate the input Position into the wind coordinate system and later rotates VelocityUVW back to global (RotFromWind). To avoid confusing users, please clarify that UserField_GetVel should return velocities in the same coordinate system as the passed-in Position (i.e., wind coordinates when RotateWindBox is enabled).

Suggested change
!! 2. Return velocity components in the global coordinate system (not rotated)
!! 3. Handle any spatial or temporal interpolation as needed
!! 4. Set appropriate error status if position/time is out of bounds
!!
!! Coordinate system:
!! 2. Return velocity components in the same coordinate system as the input Position
!! (typically the global/inertial system; when InflowWind is configured with
!! RotateWindBox, both Position and Velocity are in the rotated wind coordinates)
!! 3. Handle any spatial or temporal interpolation as needed
!! 4. Set appropriate error status if position/time is out of bounds
!!
!! Coordinate system (of the Position argument passed to this routine):

Copilot uses AI. Check for mistakes.
INTEGER(IntKi) :: NumDataLines = 0 !< number of data lines (for time-varying user wind) [-]
REAL(DbKi) , DIMENSION(:), ALLOCATABLE :: DTime !< time array for user-defined wind [seconds]
REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Data !< user-defined wind data array [NumDataLines, NumDataColumns] [-]
CHARACTER(1024) :: FileName !< name of user wind file (if applicable) [-]
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UserFieldType adds a fixed-length FileName string without default initialization. Because UF is INTENT(OUT) in IfW_User_Init and the template initialization doesn't currently assign UF%FileName, this member can remain undefined and then get copied/packed. Consider default-initializing FileName to an empty string in the type definition to keep the default template behavior deterministic.

Suggested change
CHARACTER(1024) :: FileName !< name of user wind file (if applicable) [-]
CHARACTER(1024) :: FileName = '' !< name of user wind file (if applicable) [-]

Copilot uses AI. Check for mistakes.
cmake .. -DGENERATE_TYPES=ON
make

The build process automatically regenerates the ``*_Types.f90`` files from the ``.txt`` registry files.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The -DGENERATE_TYPES=On flag is only for builds with cmake; Visual Studio does not. need this flag.

1. **No Acceleration Support**: User-defined wind fields do not currently support
acceleration calculations needed by some modules (e.g., MHK turbines).

2. **No Persistence**: Data must be recalculated if simulation is restarted.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe better to say "no persistence between simulations"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants