6060import numpy as np
6161import 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
0 commit comments