wawi 0.0.16__py3-none-any.whl → 0.0.17__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
wawi/wind.py CHANGED
@@ -32,12 +32,43 @@ beaufort_dict = {
32
32
  }
33
33
 
34
34
  def get_beaufort(U0):
35
+ """Get the Beaufort scale for a given wind speed U0."""
36
+
35
37
  return [key for key in beaufort_dict if inrange(U0, beaufort_dict[key])][0]
36
38
 
37
39
  def inrange(num, rng):
40
+ """Check if a number is in a given range."""
38
41
  return num<=np.max(rng) and num>=np.min(rng)
39
42
 
40
43
  class LoadCoefficients:
44
+ """
45
+ Class to hold the load coefficients for a aerodynamic section
46
+
47
+ Attributes
48
+ ----------
49
+ Cd : float
50
+ Drag coefficient
51
+ dCd : float
52
+ Derivative of drag coefficient with respect to reduced velocity
53
+ Cl : float
54
+ Lift coefficient
55
+ dCl : float
56
+ Derivative of lift coefficient with respect to reduced velocity
57
+ Cm : float
58
+ Moment coefficient
59
+ dCm : float
60
+ Derivative of moment coefficient with respect to reduced velocity
61
+ fill_empty : bool
62
+ If True, fill empty attributes with zeros
63
+
64
+ Methods
65
+ -------
66
+ fill_empty_with_zeros : None
67
+ Fills empty attributes with zeros
68
+ to_dict : dict
69
+ Converts the LoadCoefficients object to a dictionary
70
+
71
+ """
41
72
  keys = ['Cd', 'Cm', 'Cl', 'dCd', 'dCm', 'dCl']
42
73
 
43
74
  def __repr__(self):
@@ -58,14 +89,54 @@ class LoadCoefficients:
58
89
  self.fill_empty_with_zeros()
59
90
 
60
91
  def fill_empty_with_zeros(self):
92
+ """
93
+ Fills empty attributes with zeros.
94
+ """
95
+ # Fill empty attributes with zeros
61
96
  for key in self.keys:
62
97
  if getattr(self, key) is None:
63
98
  setattr(self, key, 0)
64
99
 
65
100
  def to_dict(self):
101
+ """
102
+ Converts the LoadCoefficients object to a dictionary.
103
+
104
+ Returns
105
+ -------
106
+ dict
107
+ A dictionary with the keys and values of the LoadCoefficients object.
108
+ """
109
+
66
110
  return {key: getattr(self, key) for key in self.keys}
67
111
 
68
112
  class ADs:
113
+ """
114
+ Class to hold the aerodynamic derivatives (ADs) for a given aerodynamic section.
115
+
116
+ Attributes
117
+ ----------
118
+ type : str
119
+ Type of the aerodynamic section
120
+ P1, P2, P3, P4, P5, P6 : function
121
+ Functions representing the aerodynamic derivatives for the section, related to horizontal motion of the section.
122
+ H1, H2, H3, H4, H5, H6 : function
123
+ Functions representing the aerodynamic derivatives for the section, related to vertical motion of the section.
124
+ A1, A2, A3, A4, A5, A6 : function
125
+ Functions representing the aerodynamic derivatives for the section, related to twisting motion of the section.
126
+
127
+ Methods
128
+ -------
129
+ plot : None
130
+ Plots the aerodynamic derivatives for the section
131
+ to_dict : dict
132
+ Converts the ADs object to a dictionary
133
+ evaluate_all : dict
134
+ Evaluates all aerodynamic derivatives for a given reduced velocity
135
+ evaluate : dict
136
+ Evaluates a specific aerodynamic derivative for a given reduced velocity
137
+
138
+ """
139
+
69
140
  ad_keys = ['P1', 'P2', 'P3', 'P4', 'P5', 'P6',
70
141
  'H1', 'H2', 'H3', 'H4', 'H5', 'H6',
71
142
  'A1', 'A2', 'A3', 'A4', 'A5', 'A6']
@@ -103,13 +174,47 @@ class ADs:
103
174
  self.A6 = A6
104
175
 
105
176
  def plot(self, v=np.arange(0,5,0.01), **kwargs):
177
+ """
178
+ Plots the aerodynamic derivatives for the section.
179
+
180
+ Parameters
181
+ ----------
182
+ v : array-like
183
+ Reduced velocity values for which to plot the aerodynamic derivatives.
184
+ **kwargs : keyword arguments
185
+ Additional keyword arguments to pass to the `plot_ads` function.
186
+ """
187
+
106
188
  return plot_ads(self.to_dict(), v, **kwargs)
107
189
 
108
190
 
109
191
  def to_dict(self):
192
+ """
193
+ Converts the ADs object to a dictionary.
194
+
195
+ Returns
196
+ -------
197
+ dict
198
+ A dictionary with the keys and values of the ADs object.
199
+ """
200
+
110
201
  return {key: getattr(self, key) for key in self.ad_keys}
111
202
 
112
203
  def evaluate_all(self, v):
204
+ """
205
+ Evaluates all aerodynamic derivatives for a given reduced velocity.
206
+
207
+ Parameters
208
+ ----------
209
+ v : float
210
+ Reduced velocity for which to evaluate the aerodynamic derivatives.
211
+
212
+ Returns
213
+ -------
214
+ dict
215
+ A dictionary with the evaluated aerodynamic derivatives.
216
+ """
217
+
113
218
  AD_evaluated = dict()
