Skip to content

Commit cbd0c6b

Browse files
authored
Merge pull request #2863 from OpenFAST/dev-cbind
Merge dev-cbind to dev (c-bindings updates)
2 parents c7fb200 + dfceeff commit cbd0c6b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+4619
-2172
lines changed

.github/workflows/automated-dev-tests.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ jobs:
7979
- name: Install dependencies
8080
run: |
8181
pip install -r requirements.txt
82+
pip install glue-codes/python/. # Installs the interface library
8283
sudo apt-get update -y
8384
sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev
8485
- name: Setup workspace
@@ -136,6 +137,7 @@ jobs:
136137
- name: Install dependencies
137138
run: |
138139
pip install -r requirements.txt
140+
pip install glue-codes/python/. # Installs the interface library
139141
sudo apt-get update -y
140142
sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev
141143
- name: Setup workspace
@@ -258,6 +260,7 @@ jobs:
258260
- name: Install dependencies
259261
run: |
260262
pip install -r requirements.txt
263+
pip install glue-codes/python/. # Installs the interface library
261264
sudo apt-get update -y
262265
sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev
263266
sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev
@@ -316,6 +319,7 @@ jobs:
316319
- name: Install dependencies
317320
run: |
318321
pip install -r requirements.txt
322+
pip install glue-codes/python/. # Installs the interface library
319323
sudo apt-get update -y
320324
sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev
321325
sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev
@@ -366,6 +370,7 @@ jobs:
366370
- name: Install dependencies
367371
run: |
368372
pip install -r requirements.txt
373+
pip install glue-codes/python/. # Installs the interface library
369374
sudo apt-get update -y
370375
sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev
371376
sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev
@@ -415,6 +420,7 @@ jobs:
415420
- name: Install dependencies
416421
run: |
417422
pip install -r requirements.txt
423+
pip install glue-codes/python/. # Installs the interface library
418424
sudo apt-get update -y
419425
sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev
420426
sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev
@@ -466,6 +472,7 @@ jobs:
466472
- name: Install dependencies
467473
run: |
468474
pip install -r requirements.txt
475+
pip install glue-codes/python/. # Installs the interface library
469476
sudo apt-get update -y
470477
sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev
471478
sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev
@@ -513,6 +520,7 @@ jobs:
513520
- name: Install dependencies
514521
run: |
515522
pip install -r requirements.txt
523+
pip install glue-codes/python/. # Installs the interface library
516524
sudo apt-get update -y
517525
sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev
518526
sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev
@@ -561,6 +569,7 @@ jobs:
561569
- name: Install dependencies
562570
run: |
563571
pip install -r requirements.txt
572+
pip install glue-codes/python/. # Installs the interface library
564573
sudo apt-get update -y
565574
sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev
566575
sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev
@@ -608,6 +617,7 @@ jobs:
608617
- name: Install dependencies
609618
run: |
610619
pip install -r requirements.txt
620+
pip install glue-codes/python/. # Installs the interface library
611621
sudo apt-get update -y
612622
sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev
613623
sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
*.app
3030
__pycache__/*
3131
*.pyc
32+
*.egg-info
3233

3334
# Build specific files
3435
build*/

glue-codes/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
add_subdirectory(openfast)
3+
add_subdirectory(labview)
34

45
if(BUILD_OPENFAST_CPP_API)
56
add_subdirectory(openfast-cpp)

glue-codes/fast-farm/src/FAST_Farm_Subs.f90

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,9 @@ SUBROUTINE Farm_InitMD( farm, ErrStat, ErrMsg )
813813
ALLOCATE( farm%MD%Input( 2 ), farm%MD%InputTimes( 2 ), STAT = ErrStat2 )
814814
if (Failed0("MD%Input and MD%InputTimes.")) return;
815815

816+
! Assign the SS pointer of the first SS instance (turbine 1) to MD. Because MD in FF mode will only pull frequency info, instance of SS doesn't matter (error will be thrown by MD if user asks for SS grid).
817+
MD_InitInp%WaveField => farm%FWrap(1)%m%Turbine%SeaSt%p%WaveField ! this is the same wave field as Init%OutData_SeaSt%WaveField in FAST_subs.f90 (as set by line 278 in SeaSt_Init). Cant use Init%OutData_SeaSt%WaveField because Init is a local variable to FAST_InitializeAll
818+
816819
! initialize MoorDyn
817820
CALL MD_Init( MD_InitInp, farm%MD%Input(1), farm%MD%p, farm%MD%x, farm%MD%xd, farm%MD%z, &
818821
farm%MD%OtherSt, farm%MD%y, farm%MD%m, farm%p%DT_mooring, MD_InitOut, ErrStat2, ErrMsg2 )

