wawi 0.0.13__tar.gz → 0.0.17__tar.gz

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.

Potentially problematic release.


This version of wawi might be problematic. Click here for more details.

Files changed (51) hide show
  1. {wawi-0.0.13 → wawi-0.0.17}/PKG-INFO +42 -3
  2. {wawi-0.0.13 → wawi-0.0.17}/README.md +41 -2
  3. {wawi-0.0.13 → wawi-0.0.17}/wawi/__init__.py +1 -1
  4. wawi-0.0.17/wawi/fe.py +381 -0
  5. {wawi-0.0.13 → wawi-0.0.17}/wawi/general.py +538 -70
  6. {wawi-0.0.13 → wawi-0.0.17}/wawi/identification.py +33 -11
  7. {wawi-0.0.13 → wawi-0.0.17}/wawi/io.py +208 -5
  8. {wawi-0.0.13 → wawi-0.0.17}/wawi/modal.py +384 -6
  9. {wawi-0.0.13 → wawi-0.0.17}/wawi/model/_model.py +1 -1
  10. {wawi-0.0.13 → wawi-0.0.17}/wawi/plot.py +379 -99
  11. wawi-0.0.17/wawi/prob.py +37 -0
  12. wawi-0.0.17/wawi/random.py +254 -0
  13. wawi-0.0.17/wawi/signal.py +153 -0
  14. wawi-0.0.17/wawi/structural.py +536 -0
  15. {wawi-0.0.13 → wawi-0.0.17}/wawi/time_domain.py +122 -1
  16. wawi-0.0.17/wawi/tools.py +30 -0
  17. wawi-0.0.17/wawi/wave.py +1031 -0
  18. {wawi-0.0.13 → wawi-0.0.17}/wawi/wind.py +776 -32
  19. wawi-0.0.17/wawi/wind_code.py +40 -0
  20. {wawi-0.0.13 → wawi-0.0.17}/wawi.egg-info/PKG-INFO +42 -3
  21. wawi-0.0.13/wawi/fe.py +0 -134
  22. wawi-0.0.13/wawi/prob.py +0 -9
  23. wawi-0.0.13/wawi/random.py +0 -38
  24. wawi-0.0.13/wawi/signal.py +0 -45
  25. wawi-0.0.13/wawi/structural.py +0 -278
  26. wawi-0.0.13/wawi/tools.py +0 -7
  27. wawi-0.0.13/wawi/wave.py +0 -490
  28. wawi-0.0.13/wawi/wind_code.py +0 -14
  29. {wawi-0.0.13 → wawi-0.0.17}/LICENSE +0 -0
  30. {wawi-0.0.13 → wawi-0.0.17}/examples/3 Software interfacing/Abaqus model export/bergsoysund-export.py +0 -0
  31. {wawi-0.0.13 → wawi-0.0.17}/examples/3 Software interfacing/Abaqus model export/hardanger-export.py +0 -0
  32. {wawi-0.0.13 → wawi-0.0.17}/pyproject.toml +0 -0
  33. {wawi-0.0.13 → wawi-0.0.17}/setup.cfg +0 -0
  34. {wawi-0.0.13 → wawi-0.0.17}/tests/test_IABSE_step11a.py +0 -0
  35. {wawi-0.0.13 → wawi-0.0.17}/tests/test_IABSE_step11c.py +0 -0
  36. {wawi-0.0.13 → wawi-0.0.17}/tests/test_IABSE_step2a.py +0 -0
  37. {wawi-0.0.13 → wawi-0.0.17}/tests/test_wind.py +0 -0
  38. {wawi-0.0.13 → wawi-0.0.17}/wawi/ext/__init__.py +0 -0
  39. {wawi-0.0.13 → wawi-0.0.17}/wawi/ext/abq.py +0 -0
  40. {wawi-0.0.13 → wawi-0.0.17}/wawi/ext/ansys.py +0 -0
  41. {wawi-0.0.13 → wawi-0.0.17}/wawi/ext/orcaflex.py +0 -0
  42. {wawi-0.0.13 → wawi-0.0.17}/wawi/ext/sofistik.py +0 -0
  43. {wawi-0.0.13 → wawi-0.0.17}/wawi/model/__init__.py +0 -0
  44. {wawi-0.0.13 → wawi-0.0.17}/wawi/model/_aero.py +0 -0
  45. {wawi-0.0.13 → wawi-0.0.17}/wawi/model/_dry.py +0 -0
  46. {wawi-0.0.13 → wawi-0.0.17}/wawi/model/_hydro.py +0 -0
  47. {wawi-0.0.13 → wawi-0.0.17}/wawi/model/_screening.py +0 -0
  48. {wawi-0.0.13 → wawi-0.0.17}/wawi.egg-info/SOURCES.txt +0 -0
  49. {wawi-0.0.13 → wawi-0.0.17}/wawi.egg-info/dependency_links.txt +0 -0
  50. {wawi-0.0.13 → wawi-0.0.17}/wawi.egg-info/requires.txt +0 -0
  51. {wawi-0.0.13 → wawi-0.0.17}/wawi.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wawi