114
219
  for key in self.ad_keys:
115
220
  AD_evaluated[key] = getattr(self, key)(v)
@@ -118,12 +223,36 @@ class ADs:
118
223
 
119
224
 
120
225
  def evaluate(self, key, v):
226
+ """
227
+ Evaluates a specific aerodynamic derivative for a given reduced velocity.
228
+
229
+ Parameters
230
+ ----------
231
+ key : str
232
+
233
+ The key of the aerodynamic derivative to evaluate.
234
+ v : float
235
+ Reduced velocity for which to evaluate the aerodynamic derivative.
236
+
237
+ Returns
238
+ -------
239
+ float
240
+ The evaluated aerodynamic derivative.
241
+ """
242
+
121
243
  AD_evaluated = getattr(self, key)(v)
122
244
 
123
245
  return AD_evaluated
124
246
 
125
247
  def flatplate_ads():
126
-
248
+ """Flat plate aerodynamic derivatives.
249
+
250
+ Returns
251
+ -------
252
+ dict
253
+ A dictionary with the aerodynamic derivatives for a flat plate.
254
+
255
+ """
127
256
  ad_dict = dict()
128
257
 
129
258
  def F(v):
@@ -175,8 +304,29 @@ def flatplate_ads():
175
304
 
176
305
 
177
306
  def quasisteady_ads(D, B, load_coefficients):
178
- # Assuming load coeffs are normalized wrt. both D (Cd) and B (Cl and Cm) and ADs are
179
- # normalized using B only.
307
+ """Quasi-steady aerodynamic derivatives.
308
+
309
+ Parameters
310
+ ----------
311
+ D : float
312
+ Diameter of the section
313
+ B : float
314
+ Width of the section
315
+ load_coefficients : LoadCoefficients or dict
316
+ Load coefficients for the section. If a dictionary is provided, it should contain
317
+ the keys 'Cd', 'dCd', 'Cl', 'dCl', 'Cm', and 'dCm' with corresponding values.
318
+ If a LoadCoefficients object is provided, it should have the same attributes.
319
+ Returns
320
+ -------
321
+ dict
322
+ A dictionary with the aerodynamic derivatives for the section.
323
+
324
+ Notes
325
+ -----
326
+ The aerodynamic derivatives are calculated based on the load coefficients provided.
327
+ The load coefficients should be normalized with respect to both D (Cd) and B (Cl and Cm).
328
+ ADs are normalized using B only.
329
+ """
180
330
 
181
331
  if type(load_coefficients)==dict:
182
332
  Cd = load_coefficients['Cd']
@@ -205,6 +355,36 @@ def quasisteady_ads(D, B, load_coefficients):
205
355
 
206
356
  def compute_aero_matrices(U, AD, B, elements, T_wind, phi,
207
357
  omega_reduced=None, print_progress=False, rho=1.225):
358
+ """Compute the aerodynamic matrices for a given set of elements.
359
+
360
+ Parameters
361
+ ----------
362
+ U : float or function
363
+ Wind speed or function to calculate wind speed at a given point.
364
+ AD : ADs
365
+ Aerodynamic derivatives for the section.
366
+ B : float
367
+ Width of the section.
368
+ elements : list
369
+ List of elements for which to compute the aerodynamic matrices.
370
+ T_wind : np.ndarray
371
+ Transformation matrix from global to wind coordinates.
372
+ phi : np.ndarray
373
+ Mode shapes for the elements.
374
+ omega_reduced : np.ndarray, optional
375
+ Reduced frequencies for which to compute the aerodynamic matrices.
376
+ print_progress : bool, optional
377
+ If True, print progress of the computation.
378
+ rho : float, optional
379
+ Air density, default is 1.225 kg/m^3.
380
+
381
+ Returns
382
+ -------
383
+ Kae : np.ndarray
384
+ Aerodynamic stiffness matrix.
385
+ Cae : np.ndarray
386
+ Aerodynamic damping matrix.
387
+ """
208
388
 
209
389
  if omega_reduced is None:
210
390
  omega_reduced = np.linspace(0.015, 2.0, 75)