glue-codes/labview/CMakeLists.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#
2+
# Copyright 2025 National Renewable Energy Laboratory
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
17+
add_library(wavetanktestinglib SHARED
18+
src/WaveTank.f90
19+
)
20+
target_link_libraries(wavetanktestinglib aerodyn_inflow_c_binding moordyn_c_binding seastate_c_binding nwtclibs versioninfolib)
21+
if(APPLE OR UNIX)
22+
target_compile_definitions(wavetanktestinglib PRIVATE IMPLICIT_DLLEXPORT)
23+
endif()
24+
25+
install(TARGETS wavetanktestinglib
26+
EXPORT "${CMAKE_PROJECT_NAME}Libraries"
27+
RUNTIME DESTINATION bin
28+
LIBRARY DESTINATION lib
29+
ARCHIVE DESTINATION lib)
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
2+
MODULE WaveTankTesting
3+
4+
USE ISO_C_BINDING
5+
USE NWTC_Library
6+
! USE Precision
7+
USE MoorDyn_C
8+
USE SeaState_C_Binding
9+
USE NWTC_C_Binding, ONLY: IntfStrLen, SetErr
10+
11+
IMPLICIT NONE
12+
SAVE
13+
14+
PUBLIC :: WaveTank_Init
15+
16+
REAL(C_DOUBLE) :: dt_c = 0.01_C_DOUBLE ! 100 hertz
17+
REAL(C_FLOAT) :: g_c = 9.8065_C_FLOAT
18+
REAL(C_FLOAT) :: rho_c = 1025.0_C_FLOAT
19+
REAL(C_FLOAT) :: depth_c = 200.0_C_FLOAT
20+
REAL(C_FLOAT), DIMENSION(6) :: ptfminit_c = 0.0_C_FLOAT
21+
INTEGER(C_INT) :: interporder_c = 2 ! 1: linear (uses two time steps) or 2: quadratic (uses three time steps)
22+
23+
INTEGER(C_INT) :: N_CAMERA_POINTS
24+
25+
INTEGER(C_INT) :: load_period = 20 ! seconds
26+
27+
CONTAINS
28+
29+
SUBROUTINE SetErrStat_C(ErrStatLocal, ErrMessLocal, ErrStatGlobal, ErrMessGlobal, RoutineName)
30+
31+
INTEGER(C_INT), INTENT(IN ) :: ErrStatLocal ! Error status of the operation
32+
CHARACTER(*, KIND=C_CHAR), INTENT(IN ) :: ErrMessLocal ! Error message if ErrStat /= ErrID_None
33+
INTEGER(C_INT), INTENT(INOUT) :: ErrStatGlobal ! Error status of the operation
34+
CHARACTER(KIND=C_CHAR), INTENT(INOUT) :: ErrMessGlobal ! Error message if ErrStat /= ErrID_None
35+
CHARACTER(*), INTENT(IN ) :: RoutineName ! Name of the routine error occurred in
36+
37+
IF ( ErrStatLocal == ErrID_None ) RETURN
38+
39+
IF (ErrStatGlobal /= ErrID_None) ErrMessGlobal = TRIM(ErrMessGlobal)//new_line('a')
40+
ErrMessGlobal = TRIM(ErrMessGlobal)//TRIM(RoutineName)//':'//TRIM(ErrMessLocal)
41+
ErrStatGlobal = MAX(ErrStatGlobal,ErrStatLocal)
42+
43+
END SUBROUTINE
44+
45+
SUBROUTINE WaveTank_Init( &
46+
MD_InputFile_c, &
47+
SS_InputFile_c, &
48+
AD_InputFile_c, &
49+
IfW_InputFile_c, &
50+
n_camera_points_c, &
51+
ErrStat_c, &
52+
ErrMsg_c &
53+
) BIND (C, NAME='WaveTank_Init')
54+
#ifndef IMPLICIT_DLLEXPORT
55+
!DEC$ ATTRIBUTES DLLEXPORT :: WaveTank_Init
56+
!GCC$ ATTRIBUTES DLLEXPORT :: WaveTank_Init
57+
#endif
58+
59+
IMPLICIT NONE
60+
61+
CHARACTER(KIND=C_CHAR), INTENT(IN ), TARGET :: MD_InputFile_c(IntfStrLen)
62+
CHARACTER(KIND=C_CHAR), INTENT(IN ), TARGET :: SS_InputFile_c(IntfStrLen)
63+
CHARACTER(KIND=C_CHAR), INTENT(IN ), TARGET :: AD_InputFile_c(IntfStrLen)
64+
CHARACTER(KIND=C_CHAR), INTENT(IN ), TARGET :: IfW_InputFile_c(IntfStrLen)
65+
INTEGER(C_INT), INTENT(IN ) :: n_camera_points_c
66+
INTEGER(C_INT), INTENT( OUT) :: ErrStat_C
67+
CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_C(ErrMsgLen_C)
68+
69+
! Local variables
70+
integer(c_int) :: numchannels_c
71+
character(kind=c_char) :: outputchannelnames_c(100000)
72+
character(kind=c_char) :: outputchannelunits_c(100000)
73+
integer(c_int) :: input_file_passed = 0 ! We're passing paths to input files rather than input strings for all modules
74+
! character(kind=c_char), pointer :: filestring_c(IntfStrLen) ! Point to input file path input argument
75+
76+
print *, MD_InputFile_c
77+
print *, SS_InputFile_c
78+
print *, AD_InputFile_c
79+
print *, IfW_InputFile_c
80+
81+
N_CAMERA_POINTS = n_camera_points_c
82+
83+
! filestring_c => MD_InputFile_c
84+
! call MD_C_Init( &
85+
! input_file_passed, &
86+
! filestring_c, &
87+
! IntfStrLen, &
88+
! dt_c, &
89+
! g_c, &
90+
! rho_c, &
91+
! depth_c, &
92+
! ptfminit_c, &
93+
! interporder_c, &
94+
! numchannels_c, &
95+
! outputchannelnames_c, &
96+
! outputchannelunits_c, &
97+
! ErrStat_C, ErrMsg_C &
98+
! )
99+
100+
! call ADI_C_Init( &
101+
! ADinputFilePassed, & ! integer(c_int), intent(in ) :: ADinputFilePassed !< Write VTK outputs [0: none, 1: init only, 2: animation]
102+
! ADinputFileString_C, & ! type(c_ptr), intent(in ) :: ADinputFileString_C !< Input file as a single string with lines deliniated by C_NULL_CHAR
103+
! ADinputFileStringLength_C, & ! integer(c_int), intent(in ) :: ADinputFileStringLength_C !< lenght of the input file string
104+
! IfWinputFilePassed, & ! integer(c_int), intent(in ) :: IfWinputFilePassed !< Write VTK outputs [0: none, 1: init only, 2: animation]
105+
! IfWinputFileString_C, & ! type(c_ptr), intent(in ) :: IfWinputFileString_C !< Input file as a single string with lines deliniated by C_NULL_CHAR
106+
! IfWinputFileStringLength_C, & ! integer(c_int), intent(in ) :: IfWinputFileStringLength_C !< lenght of the input file string
107+
! OutRootName_C, & ! character(kind=c_char), intent(in ) :: OutRootName_C(IntfStrLen) !< Root name to use for echo files and other
108+
! OutVTKDir_C, & ! character(kind=c_char), intent(in ) :: OutVTKDir_C(IntfStrLen) !< Directory to put all vtk output
109+
! gravity_C, & ! real(c_float), intent(in ) :: gravity_C !< Gravitational acceleration (m/s^2)
110+
! defFldDens_C, & ! real(c_float), intent(in ) :: defFldDens_C !< Air density (kg/m^3)
111+
! defKinVisc_C, & ! real(c_float), intent(in ) :: defKinVisc_C !< Kinematic viscosity of working fluid (m^2/s)
112+
! defSpdSound_C, & ! real(c_float), intent(in ) :: defSpdSound_C !< Speed of sound in working fluid (m/s)
113+
! defPatm_C, & ! real(c_float), intent(in ) :: defPatm_C !< Atmospheric pressure (Pa) [used only for an MHK turbine cavitation check]
114+
! defPvap_C, & ! real(c_float), intent(in ) :: defPvap_C !< Vapour pressure of working fluid (Pa) [used only for an MHK turbine cavitation check]
115+
! WtrDpth_C, & ! real(c_float), intent(in ) :: WtrDpth_C !< Water depth (m)
116+
! MSL2SWL_C, & ! real(c_float), intent(in ) :: MSL2SWL_C !< Offset between still-water level and mean sea level (m) [positive upward]
117+
! InterpOrder_C, & ! integer(c_int), intent(in ) :: InterpOrder_C !< Interpolation order to use (must be 1 or 2)
118+
! DT_C, & ! real(c_double), intent(in ) :: DT_C !< Timestep used with AD for stepping forward from t to t+dt. Must be constant.
119+
! TMax_C, & ! real(c_double), intent(in ) :: TMax_C !< Maximum time for simulation
120+
! storeHHVel, & ! integer(c_int), intent(in ) :: storeHHVel !< Store hub height time series from IfW
121+
! WrVTK_in, & ! integer(c_int), intent(in ) :: WrVTK_in !< Write VTK outputs [0: none, 1: init only, 2: animation]
122+
! WrVTK_inType, & ! integer(c_int), intent(in ) :: WrVTK_inType !< Write VTK outputs as [1: surface, 2: lines, 3: both]
123+
! WrVTK_inDT, & ! real(c_double), intent(in ) :: WrVTK_inDT !< Timestep between VTK writes
124+
! VTKNacDim_in, & ! real(c_float), intent(in ) :: VTKNacDim_in(6) !< Nacelle dimension passed in for VTK surface rendering [0,y0,z0,Lx,Ly,Lz] (m)
125+
! VTKHubRad_in, & ! real(c_float), intent(in ) :: VTKHubrad_in !< Hub radius for VTK surface rendering
126+
! wrOuts_C, &
127+
! DT_Outs_C, &
128+
! NumChannels_C, &
129+
! OutputChannelNames_C, &
130+
! OutputChannelUnits_C, &
131+
! ErrStat_C, ErrMsg_C &
132+
! )
133+
134+
135+
! ! Input file info
136+
! integer(c_int), intent(in ) :: ADinputFilePassed !< Write VTK outputs [0: none, 1: init only, 2: animation]
137+
! type(c_ptr), intent(in ) :: ADinputFileString_C !< Input file as a single string with lines deliniated by C_NULL_CHAR
138+
! integer(c_int), intent(in ) :: ADinputFileStringLength_C !< lenght of the input file string
139+
! integer(c_int), intent(in ) :: IfWinputFilePassed !< Write VTK outputs [0: none, 1: init only, 2: animation]
140+
! type(c_ptr), intent(in ) :: IfWinputFileString_C !< Input file as a single string with lines deliniated by C_NULL_CHAR
141+
! integer(c_int), intent(in ) :: IfWinputFileStringLength_C !< lenght of the input file string
142+
! character(kind=c_char), intent(in ) :: OutRootName_C(IntfStrLen) !< Root name to use for echo files and other
143+
! character(kind=c_char), intent(in ) :: OutVTKDir_C(IntfStrLen) !< Directory to put all vtk output
144+
! ! Environmental
145+
! real(c_float), intent(in ) :: gravity_C !< Gravitational acceleration (m/s^2)
146+
! real(c_float), intent(in ) :: defFldDens_C !< Air density (kg/m^3)
147+
! real(c_float), intent(in ) :: defKinVisc_C !< Kinematic viscosity of working fluid (m^2/s)
148+
! real(c_float), intent(in ) :: defSpdSound_C !< Speed of sound in working fluid (m/s)
149+
! real(c_float), intent(in ) :: defPatm_C !< Atmospheric pressure (Pa) [used only for an MHK turbine cavitation check]
150+
! real(c_float), intent(in ) :: defPvap_C !< Vapour pressure of working fluid (Pa) [used only for an MHK turbine cavitation check]
151+
! real(c_float), intent(in ) :: WtrDpth_C !< Water depth (m)
152+
! real(c_float), intent(in ) :: MSL2SWL_C !< Offset between still-water level and mean sea level (m) [positive upward]
153+
! ! Interpolation
154+
! integer(c_int), intent(in ) :: InterpOrder_C !< Interpolation order to use (must be 1 or 2)
155+
! ! Time
156+
! real(c_double), intent(in ) :: DT_C !< Timestep used with AD for stepping forward from t to t+dt. Must be constant.
157+
! real(c_double), intent(in ) :: TMax_C !< Maximum time for simulation
158+
! ! Flags
159+
! integer(c_int), intent(in ) :: storeHHVel !< Store hub height time series from IfW
160+
! ! VTK
161+
! integer(c_int), intent(in ) :: WrVTK_in !< Write VTK outputs [0: none, 1: init only, 2: animation]
162+
! integer(c_int), intent(in ) :: WrVTK_inType !< Write VTK outputs as [1: surface, 2: lines, 3: both]
163+
! real(c_double), intent(in ) :: WrVTK_inDT !< Timestep between VTK writes
164+
! real(c_float), intent(in ) :: VTKNacDim_in(6) !< Nacelle dimension passed in for VTK surface rendering [0,y0,z0,Lx,Ly,Lz] (m)
165+
! real(c_float), intent(in ) :: VTKHubrad_in !< Hub radius for VTK surface rendering
166+
! integer(c_int), intent(in ) :: wrOuts_C !< Write ADI output file
167+
! real(c_double), intent(in ) :: DT_Outs_C !< Timestep to write output file from ADI
168+
! ! Output
169+
! integer(c_int), intent( out) :: NumChannels_C !< Number of output channels requested from the input file
170+
! character(kind=c_char), intent( out) :: OutputChannelNames_C(ChanLen*MaxADIOutputs+1) !< NOTE: if MaxADIOutputs is sufficiently large, we may overrun the buffer on the Python side.
171+
! character(kind=c_char), intent( out) :: OutputChannelUnits_C(ChanLen*MaxADIOutputs+1)
172+
! integer(c_int), intent( out) :: ErrStat_C !< Error status
173+
! character(kind=c_char), intent( out) :: ErrMsg_C(ErrMsgLen_C) !< Error message (C_NULL_CHAR terminated)
174+
175+
! Set compiler flag for Labview
176+
! Cmpl4LV = .TRUE.
177+
178+
END SUBROUTINE WaveTank_Init
179+
180+
! delta_time, &
181+
SUBROUTINE WaveTank_CalcOutput( &
182+
frame_number, &
183+
positions_x, &
184+
positions_y, &
185+
positions_z, &
186+
rotation_matrix, &
187+
loads, &
188+
ErrStat_c, &
189+
ErrMsg_c &
190+
) BIND (C, NAME='WaveTank_CalcOutput')
191+
#ifndef IMPLICIT_DLLEXPORT
192+
!DEC$ ATTRIBUTES DLLEXPORT :: WaveTank_CalcOutput
193+
!GCC$ ATTRIBUTES DLLEXPORT :: WaveTank_CalcOutput
194+
#endif
195+
196+
IMPLICIT NONE
197+
198+
! INTEGER(C_INT) :: delta_time
199+
INTEGER(C_INT) :: frame_number
200+
REAL(C_FLOAT), INTENT(IN ) :: positions_x(N_CAMERA_POINTS)
201+
REAL(C_FLOAT), INTENT(IN ) :: positions_y(N_CAMERA_POINTS)
202+
REAL(C_FLOAT), INTENT(IN ) :: positions_z(N_CAMERA_POINTS)
203+
REAL(C_FLOAT), INTENT(IN ) :: rotation_matrix(9)
204+
REAL(C_FLOAT), INTENT( OUT) :: loads(N_CAMERA_POINTS)
205+
INTEGER(C_INT), INTENT( OUT) :: ErrStat_C
206+
CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_C(ErrMsgLen_C)
207+
208+
INTEGER :: i
209+
210+
IF ( MOD(frame_number / load_period, 2) == 0 ) THEN
211+
loads = -1.0
212+
ELSE
213+
loads = 1.0
214+
ENDIF
215+
216+
END SUBROUTINE
217+
218+
SUBROUTINE WaveTank_End() bind (C, NAME="WaveTank_End")
219+
220+
221+
IMPLICIT NONE
222+
223+
224+
225+
226+
END SUBROUTINE
227+
228+
end module WaveTankTesting

0 commit comments

Comments
 (0)