Conversation
Add a C binding for BeamDyn in the style of the MoorDyn and AeroDyn-Inflow C bindings, so that an external C/C++ code can drive a single BeamDyn beam without the OpenFAST glue code. Entry points (BeamDyn_C_Binding.f90, declared in BeamDyn_C_Binding.h): BD_C_Init, BD_C_GetRefPositions, BD_C_SetRootMotion, BD_C_SetPointLoads, BD_C_SetDistrLoads, BD_C_UpdateStates, BD_C_CalcOutput, BD_C_PackStates, BD_C_UnpackStates, BD_C_End. All BeamDyn data is held in module-level variables; the input history for linear or quadratic interpolation and the state history needed for correction steps are handled as in the other bindings, with the same ErrStat_C/ErrMsg_C error handling. The input file may be passed as a path or as its contents (written to a temporary file, since BeamDyn reads its input from a file unit). Checkpoint files use BeamDyn's registry pack/unpack routines. Root kinematics and gravity cross the interface in double precision: BeamDyn imposes the root motion as a boundary condition at every step, and single precision rounding of a prescribed root motion appears as root acceleration noise. Loads and outputs are single precision as in the other bindings; orientations are double precision. CMake: the driver subroutines move into a beamdyn_driver_subs library (the binding uses them to write the output file), and the new targets beamdyn_c_binding (shared) and beamdyn_c_bind_static are installed with the header. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Add BeamDyn_C_Binding_Driver.c and the beamdyn_c_binding_driver target.
The driver runs a beam from C the way the Fortran driver does (root
rotating about the origin, constant tip load, output file in the same
format) and checks the interface:
- run: time marching with optional prescribed sinusoidal root
motion; the root reaction is compared with the
rigid-body inertial estimate
- cantilever: static tip deflection and first bending frequency of a
uniform cantilever against the Euler-Bernoulli values
- checkpoint: run, write a checkpoint, restore it into a fresh
instance, and compare with the straight run
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
BD_Init took the suggested coupling interval as the default for DTBeam but never reported the time step it actually uses back through the Interval argument, as the other modules do. Set Interval to p%dt after the parameters are read so that a calling code can check or adopt the BeamDyn time step. The C interface uses the returned value for its time step check. Results are unchanged when DTBeam is DEFAULT (the regression and example cases). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
BeamDyn: C interface for driving a standalone beam from C/C++ codes
Feature or improvement description
This adds a C interface to BeamDyn in the style of the existing MoorDyn and AeroDyn-Inflow C bindings, so that an
external C/C++ code can drive a single BeamDyn beam without the OpenFAST glue code. The motivation is ERF-Fire modeling of
poles and wires: the flow solver computes the loads on each pole and wire, BeamDyn returns their dynamic response
(node motions and root reactions), and the coupling runs entirely from C/C++ without the OpenFAST glue code.
New files in
modules/beamdyn/src:BeamDyn_C_Binding.f90:BD_C_Init,BD_C_GetRefPositions,BD_C_SetRootMotion,BD_C_SetPointLoads,BD_C_SetDistrLoads,BD_C_UpdateStates,BD_C_CalcOutput,BD_C_PackStates,BD_C_UnpackStates,BD_C_End.Module-level storage of all BeamDyn data, linear/quadratic input history, correction-step handling, and the same
ErrStat_C/ErrMsg_Cerror handling as the other bindings.BeamDyn_C_Binding.h: C header declaring every entry point (installed toinclude/).BeamDyn_C_Binding_Driver.c: C driver that runs a beam like the Fortran driver (writes the same.outformat) andchecks the interface: static tip deflection and first bending frequency of a uniform cantilever against the
Euler-Bernoulli values, bitwise reproduction of the Fortran driver output, prescribed root motion, and a
checkpoint/restore round trip.
CMake: new targets
beamdyn_driver_subs(driver subroutines split into a library, as AeroDyn does),beamdyn_c_binding(shared),beamdyn_c_bind_static, andbeamdyn_c_binding_driver.Checkpointing uses BeamDyn's registry pack/unpack routines and writes a
<root>.chkpfile (same mechanism asFAST_CreateCheckpoint), so a pole or wire can be checkpointed and restored with the rest of the ERF-Fire state; therestarted run reproduces the straight run bit for bit.
Design deviation from the MoorDyn and AeroDyn-Inflow bindings: those interfaces pass positions, velocities,
accelerations, and gravity as
c_float. Here the root kinematics (position, orientation, velocity, acceleration)and gravity are
c_double; loads, node motions, reaction loads, and channel values remainc_float, andorientation DCMs are
c_doubleas in AeroDyn-Inflow. The reason is that BeamDyn imposes the root motion as aboundary condition at every step, so single-precision rounding of a prescribed root motion acts as root
acceleration noise of order eps*|disp|/dt^2. On the rotating-root BeamDyn regression case (a prescribed root motion, the situation of a wire support moving with its pole),
c_floatroot motiondiffered from the Fortran driver by up to 5e-3 (relative) in near-root acceleration channels and 1e-5 in tip
displacement; with
c_doublethe difference is below 1e-8 on every channel and 3e-13 in tip displacement.Impacted areas of the software
modules/beamdynonly. BeamDyn itself is unchanged; the Fortran driver now links the newbeamdyn_driver_subslibrary instead of compiling
Driver_Beam_Subs.f90directly.Test results, if applicable
Built with Release, BUILD_SHARED_LIBS=ON, DOUBLE_PRECISION=ON (gfortran 16, macOS), run with
beamdyn_c_binding_driver:Fortran driver vs. the same case driven through the interface (BeamDyn dynamic regression example, 1047 channels, 2502 output times, 12 printed digits): non-rotating root, identical to all digits; rotating root, max relative difference 8.7e-9 over all channels (3.5e-13 in tip displacement).
Checkpoint written mid-run, restored into a fresh instance, continued: bitwise identical to the straight run on both the cantilever and the regression example.
The third commit (BD_Init returns its time step through
Interval) leaves the Fortran driver output bit-identical on the example cases (DTBeam = DEFAULT).Regression suite: all 20 BeamDyn-labelled r-test cases (8 BeamDyn driver cases, 5 time-domain OpenFAST cases, 7 linearization cases) were run on this branch and on unmodified v5.0.0 with the same toolchain (macOS, gfortran 16, double precision). All 42 result files (
.outand.lin) are identical between the two builds. Fifteen cases pass the shipped baselines on both builds; the same five fail on both (Damped_Beam_Rotated,5MW_Land_BD_Linear_Aero,IEA22MW_ModalDamping,IEA22MW_ModalDampingLoose,5MW_Land_BD_DLL_WTurb_StC), so those are platform mismatches between this toolchain and the shipped baselines, not effects of this branch. Every BeamDyn input in r-test usesDTBeam = "DEFAULT", so theIntervalchange cannot alter regression results by construction.🤖 Generated with Claude Code