@@ -248,6 +428,37 @@ def compute_aero_matrices(U, AD, B, elements, T_wind, phi,
248
428
  def compute_aero_matrices_sets(U, AD, B, elements, T_wind, phi_dict,
249
429
  omega_reduced=None, omega=None, print_progress=False, sets=None):
250
430
 
431
+ """Compute the aerodynamic matrices for a given set of elements.
432
+
433
+ Parameters
434
+ ----------
435
+ U : float or function
436
+ Wind speed or function to calculate wind speed at a given point.
437
+ AD : dict
438
+ Dictionary of aerodynamic derivatives for the section.
439
+ B : float
440
+ Width of the section.
441
+ elements : dict
442
+ Dictionary of elements (BEEF elements) for which to compute the aerodynamic matrices.
443
+ T_wind : np.ndarray
444
+ Transformation matrix from global to wind coordinates.
445
+ phi : np.ndarray
446
+ Mode shapes for the elements.
447
+ omega_reduced : np.ndarray, optional
448
+ Reduced frequencies for which to compute the aerodynamic matrices.
449
+ print_progress : bool, optional
450
+ If True, print progress of the computation.
451
+ sets : list, optional
452
+ List of sets of elements for which to compute the aerodynamic matrices.
453
+
454
+ Returns
455
+ -------
456
+ Kae : np.ndarray
457
+ Aerodynamic stiffness matrix.
458
+ Cae : np.ndarray
459
+ Aerodynamic damping matrix.
460
+ """
461
+
251
462
  if sets is None:
252
463
  sets = elements.keys()
253
464
 
@@ -306,32 +517,6 @@ def compute_aero_matrices_sets(U, AD, B, elements, T_wind, phi_dict,
306
517
 
307
518
  return Kae, Cae
308
519
 
309
- def mvregress_ads(beta):
310
- ad_dict = dict()
311
- ad_keys = ['P1', 'P2', 'P3', 'P4', 'P5', 'P6',
312
- 'H1', 'H2', 'H3', 'H4', 'H5', 'H6',
313
- 'A1', 'A2', 'A3', 'A4', 'A5', 'A6']
314
-
315
- for key in ad_keys:
316
- ad_dict[key] = lambda v, key=key: 0
317
-
318
- #TODO: FINALIZE, NOT FINISHED
319
-
320
- return ad_dict
321
-
322
-
323
- def f_rf_fun_legacy(a, d, v):
324
- N = len(a)
325
- f = 0j
326
- for l in range(0, 3):
327
- f = f + a[l] * (1j/v)**l
328
-
329
- for l in range(0, N-3):
330
- f = f + a[l+2]*(1j/v) / ((1j/v + d[l]))
331
-
332
- f = f*v**2
333
- return f
334
-
335
520
 
336
521
  def f_rf_fun(a, d, v):
337
522
  N = len(a)
@@ -349,6 +534,29 @@ def f_rf_fun(a, d, v):
349
534
 
350
535
 
351
536
  def rf_ads(a, d):
537
+ """
538
+ Function to compute the aerodynamic derivatives for a given set of reduced frequencies using rational functions.
539
+
540
+ Parameters
541
+ ----------
542
+ a : list
543
+ List of coefficients for the rational function, assumed in the order of
544
+ P1, P2, P3, P4, P5, P6, H1, H2, H3, H4, H5, H6, A1, A2, A3, A4, A5, A6.
545
+ d : list
546
+ List of poles for the rational function, assumed in the order of
547
+ P1, P2, P3, P4, P5, P6, H1, H2, H3, H4, H5, H6, A1, A2, A3, A4, A5, A6.
548
+
549
+ Returns
550
+ -------
551
+ dict
552
+ A dictionary with the aerodynamic derivatives for the section.
553
+
554
+ Notes
555
+ -----
556
+ The aerodynamic derivatives are calculated based on the coefficients and poles provided.
557
+ The coefficients should be normalized with respect to both D (Cd) and B (Cl and Cm).
558
+
559
+ """
352
560
  # B assumed to be implicitly included in RF factors
353
561
  ad_dict = dict()
354
562
  ad_keys = ['P1', 'P2', 'P3', 'P4', 'P5', 'P6',
@@ -375,6 +583,30 @@ def rf_ads(a, d):
375
583
 
376
584
 
377
585
  def distribute_to_dict(prefix, array, count_start=1):
586
+ """
587
+ Distributes a list of arrays to a dictionary with keys based on the prefix and index.
588
+
589
+ Parameters
590
+ ----------
591
+ prefix : str
592
+ Prefix for the keys in the dictionary.
593
+ array : list
594
+ List of arrays to be distributed.
595
+ count_start : int, optional
596
+ Starting index for the keys in the dictionary. Default is 1.
597
+
598
+ Returns
599
+ -------
600
+ dict
601
+ A dictionary with keys based on the prefix and index, and values from the input array.
602
+
603
+ Notes
604
+ -----
605
+ The keys in the dictionary are formed by concatenating the prefix with the index of the array.
606
+
607
+ Docstring is generated by GitHub Copilot.
608
+
609
+ """
378
610
  array_dict = dict()
379
611
  for ix,array_i in enumerate(array):
380
612
  key = prefix + str(ix+count_start)
@@ -384,6 +616,25 @@ def distribute_to_dict(prefix, array, count_start=1):
384
616
 
385
617
 
386
618
  def distribute_multi_to_dict(prefixes, arrays):
619
+ """
620
+ Distributes a list of arrays to a dictionary with keys based on the prefix and index.
621
+
622
+ Parameters
623
+ ----------
624
+ prefixes : list
625
+ List of prefixes for the keys in the dictionary.
626
+ arrays : list
627
+ List of arrays to be distributed.
628
+
629
+ Returns
630
+ -------
631
+ dict
632
+ A dictionary with keys based on the prefix and index, and values from the input array.
633
+
634
+ Notes
635
+ -----
636
+ The keys in the dictionary are formed by concatenating the prefix with the index of the array.
637
+ Docstring is generated by GitHub Copilot."""
387
638
  array_dict = dict()
388
639
 
389
640
  for prefix_ix, prefix in enumerate(prefixes):
@@ -395,6 +646,24 @@ def distribute_multi_to_dict(prefixes, arrays):
395
646
 
396
647
 
397
648
  def unwrap_rf_parameters(parameters):
649
+ """
650
+ Unwraps the parameters from a dictionary into two lists: one for the coefficients and one for the poles.
651
+
652
+ Parameters
653
+ ----------
654
+ parameters : dict
655
+ Dictionary containing the parameters with keys starting with 'a' for coefficients and 'd' for poles.
656
+
657
+ Returns
658
+ -------
659
+ tuple
660
+ tuple containing two lists: one for the coefficients and one for the poles.
661
+
662
+ Notes
663
+ -----
664
+ Docstring is generated by GitHub Copilot.
665
+ """
666
+
398
667
  keys = list(parameters.keys())
399
668
  a_ixs = np.where([word.startswith('a') for word in keys])[0]
400
669
  d_ixs = np.where([word.startswith('d') for word in keys])[0]
@@ -415,6 +684,24 @@ def unwrap_rf_parameters(parameters):
415
684
 
416
685
 
417
686
  def normal_wind(T_g2wi, T_g2el, U=1.0):
687
+ """
688
+ Computes the wind speed in the local coordinates of the element.
689
+
690
+ Parameters
691
+ ----------
692
+ T_g2wi : np.ndarray
693
+ Transformation matrix from global to wind coordinates.
694
+ T_g2el : np.ndarray
695
+ Transformation matrix from global to element coordinates.
696
+ U : float, optional
697
+ Wind speed in the global coordinates. Default is 1.0.
698
+
699
+ Returns
700
+ -------
701
+ np.ndarray
702
+ Wind speed in the local coordinates of the element.
703
+ """
704
+
418
705
  T_wi2el = T_g2el @ T_g2wi.T
419
706
  e_wind_local = (T_wi2el @ np.array([1, 0, 0])[np.newaxis,:].T).flatten()
420
707
 
@@ -520,6 +807,29 @@ def element_aero_mats(B, omega, ad_dict, L, T=None, phi=None, rho=1.225):
520
807
 
521
808
  # Spectra
522
809
  def kaimal_auto(omega, Lx, A, sigma, V):
810
+ """
811
+ Kaimal auto-spectral density function.
812
+
813
+ Parameters
814
+ ----------
815
+ omega : float
816
+
817
+ Angular frequency.
818
+ Lx : float
819
+ Length scale.
820
+ A : float
821
+ Amplitude.
822
+ sigma : float
823
+ Standard deviation of the turbulence.
824
+ V : float
825
+ Mean wind speed.
826
+
827
+ Returns
828
+ -------
829
+ S : float
830
+ Auto-spectral density function value.
831
+ """
832
+
523
833
  f = omega/(2*np.pi)
524
834
  fhat = f*Lx/V
525
835
  S = (sigma**2*(A*fhat)/(1+(1.5*A*fhat))**(5/3))/f
@@ -527,6 +837,24 @@ def kaimal_auto(omega, Lx, A, sigma, V):
527
837
  return S/(2*np.pi)
528
838
 
529
839
  def von_karman_auto(omega, Lx, sigma, V):
840
+ """
841
+ Von Karman auto-spectral density function.
842
+
843
+ Parameters
844
+ ----------
845
+ omega : float
846
+ Angular frequency.
847
+ Lx : float
848
+ Length scale.
849
+ sigma : float
850
+ Standard deviation of the turbulence.
851
+ V : float
852
+ Mean wind speed.
853
+ Returns
854
+ -------
855
+ S : float
856
+ Auto-spectral density function value.
857
+ """
530
858
 
531
859
  A1 = [
532
860
  0.0,
@@ -553,6 +881,33 @@ def von_karman_auto(omega, Lx, sigma, V):
553
881
  return S/(2*np.pi)
554
882
 
555
883
  def generic_kaimal_matrix(omega, nodes, T_wind, A, sigma, C, Lx, U, spectrum_type='kaimal'):
884
+ """
885
+ Computes the cross-spectral density matrix for a given set of nodes.
886
+
887
+ Parameters
888
+ ----------
889
+ omega : float
890
+
891
+ Angular frequency.
892
+ nodes : list
893
+ List of BEEF nodes for which to compute the cross-spectral density matrix.
894
+ T_wind : np.ndarray
895
+ Transformation matrix from global to wind coordinates.
896
+ A : float or np.ndarray
897
+ Parameter(s) A in Kaimal auto-spectral density.
898
+ sigma : float or np.ndarray
899
+ Standard deviation of the turbulence (either single or all components).
900
+ C : float or np.ndarray
901
+ Coefficient(s) for the cross-spectral density matrix.
902
+ LX : float or np.ndarray
903
+ Length scale(s) for the cross-spectral density matrix.
904
+ U : function
905
+ Function (of x, y and z) to calculate mean wind speed at a given point.
906
+ spectrum_type : str, optional
907
+ Type of spectrum to use. Default is 'kaimal'. Other options are 'vonKarman' or 'Karman'.
908
+
909
+ """
910
+
556
911
  # Adopted from MATLAB version. `nodes` is list with beef-nodes.
557
912
  V = np.zeros(len(nodes)) # Initialize vector with mean wind in all nodes
558
913
  Su = np.zeros([len(nodes), len(nodes)]) # One-point spectra for u component in all nodes
@@ -605,6 +960,29 @@ def generic_kaimal_matrix(omega, nodes, T_wind, A, sigma, C, Lx, U, spectrum_typ
605
960
 
606
961
 
607
962
  def loadmatrix_fe(V, load_coefficients, rho, B, D, admittance=None):
963
+ """
964
+ Computes the aerodynamic load matrix for a given set of parameters.
965
+
966
+ Parameters
967
+ ----------
968
+ V : float
969
+ Wind speed.
970
+ load_coefficients : dict
971
+ Dictionary containing the aerodynamic coefficients.
972
+ rho : float
973
+ Air density.
974
+ B : float
975
+ Width of the section.
976
+ D : float
977
+ Height of the section.
978
+ admittance : function, optional
979
+ Function to compute the admittance function. Default is None.
980
+
981
+ Returns
982
+ -------
983
+ BqBq : function
984
+ Function to compute the aerodynamic load matrix for a given frequency.
985
+ """
608
986
 
609
987
  if admittance is None :
610
988
  admittance = lambda omega_k: np.ones( (4,3) )
@@ -625,6 +1003,27 @@ def loadmatrix_fe(V, load_coefficients, rho, B, D, admittance=None):
625
1003
  return BqBq
626
1004
 
627
1005
  def loadmatrix_fe_static(V, load_coefficients, rho, B, D ):
1006
+ """
1007
+ Computes the aerodynamic load matrix for a given set of parameters in static conditions.
1008
+
1009
+ Parameters
1010
+ ----------
1011
+ V : float
1012
+ Wind speed.
1013
+ load_coefficients : dict
1014
+ Dictionary containing the aerodynamic coefficients.
1015
+ rho : float
1016
+ Air density.
1017
+ B : float
1018
+ Width of the section.
1019
+ D : float
1020
+ Height of the section.
1021
+
1022
+ Returns
1023
+ -------
1024
+ BqBq : np.ndarray
1025
+ Aerodynamic load matrix.
1026
+ """
628
1027
 
629
1028
  Cd = load_coefficients['Cd']
630
1029
  Cl = load_coefficients['Cl']
@@ -637,6 +1036,30 @@ def loadmatrix_fe_static(V, load_coefficients, rho, B, D ):
637
1036
  return BqBq
638
1037
 
639
1038
  def loadvector(T_el, Bq, T_wind, L, static = False):
1039
+ """
1040
+ Computes load vectors for a given set of parameters.
1041
+
1042
+ Parameters
1043
+ ----------
1044
+ T_el : np.ndarray
1045
+ Transformation matrix from global to element coordinates.
1046
+ Bq : np.ndarray
1047
+ Aerodynamic load matrix.
1048
+ T_wind : np.ndarray
1049
+ Transformation matrix from global to wind coordinates.
1050
+ L : float
1051
+ Length of the element.
1052
+ static : bool, optional
1053
+ If True, compute the load vector for static conditions. Default is False.
1054
+
1055
+ Returns
1056
+ -------
1057
+ R1 : np.ndarray
1058
+ Load vector for element node 1.
1059
+ R2 : np.ndarray
1060
+ Load vector for element node 2.
1061
+
1062
+ """
640
1063
 
641
1064
  G = np.zeros([12,4])
642
1065
  G[0,0] = L/2
@@ -674,6 +1097,48 @@ def loadvector(T_el, Bq, T_wind, L, static = False):
674
1097
  def windaction(omega, S, load_coefficients, elements, T_wind,
675
1098
  phi, B, D, U, omega_reduced=None, rho=1.225, print_progress=True,
676
1099
  section_lookup=None, nodes=None, admittance=None):
1100
+ """
1101
+ Computes the wind cross-spectral density matrix on a set of elements using the specified parameters.
1102
+
1103
+ Parameters
1104
+ ----------
1105
+ omega : np.ndarray
1106
+ Angular frequency.
1107
+ S : function
1108
+ Function to compute the cross-spectral density matrix.
1109
+ load_coefficients : dict
1110
+ Dictionary containing the aerodynamic coefficients.
1111
+ elements : list
1112
+ List of elements for which to compute the wind cross-spectral density matrix.
1113
+ T_wind : np.ndarray
1114
+ Transformation matrix from global to wind coordinates.
1115
+ phi : np.ndarray
1116
+ Transformation matrix from global to element coordinates.
1117
+ B : float
1118
+ Width of the section.
1119
+ D : float
1120
+ Height of the section.
1121
+ U : function
1122
+ Function to calculate mean wind speed at a given point.
1123
+ omega_reduced : np.ndarray, optional
1124
+ Reduced angular frequency. Default is None.
1125
+ rho : float, optional
1126
+ Air density. Default is 1.225.
1127
+ print_progress : bool, optional
1128
+ If True, print progress. Default is True.
1129
+ section_lookup : dict, optional
1130
+ Dictionary to look up sections for each element. Default is None.
1131
+ nodes : list, optional
1132
+ List of BEEF nodes for which to compute the wind cross-spectral density matrix. Default is None.
1133
+ admittance : function, optional
1134
+ Function to compute the admittance function. Default is None.
1135
+
1136
+ Returns
1137
+ -------
1138
+ genSqSq_reduced : np.ndarray
1139
+ Cross-spectral density matrix for the wind action.
1140
+
1141
+ """
677
1142
 
678
1143
  if nodes is None:
679
1144
  nodes = list(set([a for b in [el.nodes for el in elements] for a in b]))
@@ -787,6 +1252,40 @@ def windaction_static(load_coefficients, elements, T_wind,
787
1252
  phi, B, D, U, rho=1.225, print_progress=True,
788
1253
  section_lookup=None, nodes=None):
789
1254
 
1255
+ """
1256
+ Computes the wind load vector for a set of elements using the specified parameters.
1257
+
1258
+ Parameters
1259
+ ----------
1260
+ load_coefficients : dict
1261
+ Dictionary containing the aerodynamic coefficients.
1262
+ elements : list
1263
+ List of BEEF elements for which to compute the wind load vector.
1264
+ T_wind : np.ndarray
1265
+ Transformation matrix from global to wind coordinates.
1266
+ phi : np.ndarray
1267
+ Transformation matrix from global to element coordinates.
1268
+ B : float
1269
+ Width of the section.
1270
+ D : float
1271
+ Height of the section.
1272
+ U : function
1273
+ Function to calculate mean wind speed at a given point.
1274
+ rho : float, optional
1275
+ Air density. Default is 1.225.
1276
+ print_progress : bool, optional
1277
+ If True, print progress. Default is True.
1278
+ section_lookup : dict, optional
1279
+ Dictionary to look up sections for each element. Default is None.
1280
+ nodes : list, optional
1281
+ List of BEEF nodes for which to compute the wind load vector. Default is None.
1282
+
1283
+ Returns
1284
+ -------
1285
+ genF : np.ndarray
1286
+ Wind load vector for the specified elements.
1287
+ """
1288
+
790
1289
  if nodes is None:
791
1290
  nodes = list(set([a for b in [el.nodes for el in elements] for a in b]))
792
1291
 
@@ -834,6 +1333,35 @@ def windaction_static(load_coefficients, elements, T_wind,
834
1333
  return genF
835
1334
 
836
1335
  def K_from_ad(ad, V, w, B, rho):
1336
+ """
1337
+ Compute the aerodynamic stiffness matrix K from aerodynamic derivatives.
1338
+
1339
+ Parameters
1340
+ ----------
1341
+ ad : dict
1342
+ Dictionary containing aerodynamic derivative functions. Expected keys are:
1343
+ 'P4', 'P6', 'P3', 'H6', 'H4', 'H3', 'A6', 'A4', 'A3'. Each value should be a callable
1344
+ that takes a single argument (the reduced velocity `v`).
1345
+ V : float
1346
+ Wind velocity.
1347
+ w : float
1348
+ Circular frequency (rad/s). If zero, returns a zero matrix.
1349
+ B : float
1350
+ Reference length (e.g., bridge deck width).
1351
+ rho : float
1352
+ Air density.
1353
+
1354
+ Returns
1355
+ -------
1356
+ k : ndarray of shape (3, 3)
1357
+ Aerodynamic stiffness matrix.
1358
+
1359
+ Notes
1360
+ -----
1361
+ If `w` is zero, the function returns a 3x3 zero matrix.
1362
+ Otherwise, the matrix is computed using the provided aerodynamic derivatives evaluated at the reduced velocity.
1363
+ """
1364
+
837
1365
  if w==0:
838
1366
  k = np.zeros([3,3])
839
1367
  else:
@@ -849,6 +1377,34 @@ def K_from_ad(ad, V, w, B, rho):
849
1377
 
850
1378
 
851
1379
  def C_from_ad(ad, V, w, B, rho):
1380
+ """
1381
+ Compute the aerodynamic damping matrix K from aerodynamic derivatives.
1382
+
1383
+ Parameters
1384
+ ----------
1385
+ ad : dict
1386
+ Dictionary containing aerodynamic derivative functions. Expected keys are:
1387
+ 'P1', 'P5', 'P2', 'H5', 'H1', 'H2', 'A5', 'A1', 'A2'. Each value should be a callable
1388
+ that takes a single argument (the reduced velocity `v`).
1389
+ V : float
1390
+ Wind velocity.
1391
+ w : float
1392
+ Circular frequency (rad/s). If zero, returns a zero matrix.
1393
+ B : float
1394
+ Reference length (e.g., bridge deck width).
1395
+ rho : float
1396
+ Air density.
1397
+
1398
+ Returns
1399
+ -------
1400
+ k : ndarray of shape (3, 3)
1401
+ Aerodynamic stiffness matrix.
1402
+
1403
+ Notes
1404
+ -----
1405
+ If `w` is zero, the function returns a 3x3 zero matrix.
1406
+ Otherwise, the matrix is computed using the provided aerodynamic derivatives evaluated at the reduced velocity.
1407
+ """
852
1408
  if w==0:
853
1409
  c = np.zeros([3,3])
854
1410
  else:
@@ -863,6 +1419,24 @@ def C_from_ad(ad, V, w, B, rho):
863
1419
 
864
1420
 
865
1421
  def phi_aero_sum(mat, phi, x):
1422
+ """
1423
+ Computes the aerodynamic matrix (damping or stiffness) in modal coordinates.
1424
+
1425
+ Parameters
1426
+ ----------
1427
+ mat : ndarray
1428
+ Aerodynamic matrix in global coordinates.
1429
+ phi : ndarray
1430
+ Transformation matrix from global to modal coordinates.
1431
+ x : ndarray
1432
+ Vector of x-coordinates for integration.
1433
+
1434
+ Returns
1435
+ -------
1436
+ mat : ndarray
1437
+ Aerodynamic matrix in modal coordinates.
1438
+ """
1439
+
866
1440
  n_modes = phi.shape[1]
867
1441
  n_points = len(x)
868
1442
 
@@ -878,6 +1452,24 @@ def phi_aero_sum(mat, phi, x):
878
1452
 
879
1453
 
880
1454
  def function_sum(fun, const, fun_factor=1):
1455
+ """
1456
+ Function to sum a function and a constant. The function is multiplied by a factor.
1457
+
1458
+ Parameters
1459
+ ----------
1460
+ fun : callable
1461
+ Function to be summed with the constant.
1462
+ const : float
1463
+ Constant to be summed with the function.
1464
+ fun_factor : float, optional
1465
+ Factor to multiply the function. Default is 1.
1466
+
1467
+ Returns
1468
+ -------
1469
+ fsum : callable
1470
+ Function that computes the sum of the function and the constant.
1471
+
1472
+ """
881
1473
  def fsum(x):
882
1474
  if fun is None:
883
1475
  return const
@@ -888,6 +1480,33 @@ def function_sum(fun, const, fun_factor=1):
888
1480
 
889
1481
 
890
1482
  def get_aero_cont_adfun(ad_dict_fun, V, B, rho, phi, x):
1483
+ """
1484
+ Computes the aerodynamic matrices in modal coordinates.
1485
+
1486
+ Parameters
1487
+ ----------
1488
+ ad_dict_fun : callable
1489
+ Function that returns the aerodynamic derivatives for a given reduced velocity.
1490
+ V : float
1491
+ Wind velocity.
1492
+ B : float
1493
+ Reference length (e.g., bridge deck width).
1494
+ rho : float
1495
+ Air density.
1496
+ phi : ndarray
1497
+ Transformation matrix from global to modal coordinates.
1498
+ x : ndarray
1499
+ Vector of x-coordinates for integration.
1500
+
1501
+ Returns
1502
+ -------
1503
+ K : callable
1504
+ Function that computes the aerodynamic stiffness matrix in modal coordinates.
1505
+ C : callable
1506
+ Function that computes the aerodynamic damping matrix in modal coordinates.
1507
+
1508
+
1509
+ """
891
1510
  def K(w):
892
1511
  n_modes = phi.shape[1]
893
1512
  n_points = len(x)
@@ -920,6 +1539,35 @@ def get_aero_cont_adfun(ad_dict_fun, V, B, rho, phi, x):
920
1539
 
921
1540
 
922
1541
  def get_aero_cont_addict(ad_dict, V, B, rho, phi, x):
1542
+ """
1543
+ Computes the aerodynamic matrices in modal coordinates.
1544
+
1545
+ Parameters
1546
+ ----------
1547
+ ad_dict : dict
1548
+ Dictionary containing aerodynamic derivative functions. Expected keys are:
1549
+ 'P4', 'P6', 'P3', 'H6', 'H4', 'H3', 'A6', 'A4', 'A3'. Each value should be a callable
1550
+ that takes a single argument (the reduced velocity `v`).
1551
+ V : float
1552
+ Wind velocity.
1553
+ B : float
1554
+ Reference length (e.g., bridge deck width).
1555
+ rho : float
1556
+ Air density.
1557
+ phi : ndarray
1558
+ Transformation matrix from global to modal coordinates.
1559
+ x : ndarray
1560
+ Vector of x-coordinates for integration.
1561
+
1562
+ Returns
1563
+ -------
1564
+ K : callable
1565
+ Function that computes the aerodynamic stiffness matrix in modal coordinates.
1566
+ C : callable
1567
+ Function that computes the aerodynamic damping matrix in modal coordinates.
1568
+
1569
+
1570
+ """
923
1571
  def K(w):
924
1572
  kae = K_from_ad(ad_dict, V, w, B, rho)
925
1573
  return phi_aero_sum(kae, phi, x)
@@ -935,6 +1583,58 @@ def itflutter_cont(Ms, Cs, Ks, phi, x, ad_dict, B, V=0.0, rho=1.225, dV=1,
935
1583
  overshoot_factor=0.5, itmax={}, omega_ref=None,
936
1584
  tol={}, print_progress=True, keep_all=False, track_by_psi=True):
937
1585
 
1586
+ """
1587
+ Iterative flutter analysis for continuous systems using the iterative eigensolver.
1588
+
1589
+ Parameters
1590
+ ----------
1591
+ Ms : ndarray
1592
+ Mass matrix for in-vacuum and dry sub-structure.
1593
+ Cs : ndarray
1594
+ Damping matrix for in-vacuum and dry sub-structure.
1595
+ Ks : ndarray
1596
+ Stiffness matrix for in-vacuum and dry sub-structure.
1597
+ phi : ndarray
1598
+ Transformation matrix from global to modal coordinates.
1599
+ x : ndarray
1600
+ Vector of x-coordinates for integration.
1601
+ ad_dict : dict or callable
1602
+ Dictionary containing aerodynamic derivative functions or a function that returns the aerodynamic derivatives.
1603
+ If a dictionary, it should contain the following keys: 'P4', 'P6', 'P3', 'H6', 'H4', 'H3', 'A6', 'A4', 'A3'.
1604
+ Each value should be a callable that takes a single argument (the reduced velocity `v`).
1605
+ B : float
1606
+ Reference length (e.g., bridge deck width).
1607
+ V : float, optional
1608
+ Initial wind velocity. Default is 0.0.
1609
+ rho : float, optional
1610
+ Air density. Default is 1.225.
1611
+ dV : float, optional
1612
+ Increment for wind velocity. Default is 1.
1613
+ overshoot_factor : float, optional
1614
+ Factor to reduce the increment for wind velocity in case of overshooting. Default is 0.5.
1615
+ itmax : dict, optional
1616
+ Dictionary containing maximum iterations for velocity and frequency. Default is {'V': 50, 'f': 15}.
1617
+ omega_ref : float, optional
1618
+ Reference angular frequency. If None, it is computed from the eigenvalues of the system.
1619
+ tol : dict, optional
1620
+ Dictionary containing tolerance for velocity and frequency. Default is {'V': 1e-3, 'f': 1e-4}.
1621
+ print_progress : bool, optional
1622
+ If True, print progress. Default is True.
1623
+ keep_all : bool, optional
1624
+ If True, keep all results. Default is False.
1625
+ track_by_psi : bool, optional
1626
+ If True, track the eigenvectors by their similarity. Default is True.
1627
+
1628
+ Returns
1629
+ -------
1630
+ res : dict
1631
+ Dictionary containing the results of the flutter analysis. The keys are:
1632
+ 'V' : list of wind velocities at which flutter was detected.
1633
+ 'lambd' : list of eigenvalues at which flutter was detected.
1634
+ 'critical_mode' : list of indices of the critical mode at each velocity.
1635
+ 'critical_psi' : list of eigenvectors corresponding to the critical mode at each velocity.
1636
+ """
1637
+
938
1638
  if callable(ad_dict):
939
1639
  get_aero = get_aero_cont_adfun
940
1640
  else:
@@ -1028,7 +1728,52 @@ def itflutter_cont(Ms, Cs, Ks, phi, x, ad_dict, B, V=0.0, rho=1.225, dV=1,
1028
1728
 
1029
1729
  def itflutter_cont_naive(Ms, Cs, Ks, phi, x, ad_dict, B, V=0.0, rho=1.225, dV=1,
1030
1730
  overshoot_factor=0.5, itmax={}, tol={}, print_progress=True):
1031
-
1731
+ """
1732
+ Iterative flutter analysis for continuous systems using a naive iteration.
1733
+
1734
+ Parameters
1735
+ ----------
1736
+ Ms : ndarray
1737
+ Mass matrix for in-vacuum and dry sub-structure.
1738
+ Cs : ndarray
1739
+ Damping matrix for in-vacuum and dry sub-structure.
1740
+ Ks : ndarray
1741
+ Stiffness matrix for in-vacuum and dry sub-structure.
1742
+ phi : ndarray
1743
+ Transformation matrix from global to modal coordinates.
1744
+ x : ndarray
1745
+ Vector of x-coordinates for integration.
1746
+ ad_dict : dict or callable
1747
+ Dictionary containing aerodynamic derivative functions or a function that returns the aerodynamic derivatives.
1748
+ If a dictionary, it should contain the following keys: 'P4', 'P6', 'P3', 'H6', 'H4', 'H3', 'A6', 'A4', 'A3'.
1749
+ Each value should be a callable that takes a single argument (the reduced velocity `v`).
1750
+ B : float
1751
+ Reference length (e.g., bridge deck width).
1752
+ V : float, optional
1753
+ Initial wind velocity. Default is 0.0.
1754
+ rho : float, optional
1755
+ Air density. Default is 1.225.
1756
+ dV : float, optional
1757
+ Increment for wind velocity. Default is 1.
1758
+ overshoot_factor : float, optional
1759
+ Factor to reduce the increment for wind velocity in case of overshooting. Default is 0.5.
1760
+ itmax : dict, optional
1761
+ Dictionary containing maximum iterations for velocity and frequency. Default is {'V': 50, 'f': 15}.
1762
+ tol : dict, optional
1763
+ Dictionary containing tolerance for velocity and frequency. Default is {'V': 1e-3, 'f': 1e-4}.
1764
+ print_progress : bool, optional
1765
+ If True, print progress. Default is True.
1766
+
1767
+ Returns
1768
+ -------
1769
+ res : dict
1770
+ Dictionary containing the results of the flutter analysis. The keys are:
1771
+ 'V' : list of wind velocities at which flutter was detected.
1772
+ 'lambd' : list of eigenvalues at which flutter was detected.
1773
+ 'critical_mode' : list of indices of the critical mode at each velocity.
1774
+ 'critical_psi' : list of eigenvectors corresponding to the critical mode at each velocity.
1775
+
1776
+ """
1032
1777
 
1033
1778
  if callable(ad_dict):
1034
1779
  get_aero = get_aero_cont_adfun
@@ -1098,5 +1843,4 @@ def itflutter_cont_naive(Ms, Cs, Ks, phi, x, ad_dict, B, V=0.0, rho=1.225, dV=1,
1098
1843
 
1099
1844
  res = {key: np.array(res[key]) for key in ['critical_mode', 'critical_psi', 'V', 'lambd']}
1100
1845
 
1101
- return res
1102
-
1846
+ return res