3
- Version: 0.0.13
3
+ Version: 0.0.17
4
4
  Summary: WAve and WInd response prediction
5
5
  Author-email: "Knut A. Kvåle" <knut.a.kvale@ntnu.no>, Ole Øiseth <ole.oiseth@ntnu.no>, Aksel Fenerci <aksel.fenerci@ntnu.no>, Øivind Wiig Petersen <oyvind.w.petersen@ntnu.no>
6
6
  License: MIT License
@@ -50,7 +50,28 @@ Dynamic: license-file
50
50
 
51
51
  What is WAWI?
52
52
  =======================
53
- WAWI is a Python toolbox for prediction of response of structures exposed to wind and wave excitation. The package is still under development in its alpha stage, and documentation and testing will be completed along the way.
53
+ WAWI is a Python toolbox for prediction of response of structures exposed to wind and wave excitation, using a multimodal frequency-domain approach. It supports special features such as:
54
+
55
+ * Hydrodynamic added mass, radiation damping and hydrodynamic force transfer function from e.g. WAMIT analysis
56
+ * Quasisteady wind forcing for buffeting analysis
57
+ * Combined effects of wind and waves
58
+ * Iterative multimodal flutter
59
+ * Iterative modal analysis
60
+ * Modelling of motion-induced aerodynamic forces using aerodynamic derivatives
61
+ * Inhomogeneous sea states
62
+ * Inhomogeneous mean wind (other parameters planned for)
63
+ * Current effects on wave excitation
64
+ * Stochastic linearization methodology to support linearized effect of quadratic drag damping (both line elements and pontoon objects)
65
+ * Object-oriented model setup, including FE description (using Python package BEEF) of beams exposed to aerodynamic forcing
66
+
67
+ Planned implemented in the near future:
68
+
69
+ * Fully inhomogeneous wind state definition (all wind field parameters)
70
+ * Hydrodynamic interaction effects from multibody analyses
71
+ * Second-order wave excitation effects
72
+ * Definition of ADs (aerodynamic derivatives) using rational functions
73
+
74
+ The package is still under development in its alpha stage, and documentation and testing will be completed along the way.
54
75
 
55
76
 
56
77
  Installation
@@ -71,7 +92,17 @@ pip install git+https://www.github.com/knutankv/wawi.git@main
71
92
  How does WAWI work?
72
93
  ======================
73
94
  By representing both aerodynamic and hydrodynamic motion-induced forces and excitation using a coordinate basis defined by the dry in-vacuum mode shapes of the structure, WAWI is able to versatily predict response based on input from any commercial FE software. The main structure used for response prediction is given in this figure:
