@@ -199,6 +199,19 @@ def _initialize_routines(self):
199199 ]
200200 self .HydroDyn_C_CalcOutput .restype = c_int
201201
202+ self .HydroDyn_C_CalcOutput_and_AddedMass .argtypes = [
203+ POINTER (c_double ), # Time_C
204+ POINTER (c_int ), # numNodePts -- number of points expecting motions/loads
205+ POINTER (c_float ), # nodePos -- node positions in flat array of 6*numNodePts
206+ POINTER (c_float ), # nodeVel -- node velocities in flat array of 6*numNodePts
207+ POINTER (c_float ), # nodeFrc -- node forces/moments in flat array of 6*numNodePts
208+ POINTER (c_float ), # nodeAdm -- node added mass matrix in flat array of 6*numNodePts*6*numNodePts
209+ POINTER (c_float ), # Output Channel Values
210+ POINTER (c_int ), # ErrStat_C
211+ POINTER (c_char ) # ErrMsg_C
212+ ]
213+ self .HydroDyn_C_CalcOutput_and_AddedMass .restype = c_int
214+
202215 self .HydroDyn_C_UpdateStates .argtypes = [
203216 POINTER (c_double ), # Time_C
204217 POINTER (c_double ), # TimeNext_C
@@ -259,7 +272,7 @@ def hydrodyn_init(self, seast_input_string_array, hd_input_string_array):
259272 raise Exception ("\n HydroDyn terminated prematurely." )
260273
261274 # Make a flat 1D array of position info:
262- # [x2 ,y1,z1,Rx1,Ry1,Rz1, x2,y2,z2,Rx2,Ry2,Rz2 ...]
275+ # [x1 ,y1,z1,Rx1,Ry1,Rz1, x2,y2,z2,Rx2,Ry2,Rz2 ...]
263276 nodeInitLoc_flat = [pp for p in self .initNodePos for pp in p ]
264277 nodeInitLoc_flat_c = (c_float * (6 * self .numNodePts ))(0.0 ,)
265278 for i , p in enumerate (nodeInitLoc_flat ):
@@ -302,16 +315,16 @@ def hydrodyn_init(self, seast_input_string_array, hd_input_string_array):
302315 def hydrodyn_calcOutput (self , time , nodePos , nodeVel , nodeAcc , nodeFrcMom , outputChannelValues ):
303316
304317 # Check input motion info
305- self .check_input_motions (nodePos ,nodeVel ,nodeAcc )
318+ self .check_input_motions (time , nodePos ,nodeVel ,nodeAcc )
306319
307320 # set flat arrays for inputs of motion
308- # Position -- [x2 ,y1,z1,Rx1,Ry1,Rz1, x2,y2,z2,Rx2,Ry2,Rz2 ...]
321+ # Position -- [x1 ,y1,z1,Rx1,Ry1,Rz1, x2,y2,z2,Rx2,Ry2,Rz2 ...]
309322 nodePos_flat = [pp for p in nodePos for pp in p ]
310323 nodePos_flat_c = (c_float * (6 * self .numNodePts ))(0.0 ,)
311324 for i , p in enumerate (nodePos_flat ):
312325 nodePos_flat_c [i ] = c_float (p )
313326
314- # Velocity -- [Vx2 ,Vy1,Vz1,RVx1,RVy1,RVz1, Vx2,Vy2,Vz2,RVx2,RVy2,RVz2 ...]
327+ # Velocity -- [Vx1 ,Vy1,Vz1,RVx1,RVy1,RVz1, Vx2,Vy2,Vz2,RVx2,RVy2,RVz2 ...]
315328 nodeVel_flat = [pp for p in nodeVel for pp in p ]
316329 nodeVel_flat_c = (c_float * (6 * self .numNodePts ))(0.0 ,)
317330 for i , p in enumerate (nodeVel_flat ):
@@ -331,7 +344,7 @@ def hydrodyn_calcOutput(self, time, nodePos, nodeVel, nodeAcc, nodeFrcMom, outpu
331344
332345 # Run HydroDyn_C_CalcOutput
333346 self .HydroDyn_C_CalcOutput (
334- byref (c_double (time )), # IN: time at which to calculate output forces
347+ byref (c_double (time )), # IN: time at which to calculate output forces
335348 byref (c_int (self .numNodePts )), # IN: number of attachment points expected (where motions are transferred into HD)
336349 nodePos_flat_c , # IN: positions - specified by user
337350 nodeVel_flat_c , # IN: velocities at desired positions
@@ -359,11 +372,76 @@ def hydrodyn_calcOutput(self, time, nodePos, nodeVel, nodeAcc, nodeFrcMom, outpu
359372 for k in range (0 ,self .numChannels ):
360373 outputChannelValues [k ] = float (outputChannelValues_c [k ])
361374
375+ # hydrodyn_calcOutput_and_addedMass ------------------------------------------------------------------------------------------------------
376+ def hydrodyn_calcOutput_and_addedMass (self , time , nodePos , nodeVel , nodeFrcMom , nodeAdm , outputChannelValues ):
377+
378+ # Check input motion info
379+ self .check_input_motions_noAcc (time ,nodePos ,nodeVel )
380+
381+ # set flat arrays for inputs of motion
382+ # Position -- [x1,y1,z1,Rx1,Ry1,Rz1, x2,y2,z2,Rx2,Ry2,Rz2 ...]
383+ nodePos_flat = [pp for p in nodePos for pp in p ]
384+ nodePos_flat_c = (c_float * (6 * self .numNodePts ))(0.0 ,)
385+ for i , p in enumerate (nodePos_flat ):
386+ nodePos_flat_c [i ] = c_float (p )
387+
388+ # Velocity -- [Vx1,Vy1,Vz1,RVx1,RVy1,RVz1, Vx2,Vy2,Vz2,RVx2,RVy2,RVz2 ...]
389+ nodeVel_flat = [pp for p in nodeVel for pp in p ]
390+ nodeVel_flat_c = (c_float * (6 * self .numNodePts ))(0.0 ,)
391+ for i , p in enumerate (nodeVel_flat ):
392+ nodeVel_flat_c [i ] = c_float (p )
393+
394+ # Resulting Forces/moments -- [Fx1,Fy1,Fz1,Mx1,My1,Mz1, Fx2,Fy2,Fz2,Mx2,My2,Mz2 ...]
395+ nodeFrc_flat_c = (c_float * (6 * self .numNodePts ))(0.0 ,)
396+
397+ # Resulting Added-mass matrix
398+ nodeAdm_flat_c = (c_float * (6 * self .numNodePts * 6 * self .numNodePts ))(0.0 ,)
399+
400+ # Set up output channels
401+ outputChannelValues_c = (c_float * self .numChannels )(0.0 ,)
402+
403+ # Run HydroDyn_C_CalcOutput_and_AddedMass
404+ self .HydroDyn_C_CalcOutput_and_AddedMass (
405+ byref (c_double (time )), # IN: time at which to calculate output forces
406+ byref (c_int (self .numNodePts )), # IN: number of attachment points expected (where motions are transferred into HD)
407+ nodePos_flat_c , # IN: positions - specified by user
408+ nodeVel_flat_c , # IN: velocities at desired positions
409+ nodeFrc_flat_c , # OUT: resulting forces/moments array
410+ nodeAdm_flat_c , # OUT: resulting forces/moments array
411+ outputChannelValues_c , # OUT: output channel values as described in input file
412+ byref (self .error_status_c ), # OUT: ErrStat_C
413+ self .error_message_c # OUT: ErrMsg_C
414+ )
415+
416+ self .check_error ()
417+
418+ ## Reshape Force/Moment into [N,6]
419+ count = 0
420+ for j in range (0 ,self .numNodePts ):
421+ nodeFrcMom [j ,0 ] = nodeFrc_flat_c [count ]
422+ nodeFrcMom [j ,1 ] = nodeFrc_flat_c [count + 1 ]
423+ nodeFrcMom [j ,2 ] = nodeFrc_flat_c [count + 2 ]
424+ nodeFrcMom [j ,3 ] = nodeFrc_flat_c [count + 3 ]
425+ nodeFrcMom [j ,4 ] = nodeFrc_flat_c [count + 4 ]
426+ nodeFrcMom [j ,5 ] = nodeFrc_flat_c [count + 5 ]
427+ count = count + 6
428+
429+ ## Reshape added-mass matrix into [6N,6N]
430+ count = 0
431+ for j in range (0 ,6 * self .numNodePts ):
432+ for k in range (0 ,6 * self .numNodePts ):
433+ nodeAdm [k ,j ] = nodeAdm_flat_c [count ]
434+ count = count + 1
435+
436+ # Convert output channel values back into python
437+ for k in range (0 ,self .numChannels ):
438+ outputChannelValues [k ] = float (outputChannelValues_c [k ])
439+
362440 # hydrodyn_updateStates ------------------------------------------------------------------------------------------------------------
363441 def hydrodyn_updateStates (self , time , timeNext , nodePos , nodeVel , nodeAcc , nodeFrcMom ):
364442
365443 # Check input motion info
366- self .check_input_motions (nodePos ,nodeVel ,nodeAcc )
444+ self .check_input_motions (time , nodePos ,nodeVel ,nodeAcc )
367445
368446 # set flat arrays for inputs of motion
369447 # Position -- [x2,y1,z1,Rx1,Ry1,Rz1, x2,y2,z2,Rx2,Ry2,Rz2 ...]
@@ -389,7 +467,7 @@ def hydrodyn_updateStates(self, time, timeNext, nodePos, nodeVel, nodeAcc, nodeF
389467
390468 # Run HydroDyn_UpdateStates_c
391469 self .HydroDyn_C_UpdateStates (
392- byref (c_double (time )), # IN: time at which to calculate output forces
470+ byref (c_double (time )), # IN: time at which to calculate output forces
393471 byref (c_double (timeNext )), # IN: time T+dt we are stepping to
394472 byref (c_int (self .numNodePts )), # IN: number of attachment points expected (where motions are transferred into HD)
395473 nodePos_flat_c , # IN: positions - specified by user
@@ -425,10 +503,9 @@ def check_error(self):
425503 raise Exception ("\n HydroDyn terminated prematurely." )
426504
427505
428- def check_input_motions (self ,nodePos ,nodeVel ,nodeAcc ):
506+ def check_input_motions (self ,time , nodePos ,nodeVel ,nodeAcc ):
429507 # make sure number of nodes didn't change for some reason
430508 if self ._initNumNodePts != self .numNodePts :
431- # @ANDY TODO: `time` is not available here so this would be a runtime error
432509 print (f"At time { time } , the number of node points changed from initial value of { self ._initNumNodePts } . This is not permitted during the simulation." )
433510 self .hydrodyn_end ()
434511 raise Exception ("\n Error in calling HydroDyn library." )
@@ -466,6 +543,33 @@ def check_input_motions(self,nodePos,nodeVel,nodeAcc):
466543 raise Exception ("\n HydroDyn terminated prematurely." )
467544
468545
546+ def check_input_motions_noAcc (self ,time ,nodePos ,nodeVel ):
547+ # make sure number of nodes didn't change for some reason
548+ if self ._initNumNodePts != self .numNodePts :
549+ print (f"At time { time } , the number of node points changed from initial value of { self ._initNumNodePts } . This is not permitted during the simulation." )
550+ self .hydrodyn_end ()
551+ raise Exception ("\n Error in calling HydroDyn library." )
552+
553+ # Verify that the shape of positions array is correct
554+ if nodePos .shape [1 ] != 6 :
555+ print ("Expecting a Nx6 array of node positions (nodePos) with second index for [x,y,z,Rx,Ry,Rz]" )
556+ self .hydrodyn_end ()
557+ raise Exception ("\n HydroDyn terminated prematurely." )
558+ if nodePos .shape [0 ] != self .numNodePts :
559+ print ("Expecting a Nx6 array of node positions (nodePos) with first index for node number." )
560+ self .hydrodyn_end ()
561+ raise Exception ("\n HydroDyn terminated prematurely." )
562+
563+ # Verify that the shape of velocities array is correct
564+ if nodeVel .shape [1 ] != 6 :
565+ print ("Expecting a Nx6 array of node velocities (nodeVel) with second index for [x,y,z,Rx,Ry,Rz]" )
566+ self .hydrodyn_end ()
567+ raise Exception ("\n HydroDyn terminated prematurely." )
568+ if nodeVel .shape [0 ] != self .numNodePts :
569+ print ("Expecting a Nx6 array of node velocities (nodeVel) with first index for node number." )
570+ self .hydrodyn_end ()
571+ raise Exception ("\n HydroDyn terminated prematurely." )
572+
469573
470574 @property
471575 def output_channel_names (self ):
0 commit comments