Skip to content

Commit 883c72e

Browse files
authored
Merge pull request #3108 from andrew-platt/f/c-bind_updates_ADI
Updates to c-bindings
2 parents 7740c88 + 9463e62 commit 883c72e

File tree

17 files changed

+903
-342
lines changed

17 files changed

+903
-342
lines changed

glue-codes/labview/src/WaveTank.f90

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,13 @@ subroutine WaveTank_Init( &
301301
SimSettings%Env%WtrDpth, &
302302
SimSettings%Env%MSL2SWL, &
303303
SimSettings%Sim%MHK, &
304+
0_c_int, & ! externFlowfield_in
305+
WrVTK_Dir_C, & ! vtk directory to use
306+
SimSettings%Viz%WrVTK, & ! VTK visualization data output: (switch) {0=none; 1=initialization data only; 2=animation; 3=mode shapes}
307+
SimSettings%Viz%WrVTK_Type, & ! Type of VTK visualization data: (switch) {1=surfaces; 2=basic meshes (lines/points); 3=all meshes (debug)} [unused if WrVTK=0]
308+
SimSettings%Viz%WrVTK_DT, & ! timestep of VTK writing
309+
SimSettings%Viz%VTKNacDim, & ! Nacelle dimension passed in for VTK surface rendering [0,y0,z0,Lx,Ly,Lz] (m)
310+
SimSettings%TrbCfg%HubRad, & ! Hub radius for VTK surface rendering
304311
DebugLevelMod, &
305312
ErrStat_C2, ErrMsg_C2 &
306313
)
@@ -351,16 +358,10 @@ subroutine WaveTank_Init( &
351358
c_loc(IfW_InputFile_C(1)), & ! IfWinputFileString_C; Input file as a single string with lines delineated by C_NULL_CHAR
352359
IntfStrLen, & ! IfWinputFileStringLength_C; length of the input file string
353360
OutRootName_C, & ! Root name to use for echo files and other
354-
WrVTK_Dir_C, & ! vtk directory to use
355361
SimSettings%Sim%InterpOrd, & ! interpolation order for extrap/interp
356362
SimSettings%Sim%DT, & ! DT for simulation (used in checks only)
357363
SimSettings%Sim%TMax, & ! Max time for simulation (not used here)
358364
0_c_int, & ! storeHHVel - Store hub height time series from IfW -- set to false since not used here
359-
SimSettings%Viz%WrVTK, & ! VTK visualization data output: (switch) {0=none; 1=initialization data only; 2=animation; 3=mode shapes}
360-
SimSettings%Viz%WrVTK_Type, & ! Type of VTK visualization data: (switch) {1=surfaces; 2=basic meshes (lines/points); 3=all meshes (debug)} [unused if WrVTK=0]
361-
SimSettings%Viz%WrVTK_DT, & ! timestep of VTK writing
362-
SimSettings%Viz%VTKNacDim, & ! Nacelle dimension passed in for VTK surface rendering [0,y0,z0,Lx,Ly,Lz] (m)
363-
SimSettings%TrbCfg%HubRad, & ! Hub radius for VTK surface rendering
364365
1_c_int, & ! wrOuts_C -- Write ADI output file -- hard code to true for now
365366
SimSettings%Sim%DT, & ! Timestep to write output file from ADI
366367
ADI_NumChannels_C, ADI_WriteOutputHdr_C, ADI_WriteOutputUnt_C, &

glue-codes/python/pyOpenFAST/aerodyn_inflow.py

Lines changed: 46 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
import numpy as np
6161
import numpy.typing as npt
6262

63+
from .interface_abc import OpenFASTInterfaceType
64+
6365
#-------------------------------------------------------------------------------
6466
# Helper functions and classes
6567
#-------------------------------------------------------------------------------
@@ -144,36 +146,14 @@ class MotionData:
144146
#-------------------------------------------------------------------------------
145147
# C-interface library class for AeroDyn x InflowWind
146148
#-------------------------------------------------------------------------------
147-
class AeroDynInflowLib(CDLL):
149+
class AeroDynInflowLib(OpenFASTInterfaceType):
148150
"""A Python interface to the AeroDyn/InflowWind library.
149151
150152
This class provides a modern Python interface for calling and running AeroDyn
151153
and InflowWind together. It handles initialization, runtime operations, and cleanup
152154
of the underlying Fortran library.
153155
"""
154156

155-
#--------------------------------------
156-
# Error levels (from IfW)
157-
#--------------------------------------
158-
error_levels: Dict[int, str] = {
159-
0: "None",
160-
1: "Info",
161-
2: "Warning",
162-
3: "Severe Error",
163-
4: "Fatal Error"
164-
}
165-
166-
#--------------------------------------
167-
# Constants
168-
#--------------------------------------
169-
# NOTE: The length of the error message in Fortran is determined by the
170-
# ErrMsgLen variable in the NWTC_Base.f90 file. If ErrMsgLen is modified,
171-
# the corresponding size here must also be updated to match.
172-
ERROR_MESSAGE_LENGTH: int = 8197
173-
DEFAULT_STRING_LENGTH: int = 1025
174-
CHANNEL_NAME_LENGTH: int = 20
175-
MAX_CHANNELS: int = 8000
176-
177157
def __init__(self, library_path: Union[str, Path]) -> None:
178158
"""Initializes the AeroDyn/InflowWind interface.
179159
@@ -199,11 +179,6 @@ def __init__(self, library_path: Union[str, Path]) -> None:
199179
self.aerodyn_inputs_passed_as_string: bool = True # Pass input file as string
200180
self.inflow_inputs_passed_as_string: bool = True # Pass input file as string
201181

202-
# Error handling setup
203-
self.abort_error_level = 4
204-
self.error_status_c = c_int(0)
205-
self.error_message_c = create_string_buffer(self.ERROR_MESSAGE_LENGTH)
206-
207182
# Channel information buffers
208183
self._channel_names_c = create_string_buffer(
209184
self.CHANNEL_NAME_LENGTH * self.MAX_CHANNELS
@@ -223,6 +198,10 @@ def __init__(self, library_path: Union[str, Path]) -> None:
223198
# MHK flag: 0->not MHK, 1->fixed bottom, 2->floating
224199
self.mhk = 0
225200

201+
# External IfW data: 0->internal, 1->external IfW instance
202+
# NOTE: if external, must call set pointer routine
203+
self.externIfW = 0
204+
226205
# 0->None, 1->Info, 2->Warning, 3->Severe Error, 4->Fatal Error
227206
self.debug_level = 0
228207

@@ -316,7 +295,7 @@ def check_error(self) -> None:
316295
message = f"AeroDyn/InflowWind {error_level}: {error_msg}"
317296

318297
# If the error level is fatal, call adi_end() and raise an error
319-
if self.error_status_c.value >= self.abort_error_level:
298+
if self.error_status_c.value >= self.abort_error_level.value:
320299
try:
321300
self.adi_end()
322301
except Exception as e:
@@ -333,22 +312,37 @@ def adi_preinit(self) -> None:
333312
Raises:
334313
RuntimeError: If pre-initialization fails
335314
"""
315+
# Prepare output file paths
316+
vtk_output_dir_c = create_string_buffer(
317+
self.output_vtk_dir.ljust(self.default_str_c_len).encode('utf-8')
318+
)
319+
320+
# Convert VTK nacelle dimensions to C array
321+
vtk_nac_dimension_c = to_c_array(self.vtk_nacelle_dimension, c_float)
322+
336323
self.ADI_C_PreInit(
337-
byref(c_int(self.num_turbines)), # IN -> number of turbines
338-
byref(c_int(self.transpose_dcm)), # IN -> transpose_dcm flag (0=false, 1=true)
339-
byref(c_int(self.point_load_output)), # IN -> point_load_output flag (0=false, 1=true)
340-
byref(c_float(self.gravity)), # IN -> gravity
341-
byref(c_float(self.fluid_density)), # IN -> fluid density
342-
byref(c_float(self.kinematic_viscosity)), # IN -> kinematic viscosity
343-
byref(c_float(self.sound_speed)), # IN -> speed of sound
344-
byref(c_float(self.atmospheric_pressure)), # IN -> atmospheric pressure
345-
byref(c_float(self.vapor_pressure)), # IN -> vapor pressure
346-
byref(c_float(self.water_depth)), # IN -> water depth
347-
byref(c_float(self.mean_sea_level_offset)), # IN -> MSL to SWL offset
348-
byref(c_int(self.mhk)), # IN -> mhk flag (0=not MHK, 1=fixed bottom, 2=floating)
349-
byref(c_int(self.debug_level)), # IN -> debug level (0=None to 4=all meshes)
350-
byref(self.error_status_c), # OUT <- error status code
351-
self.error_message_c # OUT <- error message buffer
324+
byref(c_int(self.num_turbines)), # IN -> number of turbines
325+
byref(c_int(self.transpose_dcm)), # IN -> transpose_dcm flag (0=false, 1=true)
326+
byref(c_int(self.point_load_output)), # IN -> point_load_output flag (0=false, 1=true)
327+
byref(c_float(self.gravity)), # IN -> gravity
328+
byref(c_float(self.fluid_density)), # IN -> fluid density
329+
byref(c_float(self.kinematic_viscosity)), # IN -> kinematic viscosity
330+
byref(c_float(self.sound_speed)), # IN -> speed of sound
331+
byref(c_float(self.atmospheric_pressure)), # IN -> atmospheric pressure
332+
byref(c_float(self.vapor_pressure)), # IN -> vapor pressure
333+
byref(c_float(self.water_depth)), # IN -> water depth
334+
byref(c_float(self.mean_sea_level_offset)), # IN -> MSL to SWL offset
335+
byref(c_int(self.mhk)), # IN -> mhk flag (0=not MHK, 1=fixed bottom, 2=floating)
336+
byref(c_int(self.externIfW)), # IN -> external IfW instance (0=internal IfW, 1=external IfW with pointer to data (setpointer call required))
337+
vtk_output_dir_c, # IN -> directory for vtk output files
338+
byref(c_int(self.write_vtk)), # IN -> write VTK flag
339+
byref(c_int(self.vtk_type)), # IN -> VTK write type
340+
byref(c_double(self.vtk_dt)), # IN -> VTK output time step
341+
vtk_nac_dimension_c, # IN -> VTK nacelle dimensions
342+
byref(c_float(self.vtk_hub_radius)), # IN -> VTK hub radius
343+
byref(c_int(self.debug_level)), # IN -> debug level (0=None to 4=all meshes)
344+
byref(self.error_status_c), # OUT <- error status code
345+
self.error_message_c # OUT <- error message buffer
352346
)
353347
self.check_error()
354348

@@ -423,14 +417,8 @@ def adi_init(
423417

424418
# Prepare output file paths
425419
output_file_root_name_c = create_string_buffer(
426-
self.output_root_name.ljust(self.DEFAULT_STRING_LENGTH).encode('utf-8')
420+
self.output_root_name.ljust(self.default_str_c_len).encode('utf-8')
427421
)
428-
vtk_output_dir_c = create_string_buffer(
429-
self.output_vtk_dir.ljust(self.DEFAULT_STRING_LENGTH).encode('utf-8')
430-
)
431-
432-
# Convert VTK nacelle dimensions to C array
433-
vtk_nac_dimension_c = to_c_array(self.vtk_nacelle_dimension, c_float)
434422

435423
self.ADI_C_Init(
436424
byref(c_int(self.aerodyn_inputs_passed_as_string)), # IN -> AD input file is passed as string
@@ -440,16 +428,10 @@ def adi_init(
440428
c_char_p(ifw_input_string), # IN -> IfW input file as string
441429
byref(c_int(ifw_input_string_length)), # IN -> IfW input file string length
442430
output_file_root_name_c, # IN -> rootname for ADI file writing
443-
vtk_output_dir_c, # IN -> directory for vtk output files
444431
byref(c_int(self.interpolation_order)), # IN -> interpolation order (1: linear, 2: quadratic)
445432
byref(c_double(self.dt)), # IN -> time step
446433
byref(c_double(self.t_max)), # IN -> maximum simulation time
447434
byref(c_int(self.store_hub_height_velocity)), # IN -> store hub height velocity flag
448-
byref(c_int(self.write_vtk)), # IN -> write VTK flag
449-
byref(c_int(self.vtk_type)), # IN -> VTK write type
450-
byref(c_double(self.vtk_dt)), # IN -> VTK output time step
451-
vtk_nac_dimension_c, # IN -> VTK nacelle dimensions
452-
byref(c_float(self.vtk_hub_radius)), # IN -> VTK hub radius
453435
byref(c_int(self.write_outputs)), # IN -> write outputs flag
454436
byref(c_double(self.output_timestep)), # IN -> output time step
455437
byref(self._num_channels_c), # OUT <- number of channels
@@ -708,6 +690,13 @@ def _initialize_routines(self) -> None:
708690
POINTER(c_float), # WtrDpth
709691
POINTER(c_float), # MSL2SWL
710692
POINTER(c_int), # MHK
693+
POINTER(c_int), # externIfW
694+
POINTER(c_char), # OutVTKdir
695+
POINTER(c_int), # WrVTK
696+
POINTER(c_int), # WrVTK_Type
697+
POINTER(c_double), # WrVTK_DT -- 0 or negative to do every step
698+
POINTER(c_float), # VTKNacDim
699+
POINTER(c_float), # VTKHubRad
711700
POINTER(c_int), # debuglevel
712701
POINTER(c_int), # ErrStat_C
713702
POINTER(c_char) # ErrMsg_C
@@ -748,16 +737,10 @@ def _initialize_routines(self) -> None:
748737
POINTER(c_char_p), # IfW input file as string
749738
POINTER(c_int), # IfW input file string length
750739
POINTER(c_char), # OutRootName
751-
POINTER(c_char), # OutVTKdir
752740
POINTER(c_int), # InterpOrder
753741
POINTER(c_double), # dt
754742
POINTER(c_double), # tmax
755743
POINTER(c_int), # storeHHVel
756-
POINTER(c_int), # WrVTK
757-
POINTER(c_int), # WrVTK_Type
758-
POINTER(c_double), # WrVTK_DT -- 0 or negative to do every step
759-
POINTER(c_float), # VTKNacDim
760-
POINTER(c_float), # VTKHubRad
761744
POINTER(c_int), # wrOuts -- file format for writing outputs
762745
POINTER(c_double), # DT_Outs -- timestep for outputs to file
763746
POINTER(c_int), # number of channels

glue-codes/python/pyOpenFAST/hydrodyn.py

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -76,25 +76,9 @@
7676
import numpy as np
7777
import datetime
7878

79-
class HydroDynLib(CDLL):
80-
# Human readable error levels from IfW.
81-
error_levels = {
82-
0: "None",
83-
1: "Info",
84-
2: "Warning",
85-
3: "Severe Error",
86-
4: "Fatal Error"
87-
}
88-
89-
# NOTE: the error message length in Fortran is controlled by the
90-
# ErrMsgLen variable in the NWTC_Base.f90 file. If that ever
91-
# changes, it may be necessary to update the corresponding size
92-
# here.
93-
error_msg_c_len = 1025
94-
95-
# NOTE: the length of the name used for any output file written by the
96-
# HD Fortran code is 1025.
97-
default_str_c_len = 1025
79+
from .interface_abc import OpenFASTInterfaceType
80+
81+
class HydroDynLib(OpenFASTInterfaceType):
9882

9983
def __init__(self, library_path):
10084
super().__init__(library_path)
@@ -107,11 +91,6 @@ def __init__(self, library_path):
10791
self.seastate_inputs_passed_as_string: bool = True # Pass input file as string
10892
self.hydrodyn_inputs_passed_as_string: bool = True # Pass input file as string
10993

110-
# Create buffers for class data
111-
self.abort_error_level = 4
112-
self.error_status_c = c_int(0)
113-
self.error_message_c = create_string_buffer(self.error_msg_c_len)
114-
11594
# This is not sufficient for HD
11695
#FIXME: ChanLen may not always be 20 -- could be as much as 256
11796
# Possible fix is to pass this length over to Fortran side.

glue-codes/python/pyOpenFAST/inflowwind.py

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,27 +35,9 @@
3535
import datetime
3636
import os
3737

38+
from .interface_abc import OpenFASTInterfaceType
3839

39-
class InflowWindLib(CDLL):
40-
# Human readable error levels from IfW.
41-
error_levels = {
42-
0: "None",
43-
1: "Info",
44-
2: "Warning",
45-
3: "Severe Error",
46-
4: "Fatal Error"
47-
}
48-
49-
# NOTE: the error message length in Fortran is controlled by the
50-
# ErrMsgLen variable in the NWTC_Base.f90 file. If that ever
51-
# changes, it may be necessary to update the corresponding size
52-
# here.
53-
error_msg_c_len = 1025
54-
55-
# NOTE: the length of the name used for any output file written by the
56-
# IfW Fortran code is 1025.
57-
default_str_c_len = 1025
58-
40+
class InflowWindLib(OpenFASTInterfaceType):
5941
def __init__(self, library_path):
6042
super().__init__(library_path)
6143
self.library_path = library_path
@@ -69,7 +51,7 @@ def __init__(self, library_path):
6951
# Create buffers for class data
7052
self.abort_error_level = 4
7153
self.error_status_c = c_int(0)
72-
self.error_message_c = create_string_buffer(self.error_msg_c_len)
54+
self.error_message_c = create_string_buffer(self.ERROR_MESSAGE_LENGTH)
7355

7456
# This buffer for the channel names and units is set arbitrarily large
7557
# to start. InflowWind only has a maximum of 9 outputs at present, but

glue-codes/python/pyOpenFAST/interface_abc.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@
1717

1818
class OpenFASTInterfaceType(CDLL):
1919

20+
#--------------------------------------
21+
# Constants
22+
#--------------------------------------
23+
# NOTE: The length of the error message in Fortran is determined by the
24+
# ErrMsgLen variable in the NWTC_Base.f90 file. If ErrMsgLen is modified,
25+
# the corresponding size here must also be updated to match.
26+
ERROR_MESSAGE_LENGTH: int = 8197
27+
DEFAULT_STRING_LENGTH: int = 1025
28+
CHANNEL_NAME_LENGTH: int = 20
29+
MAX_CHANNELS: int = 8000
30+
2031
# Human readable error levels
2132
error_levels = {
2233
0: "None",
@@ -39,7 +50,12 @@ class OpenFASTInterfaceType(CDLL):
3950
# Fortran code is 1025.
4051
default_str_c_len = 1025
4152

53+
# error handling
4254
abort_error_level = c_int(4)
55+
error_status_c = c_int(0)
56+
error_message_c = create_string_buffer(ERROR_MESSAGE_LENGTH)
57+
58+
4359

4460
def __init__(self, library_path: str):
4561
super().__init__(library_path)

glue-codes/python/pyOpenFAST/moordyn.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,6 @@ def __init__(self, library_path):
4646
super().__init__(library_path)
4747

4848
self._initialize_routines()
49-
50-
# Create buffers for class data
51-
self.error_status_c = c_int(0)
52-
self.error_message_c = create_string_buffer(self.ERROR_MSG_C_LEN)
53-
self.error_message = create_string_buffer(1025)
5449
self.ended = False # For error handling at end
5550

5651
self._channel_names = create_string_buffer(256*1000)

0 commit comments

Comments
 (0)