74
- ![Model](https://raw.githubusercontent.com/knutankv/wawi/main/docs/flowchart.png)
95
+ ![Model](https://raw.githubusercontent.com/knutankv/wawi/main/docs/flowchart.svg)
96
+
97
+ The object structure of a WAWI model is given here:
98
+ ![Modelattributes](https://raw.githubusercontent.com/knutankv/wawi/main/docs/structure.svg)
99
+
100
+ Further details regarding hydrodynamic definitions initiated by the `Hydro` class is given below:
101
+ ![Hydro](https://raw.githubusercontent.com/knutankv/wawi/main/docs/hydro_part.svg)
102
+
103
+ Further details regarding aerodynamic definitions initiated by the `Aero` class is given below:
104
+ ![Aero](https://raw.githubusercontent.com/knutankv/wawi/main/docs/aero_part.svg)
105
+
75
106
 
76
107
  Quick start
77
108
  =======================
@@ -148,6 +179,14 @@ The examples are structured in the following folders based on their topic:
148
179
 
149
180
  References
150
181
  =======================
182
+ The following papers provide background for the implementation:
183
+
184
+ * Beam (FE) description of aerodynamic forces: [Øiseth et al. (2012)](https://www.sciencedirect.com/science/article/abs/pii/S0168874X11001880)
185
+ * Wave modelling and response prediction: [Kvåle et al. (2016)](https://www.sciencedirect.com/science/article/abs/pii/S004579491500334X)
186
+ * Inhomogeneous wave modelling: [Kvåle et al. (2024)](https://www.sciencedirect.com/science/article/pii/S0141118723003437)
187
+ * Hydrodynamic interaction effects: [Fenerci et al. (2022)](https://www.sciencedirect.com/science/article/pii/S095183392200017X)
188
+ * Wave-current interaction: [Fredriksen et al. (2024)](https://www.researchgate.net/profile/Arnt-Fredriksen/publication/386453916_On_the_wave-current_interaction_effect_on_linear_motion_for_floating_bridges/links/6751a40fabddbb448c65cbef/On-the-wave-current-interaction-effect-on-linear-motion-for-floating-bridges.pdf)
189
+
151
190
 
152
191
  Citation
153
192
  =======================
@@ -3,7 +3,28 @@
3
3
 
4
4
  What is WAWI?
5
5
  =======================
6
- WAWI is a Python toolbox for prediction of response of structures exposed to wind and wave excitation. The package is still under development in its alpha stage, and documentation and testing will be completed along the way.
6
+ WAWI is a Python toolbox for prediction of response of structures exposed to wind and wave excitation, using a multimodal frequency-domain approach. It supports special features such as:
7
+
8
+ * Hydrodynamic added mass, radiation damping and hydrodynamic force transfer function from e.g. WAMIT analysis
9
+ * Quasisteady wind forcing for buffeting analysis
10
+ * Combined effects of wind and waves
11
+ * Iterative multimodal flutter
12
+ * Iterative modal analysis
13
+ * Modelling of motion-induced aerodynamic forces using aerodynamic derivatives
14
+ * Inhomogeneous sea states
15
+ * Inhomogeneous mean wind (other parameters planned for)
16
+ * Current effects on wave excitation
17
+ * Stochastic linearization methodology to support linearized effect of quadratic drag damping (both line elements and pontoon objects)
18
+ * Object-oriented model setup, including FE description (using Python package BEEF) of beams exposed to aerodynamic forcing
19
+
20
+ Planned implemented in the near future:
21
+
22
+ * Fully inhomogeneous wind state definition (all wind field parameters)
23
+ * Hydrodynamic interaction effects from multibody analyses
24
+ * Second-order wave excitation effects
25
+ * Definition of ADs (aerodynamic derivatives) using rational functions
26
+
27
+ The package is still under development in its alpha stage, and documentation and testing will be completed along the way.
7
28
 
8
29
 
9
30
  Installation
@@ -24,7 +45,17 @@ pip install git+https://www.github.com/knutankv/wawi.git@main
24
45
  How does WAWI work?
25
46
  ======================
26
47
  By representing both aerodynamic and hydrodynamic motion-induced forces and excitation using a coordinate basis defined by the dry in-vacuum mode shapes of the structure, WAWI is able to versatily predict response based on input from any commercial FE software. The main structure used for response prediction is given in this figure:
27
- ![Model](https://raw.githubusercontent.com/knutankv/wawi/main/docs/flowchart.png)
48
+ ![Model](https://raw.githubusercontent.com/knutankv/wawi/main/docs/flowchart.svg)
49
+
50
+ The object structure of a WAWI model is given here:
51
+ ![Modelattributes](https://raw.githubusercontent.com/knutankv/wawi/main/docs/structure.svg)
52
+
53
+ Further details regarding hydrodynamic definitions initiated by the `Hydro` class is given below:
54
+ ![Hydro](https://raw.githubusercontent.com/knutankv/wawi/main/docs/hydro_part.svg)
55
+
56
+ Further details regarding aerodynamic definitions initiated by the `Aero` class is given below:
57
+ ![Aero](https://raw.githubusercontent.com/knutankv/wawi/main/docs/aero_part.svg)
58
+
28
59
 
29
60
  Quick start
30
61
  =======================
@@ -101,6 +132,14 @@ The examples are structured in the following folders based on their topic:
101
132
 
102
133
  References
103
134
  =======================
135
+ The following papers provide background for the implementation:
136
+
137
+ * Beam (FE) description of aerodynamic forces: [Øiseth et al. (2012)](https://www.sciencedirect.com/science/article/abs/pii/S0168874X11001880)
138
+ * Wave modelling and response prediction: [Kvåle et al. (2016)](https://www.sciencedirect.com/science/article/abs/pii/S004579491500334X)
139
+ * Inhomogeneous wave modelling: [Kvåle et al. (2024)](https://www.sciencedirect.com/science/article/pii/S0141118723003437)
140
+ * Hydrodynamic interaction effects: [Fenerci et al. (2022)](https://www.sciencedirect.com/science/article/pii/S095183392200017X)
141
+ * Wave-current interaction: [Fredriksen et al. (2024)](https://www.researchgate.net/profile/Arnt-Fredriksen/publication/386453916_On_the_wave-current_interaction_effect_on_linear_motion_for_floating_bridges/links/6751a40fabddbb448c65cbef/On-the-wave-current-interaction-effect-on-linear-motion-for-floating-bridges.pdf)
142
+
104
143
 
105
144
  Citation
106
145
  =======================
@@ -3,7 +3,7 @@
3
3
  '''
4
4
  __pdoc__ = {'wawi.ext.abq': False}
5
5
 
6
- __version__ = "0.0.13"
6
+ __version__ = "0.0.17"
7
7
 
8
8
  # Other packages
9
9
  import numpy as np
wawi-0.0.17/wawi/fe.py ADDED
@@ -0,0 +1,381 @@
1
+ # -*- coding: utf-8 -*-
2
+ import numpy as np
3
+ from .general import blkdiag, transform_unit
4
+
5
+ '''
6
+ FE-related tools.
7
+ '''
8
+
9
+ def intpoints_from_elements(nodes, elements, sort_axis=0):
10
+ """
11
+ Calculates the integration points (midpoints) for each element based on node coordinates.
12
+
13
+ Parameters
14
+ ----------
15
+ nodes : np.ndarray
16
+ Array of node coordinates with shape (n_nodes, 4), where columns represent node index and x, y, z coordinates.
17
+ elements : np.ndarray
18
+ Array of element connectivity with shape (n_elements, 2), where each row contains indices of the two nodes forming an element.
19
+ sort_axis : int, optional
20
+ Axis (0 for x, 1 for y, 2 for z) to sort the integration points by. Default is 0 (x-axis).
21
+
22
+ Returns
23
+ -------
24
+ x : np.ndarray
25
+ Array of x-coordinates of the integration points, sorted by the specified axis.
26
+ y : np.ndarray
27
+ Array of y-coordinates of the integration points, sorted by the specified axis.
28
+ z : np.ndarray
29
+ Array of z-coordinates of the integration points, sorted by the specified axis.
30
+
31
+ Notes
32
+ -----
33
+ Assumes that `nodeix_from_elements` is a function that returns the indices of the nodes for each element. Docstring is generated by Github Copilot.
34
+ """
35
+
36
+ nodeix = nodeix_from_elements(elements, nodes).astype('int')
37
+
38
+ intpoints = (nodes[nodeix[:,0], 1:4]+nodes[nodeix[:,1], 1:4])/2
39
+ sortix = np.argsort(intpoints[:,sort_axis])
40
+ intpoints = intpoints[sortix, :]
41
+
42
+ x = intpoints[:, 0]
43
+ y = intpoints[:, 1]
44
+ z = intpoints[:, 2]
45
+
46
+ return x, y, z
47
+
48
+
49
+ def nodeix_from_elements(element_matrix, node_matrix, return_as_flat=False):
50
+ """
51
+ Map element node labels to their corresponding indices in the node matrix.
52
+
53
+ Parameters
54
+ ----------
55
+ element_matrix : np.ndarray
56
+ Array of elements with shape (n_elements, m), where columns 1 and 2 contain node IDs for each element.
57
+ node_matrix : np.ndarray
58
+ Array of nodes with shape (n_nodes, k), where column 0 contains node IDs.
59
+ return_as_flat : bool, optional
60
+ If True, returns a 1D array of unique node indices used by all elements.
61
+ If False, returns a 2D array of shape (n_elements, 2) with node indices for each element.
62
+ Default is False.
63
+
64
+ Returns
65
+ -------
66
+ np.ndarray
67
+ If return_as_flat is False, returns a 2D array of node indices for each element (shape: n_elements, 2).
68
+ If return_as_flat is True, returns a 1D array of unique node indices.
69
+
70
+ Notes
71
+ -----
72
+ Each element is assumed to be defined by two node labels in columns 1 and 2 of element_matrix. Docstring is generated by GitHub Copilot.
73
+ """
74
+ nodeix = [None] * len(element_matrix[:, 0])
75
+ for element_ix, __ in enumerate(element_matrix[:, 0]):
76
+ node1 = element_matrix[element_ix, 1]
77
+ node2 = element_matrix[element_ix, 2]
78
+
79
+ nodeix1 = np.where(node_matrix[:, 0] == node1)[0][0]
80
+ nodeix2 = np.where(node_matrix[:, 0] == node2)[0][0]
81
+ nodeix[element_ix] = [nodeix1, nodeix2]
82
+
83
+ nodeix = np.array(nodeix)
84
+
85
+ if return_as_flat:
86
+ nodeix = np.unique(nodeix.flatten())
87
+
88
+ return nodeix
89
+
90
+
91
+ def create_node_dict(element_dict, node_labels, x_nodes, y_nodes, z_nodes):
92
+ """
93
+ Creates a dictionary mapping element keys to their corresponding node data.
94
+
95
+ Parameters
96
+ ----------
97
+ element_dict : dict
98
+ A dictionary where each key corresponds to an element and each value contains information
99
+ about the nodes associated with that element.
100
+ node_labels : array-like
101
+ An array of node labels/IDs.
102
+ x_nodes : array-like
103
+ An array of x-coordinates for each node.
104
+ y_nodes : array-like
105
+ An array of y-coordinates for each node.
106
+ z_nodes : array-like
107
+ An array of z-coordinates for each node.
108
+
109
+ Returns
110
+ -------
111
+ node_dict : dict
112
+ A dictionary where each key matches an element key from `element_dict`, and each value is
113
+ an array containing the node label and coordinates (label, x, y, z) for the nodes
114
+ associated with that element.
115
+
116
+ Notes
117
+ -----
118
+ This function relies on the helper function `nodeix_from_elements` to determine the indices
119
+ of nodes associated with each element. Docstring is generated by GitHub Copilot.
120
+ """
121
+
122
+ node_dict = dict()
123
+ node_matrix = np.vstack([node_labels, x_nodes, y_nodes, z_nodes]).T
124
+
125
+ for key in element_dict.keys():
126
+ node_ix = nodeix_from_elements(element_dict[key], node_matrix, return_as_flat=True)
127
+ node_dict[key] = node_matrix[node_ix, :]
128
+
129
+ return node_dict
130
+
131
+
132
+ def elements_with_node(element_matrix, node_label):
133
+ """
134
+ Finds elements containing a specific node and returns their labels, indices, and local node indices.
135
+
136
+ Parameters
137
+ ----------
138
+ element_matrix : np.ndarray
139
+ A 2D array where each row represents an element. The first column contains element labels,
140
+ and the second and third columns contain node labels associated with each element.
141
+ node_label : int or float
142
+ The node label to search for within the element matrix.
143
+
144
+ Returns
145
+ -------
146
+ element_labels : np.ndarray
147
+ Array of element labels that contain the specified node.
148
+ element_ixs : np.ndarray
149
+ Array of indices in `element_matrix` where the specified node is found.
150
+ local_node_ix : np.ndarray
151
+ Array indicating the local node index (0 or 1) within each element where the node is found.
152
+
153
+ Examples
154
+ --------
155
+ >>> element_matrix = np.array([[1, 10, 20],
156
+ ... [2, 20, 30],
157
+ ... [3, 10, 30]])
158
+ >>> elements_with_node(element_matrix, 10)
159
+ (array([1, 3]), array([0, 2]), array([0., 0.]))
160
+
161
+ Notes
162
+ ---------
163
+ Docstring is generated by GitHub Copilot.
164
+ """
165
+ element_ixs1 = np.array(np.where(element_matrix[:,1]==node_label)).flatten()
166
+ element_ixs2 = np.array(np.where(element_matrix[:,2]==node_label)).flatten()
167
+
168
+ element_ixs = np.hstack([element_ixs1, element_ixs2])
169
+ element_labels = element_matrix[element_ixs, 0]
170
+
171
+ local_node_ix = np.zeros(np.shape(element_ixs))
172
+ local_node_ix[np.arange(0,len(element_ixs1))] = 0
173
+ local_node_ix[np.arange(len(element_ixs1), len(element_ixs1) + len(element_ixs2))] = 1
174
+
175
+ return element_labels, element_ixs, local_node_ix
176
+
177
+
178
+ def nodes_to_beam_element_matrix(node_labels, first_element_label=1):
179
+ """
180
+ Generates an element connectivity matrix for beam elements from a sequence of node labels.
181
+
182
+ Parameters
183
+ ----------
184
+ node_labels : array_like
185
+ Sequence of node labels (integers or floats) defining the order of nodes along the beam.
186
+ first_element_label : int, optional
187
+ The label to assign to the first element. Default is 1.
188
+
189
+ Returns
190
+ -------
191
+ element_matrix : ndarray of shape (n_elements, 3)
192
+ Array where each row represents a beam element. The columns are:
193
+ [element_label, start_node_label, end_node_label].
194
+
195
+ Examples
196
+ --------
197
+ >>> nodes = [10, 20, 30, 40]
198
+ >>> nodes_to_beam_element_matrix(nodes)
199
+ array([[ 1., 10., 20.],
200
+ [ 2., 20., 30.],
201
+ [ 3., 30., 40.]])
202
+
203
+ Notes
204
+ ---------
205
+ Docstring is generated by GitHub Copilot.
206
+ """
207
+
208
+ n_nodes = len(node_labels)
209
+ n_elements = n_nodes-1
210
+
211
+ element_matrix = np.empty([n_elements, 3])
212
+ element_matrix[:, 0] = np.arange(first_element_label,first_element_label+n_elements)
213
+ element_matrix[:, 1] = node_labels[0:-1]
214
+ element_matrix[:, 2] = node_labels[1:]
215
+
216
+ return element_matrix
217
+
218
+
219
+ def node_ix_to_dof_ix(node_ix, n_dofs=6):
220
+ """
221
+ Converts a node index to a degree of freedom (DOF) index.
222
+ Each node has n_dofs degrees of freedom, and this function returns the corresponding DOF indices.
223
+
224
+ Parameters
225
+ ----------
226
+ node_ix : int
227
+ Index of the node for which to find the DOF indices.
228
+ n_dofs : int, optional
229
+ Number of degrees of freedom per node. Default is 6.
230
+
231
+ Returns
232
+ -------
233
+ dof_ix : np.ndarray
234
+ Array of DOF indices corresponding to the given node index.
235
+
236
+ Examples
237
+ --------
238
+ >>> node_ix = 2
239
+ >>> n_dofs = 6
240
+ >>> dof_ix = node_ix_to_dof_ix(node_ix, n_dofs)
241
+ >>> print(dof_ix)
242
+ [12 13 14 15 16 17]
243
+
244
+ Notes
245
+ --------
246
+ Docstring is generated by GitHub Copilot.
247
+
248
+ """
249
+ start = node_ix*n_dofs
250
+ stop = node_ix*n_dofs+n_dofs
251
+ dof_ix = []
252
+ for (i,j) in zip(start,stop):
253
+ dof_ix.append(np.arange(i,j))
254
+
255
+ dof_ix = np.array(dof_ix).flatten()
256
+
257
+ return dof_ix
258
+
259
+
260
+ def dof_sel(arr, dof_sel, n_dofs=6, axis=0):
261
+ """
262
+ Selects degrees of freedom (DOFs) from an array along a specified axis.
263
+
264
+ Parameters
265
+ ----------
266
+ arr : np.ndarray
267
+ Input array from which to select DOFs.
268
+ dof_sel : array-like
269
+ Indices of the DOFs to select (relative to each block of n_dofs).
270
+ n_dofs : int, optional
271
+ Number of DOFs per node or block. Default is 6.
272
+ axis : int, optional
273
+ Axis along which to select DOFs. Default is 0.
274
+
275
+ Returns
276
+ -------
277
+ arr_sel : np.ndarray
278
+ Array containing only the selected DOFs along the specified axis.
279
+
280
+ Examples
281
+ --------
282
+ >>> arr = np.arange(18).reshape(3, 6)
283
+ >>> dof_sel(arr, [0, 2], n_dofs=6, axis=1)
284
+ array([[ 0, 2],
285
+ [ 6, 8],
286
+ [12, 14]])
287
+
288
+ Notes
289
+ -------
290
+ Docstring is generated by GitHub Copilot.
291
+ """
292
+
293
+ N = np.shape(arr)[axis]
294
+ all_ix = [range(dof_sel_i, N, n_dofs) for dof_sel_i in dof_sel]
295
+ sel_ix = np.array(all_ix).T.flatten()
296
+
297
+ # Select the elements
298
+ arr_sel = np.take(arr, sel_ix, axis=axis)
299
+
300
+ return arr_sel
301
+
302
+
303
+
304
+ def elements_from_common_nodes(element_matrix, selected_nodes):
305
+ """
306
+ Find elements that have both nodes in `selected_nodes`.
307
+
308
+ Parameters
309
+ ----------
310
+ element_matrix : np.ndarray
311
+ Array of elements with shape (n_elements, 3), where columns are [element_id, node1, node2].
312
+ selected_nodes : array-like
313
+ List or array of node labels to search for.
314
+
315
+ Returns
316
+ -------
317
+ selected_element_matrix : np.ndarray
318
+ Subset of `element_matrix` where both nodes are in `selected_nodes`.
319
+ sel_ix : np.ndarray
320
+ Indices of the selected elements in the original `element_matrix`.
321
+
322
+ Notes
323
+ -----
324
+ Only elements where both node1 and node2 are in `selected_nodes` are selected. Docstring is generated by GitHub Copilot.
325
+ """
326
+
327
+ mask = np.isin(element_matrix[:, 1], selected_nodes) & np.isin(element_matrix[:, 2], selected_nodes)
328
+ sel_ix = np.where(mask)[0]
329
+ selected_element_matrix = element_matrix[sel_ix, :]
330
+
331
+ return selected_element_matrix, sel_ix
332
+
333
+
334
+ def transform_elements(node_matrix, element_matrix, e2p, repeats=1):
335
+ """
336
+ Transforms elements from global to local coordinates.
337
+ Given a node matrix and an element matrix, this function computes the transformation matrices
338
+ from global to local coordinates for each element. The transformation is based on the direction
339
+ vector between the nodes of each element. The transformation matrices are constructed using
340
+ the `transform_unit` function and are repeated as specified.
341
+
342
+ Parameters
343
+ ----------
344
+ node_matrix : np.ndarray
345
+ Array of node data. The first column should contain node IDs, and the remaining columns
346
+ should contain node coordinates.
347
+ element_matrix : np.ndarray
348
+ Array of element data. Each row corresponds to an element, with the first column as the
349
+ element ID and the next columns as node IDs defining the element.
350
+ e2p : np.ndarray or similar
351
+ Additional parameter passed to `transform_unit` for transformation construction.
352
+ repeats : int, optional
353
+ Number of times to repeat the transformation block (default is 1).
354
+
355
+ Returns
356
+ -------
357
+ list of np.ndarray
358
+ List of transformation matrices, one for each element, mapping global to local coordinates.
359
+
360
+ Notes
361
+ -----
362
+ - Assumes that `transform_unit` and `blkdiag` functions are defined elsewhere.
363
+ - The function matches node IDs between `element_matrix` and `node_matrix` to determine node positions.
364
+ Docstring is generated by GitHub Copilot.
365
+ """
366
+
367
+ n_elements = np.shape(element_matrix)[0]
368
+ T_g2el = [None]*n_elements
369
+
370
+ for el in range(0, n_elements):
371
+ n1_ix = np.where(node_matrix[:,0]==element_matrix[el, 1])
372
+ n2_ix = np.where(node_matrix[:,0]==element_matrix[el, 2])
373
+
374
+ X1 = node_matrix[n1_ix, 1:]
375
+ X2 = node_matrix[n2_ix, 1:]
376
+ dx = X2-X1
377
+ e1 = dx/np.linalg.norm(dx)
378
+
379
+ T_g2el[el] = blkdiag(transform_unit(e1, e2p), repeats) # Transform from global to local coordinates VLocal = T*VGlobal
380
+
381
+ return T_g2el