wawi 0.0.8__py3-none-any.whl → 0.0.9__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.

Potentially problematic release.


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

@@ -0,0 +1,263 @@
1
+ import pytest
2
+ import numpy as np
3
+ from math import isclose
4
+ import dill
5
+
6
+ # use the local wawi (Github folder) instead of the installed version (remove this when using the installed version)
7
+ import sys
8
+ import os
9
+ sys.path.insert(0, os.path.abspath('C:\\Users\\aksef\\Documents\\GitHub\\wawi'))
10
+
11
+ from wawi.io import import_folder
12
+ from wawi.model import Windstate
13
+ from wawi.wind import ADs
14
+ from wawi.wind import itflutter_cont_naive
15
+
16
+ model_folder = './tests/models/model_2a'
17
+
18
+ def AD_dict(AD_funs):
19
+ AD_s = dict(
20
+ A1 = lambda v: -AD_funs['a_fun'][0](v), # sign convention
21
+ A2 = AD_funs['a_fun'][1],
22
+ A3 = AD_funs['a_fun'][2],
23
+ A4 = lambda v: -AD_funs['a_fun'][3](v),
24
+ A5 = lambda v: -AD_funs['a_fun'][4](v),
25
+ A6 = lambda v: -AD_funs['a_fun'][5](v),
26
+
27
+ H1 = AD_funs['h_fun'][0],
28
+ H2 = lambda v: -AD_funs['h_fun'][1](v),
29
+ H3 = lambda v: -AD_funs['h_fun'][2](v),
30
+ H4 = AD_funs['h_fun'][3],
31
+ H5 = AD_funs['h_fun'][4],
32
+ H6 = AD_funs['h_fun'][5],
33
+
34
+ P1 = AD_funs['p_fun'][0],
35
+ P2 = lambda v: -AD_funs['p_fun'][1](v),
36
+ P3 = lambda v: -AD_funs['p_fun'][2](v),
37
+ P4 = AD_funs['p_fun'][3],
38
+ P5 = AD_funs['p_fun'][4],
39
+ P6 = AD_funs['p_fun'][5],
40
+ )
41
+ return AD_s
42
+
43
+ def iabse_2a_windstate(mean_v):
44
+ windstate = Windstate(mean_v,
45
+ 90,
46
+ Iu=0.1,
47
+ Iw=0.05,
48
+ Au=6.8, Aw=9.4, # not used in von Karman
49
+ Cuy=10.0, Cwy=6.5,
50
+ Cuz=10.0, Cwz=3.0,
51
+ Lux=200.0, Lwx=20.0,
52
+ x_ref=[0,0,0], rho=1.22,
53
+ spectrum_type='vonKarman'
54
+ )
55
+
56
+ return windstate
57
+
58
+ davenport = lambda fred: 2*(7*fred-1+np.exp(-7*fred))/(7*fred)**2
59
+
60
+ @pytest.mark.parametrize(
61
+ 'V, expected_f, expected_zeta, tol',
62
+ [(15, 0.274, 0.008 , 0.1),
63
+ (30, 0.267, 0.014, 0.1),
64
+ (45, 0.254 , 0.019, 0.1),
65
+ (60, 0.234, 0.015, 0.1),
66
+ (68, 0.220 , 0.004, 0.15)],
67
+ )
68
+
69
+ def test_in_wind_frequencies_and_damping( V, expected_f, expected_zeta, tol):
70
+ # importing the relevant model
71
+ model = import_folder(model_folder)
72
+ model.modal_dry.xi0 = .3e-2
73
+
74
+ # assign ADs (BB3 ADs)
75
+ with open( model_folder + '/AD_funs_BB3_scanlan.pkl', 'rb') as file:
76
+ AD_funs = dill.load(file)
77
+ AD_s = AD_dict(AD_funs)
78
+ for key in model.aero.sections:
79
+ model.aero.sections[key].ADs = ADs(**AD_s)
80
+
81
+ model.aero.windstate = iabse_2a_windstate(V)
82
+ model.run_eig(w_initial=model.modal_dry.omega_n.tolist(), freq_kind=True, itmax=100)
83
+ lambd = model.results.lambd
84
+
85
+ f9 = np.abs(lambd[8].imag) / (2*np.pi)
86
+ zeta9 = -lambd[8].real/ np.abs(lambd[8])
87
+
88
+ assert isclose(f9, expected_f, rel_tol = tol)
89
+ assert isclose(zeta9, expected_zeta, rel_tol = tol)
90
+
91
+ # flutter speed
92
+ def test_flutter():
93
+ expected_flutter_speed = 69.8 # m/s (reference value from paper)
94
+ tol = 0.01
95
+ with open( model_folder + '/AD_funs_BB3_scanlan.pkl', 'rb') as file:
96
+ AD_funs = dill.load(file)
97
+ ad_dict = AD_dict(AD_funs)
98
+
99
+ # importing the relevant model
100
+ model = import_folder(model_folder)
101
+ model.modal_dry.xi0 = .3e-2
102
+ B = model.aero.sections['girder'].B
103
+
104
+ Ms = model.dry_M
105
+ Cs = model.dry_C
106
+ Ks = model.dry_K
107
+ phi = model.get_dry_phi('full')
108
+
109
+ # calculate the flutter speed
110
+ x_coor = [node.coordinates[0] for node in model.eldef.nodes ]
111
+
112
+ res = itflutter_cont_naive(Ms, Cs, Ks, phi, x_coor, ad_dict, B, V=0.1, rho=1.22, dV=5,
113
+ overshoot_factor=0.5, itmax={}, tol={}, print_progress=True)
114
+
115
+ assert isclose(res['V'][-1], expected_flutter_speed, rel_tol = tol)
116
+
117
+
118
+ # spectra of vertical and torsional response at 45 m/s
119
+ def test_RS_spectra():
120
+
121
+ V = 45
122
+
123
+ # omega_axis
124
+ omega = (2*np.pi)*np.array([0.086, 0.1, 0.123, 0.142, 0.151, 0.179, 0.2, 0.236, 0.247, 0.262, 0.278, 0.283, 0.3, 0.379,])
125
+
126
+ Sz_midspan_expected = np.array([2.5816E+00 ,
127
+ 3.9291E+00 ,
128
+ 1.2792E+00 ,
129
+ 8.3683E-01 ,
130
+ 3.6548E-01 ,
131
+ 6.1153E-02 ,
132
+ 2.5616E-02 ,
133
+ ])
134
+ Szeq_midspan_expected = np.array([9.7440E-03 ,
135
+ 4.1529E-03 ,
136
+ 1.1582E-02 ,
137
+ 1.2131E-02 ,
138
+ 1.2402E-02 ,
139
+ 1.4801E-02 ,
140
+ 2.0026E-02 ,
141
+ 9.3995E-02 ,
142
+ 3.5115E-01 ,
143
+ 2.9514E-01 ,
144
+ 3.1238E-02 ,
145
+ 2.0048E-02 ,
146
+ 6.3728E-03 ,
147
+ ])
148
+ Sz_qspan_expected = np.array([5.7483E+00 ,
149
+ 2.3605E+00 ,
150
+ 7.0894E-01 ,
151
+ 4.9097E-01 ,
152
+ 2.1767E-01 ,
153
+ 3.9699E-02 ,
154
+ 1.7792E-02 ,
155
+ ])
156
+ Szeq_qspan_expected = np.array([4.0150E-03 ,
157
+ 3.5677E-03 ,
158
+ 4.8657E-03 ,
159
+ 5.4711E-03 ,
160
+ 5.5522E-03 ,
161
+ 6.1715E-03 ,
162
+ 7.8843E-03 ,
163
+ 3.2631E-02 ,
164
+ 1.1894E-01 ,
165
+ 1.0044E-01 ,
166
+ 1.1859E-02 ,
167
+ 8.1749E-03 ,
168
+ 3.9972E-03 ,
169
+ 1.5413E-02 ,
170
+ ])
171
+
172
+ # import the model and assign properties
173
+ model = import_folder(model_folder)
174
+ model.modal_dry.xi0 = .3e-2
175
+
176
+ # assign ADs (BB3 ADs)
177
+ with open( model_folder + '/AD_funs_BB3_scanlan.pkl', 'rb') as file:
178
+ AD_funs = dill.load(file)
179
+ AD_s = AD_dict(AD_funs)
180
+ for key in model.aero.sections:
181
+ model.aero.sections[key].ADs = ADs(**AD_s)
182
+
183
+ # assign windstate
184
+ model.aero.windstate = iabse_2a_windstate(V)
185
+ # admittance
186
+ for key in model.aero.sections:
187
+ model.aero.sections[key].Admittance = lambda fred: np.full((4, 3), davenport(fred))
188
+
189
+ # run analysis
190
+ model.run_freqsim(omega,
191
+ include_selfexcited=['aero'],
192
+ include_action=['aero'],
193
+ print_progress=False, merge_aero_sections=True,
194
+ ensure_at_peaks=False) # keep the given frequency axis
195
+
196
+
197
+ # extract PSD - at the midpsan
198
+ global_dof_ix_ms = model.eldef.node_dof_lookup(36) # node 36 is the midspan node
199
+ S = model.get_result_psd(key='full',
200
+ index=global_dof_ix_ms[1:4])
201
+ # extract PSD - at the quarter-span
202
+ global_dof_ix_qs = model.eldef.node_dof_lookup(26) # node 26 is the quarter-span node
203
+ Sq = model.get_result_psd(key='full',
204
+ index=global_dof_ix_qs[1:4])
205
+
206
+ assert np.allclose((2*np.pi)*S[1,1,range(len(Sz_midspan_expected))], Sz_midspan_expected, rtol=1e-1)
207
+ assert np.allclose((31/2)**2*(2*np.pi)*S[2,2,range(len(Szeq_midspan_expected))], Szeq_midspan_expected, rtol=2e-1)
208
+
209
+ assert np.allclose((2*np.pi)*Sq[1,1,range(len(Sz_qspan_expected))], Sz_qspan_expected, rtol=1e-1)
210
+ assert np.allclose((31/2)**2*(2*np.pi)*Sq[2,2,range(len(Szeq_qspan_expected))], Szeq_qspan_expected, rtol=35e-2)
211
+
212
+ # buffeting responses (RMS values)
213
+ @pytest.mark.parametrize(
214
+ 'Vbuff, RMS_horz_exp1, RMS_vert_exp1, RMS_tors_exp1, RMS_horz_exp2, RMS_vert_exp2, RMS_tors_exp2',
215
+ [(15., 0.019, 0.058, 0.009, 0.015, 0.078, 0.006 ),
216
+ (30., 0.128, 0.238, 0.051, 0.091, 0.296, 0.035 ),
217
+ (45., 0.316, 0.508, 0.150, 0.225, 0.563, 0.103 ),
218
+ (60., 0.557, 0.879, 0.417, 0.413, 0.880, 0.273 ),
219
+ ],
220
+ )
221
+
222
+ def test_RMS_response(Vbuff, RMS_horz_exp1, RMS_vert_exp1, RMS_tors_exp1, RMS_horz_exp2, RMS_vert_exp2, RMS_tors_exp2):
223
+ omega = np.linspace(0.0001, 4, 3000)
224
+
225
+ # import the model and assign properties
226
+ model = import_folder(model_folder)
227
+ model.modal_dry.xi0 = .3e-2
228
+
229
+ # assign ADs (BB3 ADs)
230
+ with open( model_folder + '/AD_funs_BB3_scanlan.pkl', 'rb') as file:
231
+ AD_funs = dill.load(file)
232
+ AD_s = AD_dict(AD_funs)
233
+ for key in model.aero.sections:
234
+ model.aero.sections[key].ADs = ADs(**AD_s)
235
+
236
+ # assign windstate
237
+ model.aero.windstate = iabse_2a_windstate(Vbuff)
238
+ # admittance
239
+ for key in model.aero.sections:
240
+ model.aero.sections[key].Admittance = lambda fred: np.full((4, 3), davenport(fred))
241
+
242
+ #model.run_eig(w_initial=model.modal_dry.omega_n.tolist(), freq_kind=True, itmax=100) # alters integration
243
+
244
+ # run analysis
245
+ model.run_freqsim(omega,
246
+ include_selfexcited=['aero'],
247
+ include_action=['aero'],
248
+ print_progress=False, merge_aero_sections=True)
249
+ # RMS responses
250
+ stds = model.get_result_std(key = 'full')
251
+ # global dofs
252
+ global_dof_ix1 = model.eldef.node_dof_lookup(36)[1:4]
253
+ global_dof_ix2 = model.eldef.node_dof_lookup(26)[1:4]
254
+
255
+ assert isclose(stds[global_dof_ix1][0], RMS_horz_exp1, rel_tol = 15e-2) # midspan horizontal
256
+ assert isclose(stds[global_dof_ix1][1], RMS_vert_exp1, rel_tol = 15e-2) # midspan vertical
257
+ assert isclose(stds[global_dof_ix1][2]*31/2, RMS_tors_exp1, rel_tol = 15e-2) # midspan torsional
258
+
259
+ assert isclose(stds[global_dof_ix2][0], RMS_horz_exp2, rel_tol = 15e-2) # q-span horizontal
260
+ assert isclose(stds[global_dof_ix2][1], RMS_vert_exp2, rel_tol = 15e-2) # q-span vertical
261
+ assert isclose(stds[global_dof_ix2][2]*31/2, RMS_tors_exp2, rel_tol = 20e-2) # q-span torsional
262
+
263
+
tests/test_wind.py ADDED
@@ -0,0 +1,71 @@
1
+
2
+ # test wind functions
3
+
4
+ # wind state
5
+
6
+ # from wawi.model import Windstate
7
+
8
+ # use the local wawi (Github folder) instead of the installed version
9
+ import sys
10
+ import os
11
+ sys.path.insert(0, os.path.abspath('C:\\Users\\aksef\\Documents\\GitHub\\wawi'))
12
+ from wawi.model import Windstate
13
+
14
+
15
+ from math import isclose
16
+
17
+
18
+ def test_windstate():
19
+
20
+ V0 = 40.0 # these could be also parametrized
21
+
22
+ dir = 45
23
+ Iu=2.0/V0
24
+ Iw=1.0/V0
25
+ Au=30
26
+ Aw=3
27
+ Cuy=10.0
28
+ Cwy=8.0
29
+ Cuz=10.0
30
+ Cwz=8.0
31
+ Lux=60
32
+ Lwx=60
33
+ x_ref=[0,0,0]
34
+ rho=1.25
35
+
36
+ tol = 1e-5
37
+
38
+ # Act
39
+ windstate = Windstate(V0,
40
+ dir,
41
+ Iu=Iu,
42
+ Iw=Iw,
43
+ Au=Au, Aw=Aw,
44
+ Cuy=Cuy, Cwy=Cwy,
45
+ Cuz=Cuz, Cwz=Cwz,
46
+ Lux=Lux, Lwx=Lwx,
47
+ x_ref=x_ref, rho=rho)
48
+
49
+ # Assert
50
+ assert isclose(windstate.V0, V0, rel_tol = tol)
51
+ assert isclose(windstate.direction, dir, rel_tol = tol)
52
+ assert isclose(windstate.Iu, Iu, rel_tol = tol)
53
+ assert isclose(windstate.Iw, Iw, rel_tol = tol)
54
+ assert isclose(windstate.Au, Au, rel_tol = tol)
55
+ assert isclose(windstate.Aw, Aw, rel_tol = tol)
56
+
57
+ assert isclose(windstate.Cuy, Cuy, rel_tol = tol)
58
+ assert isclose(windstate.Cwy, Cwy, rel_tol = tol)
59
+ assert isclose(windstate.Cuz, Cuz, rel_tol = tol)
60
+ assert isclose(windstate.Cwz, Cwz, rel_tol = tol)
61
+
62
+ assert isclose(windstate.Lux, Lux, rel_tol = tol)
63
+ assert isclose(windstate.Lwx, Lwx, rel_tol = tol)
64
+ assert isclose(windstate.rho, rho, rel_tol = tol)
65
+
66
+ assert all(abs(a - b) <= tol for a, b in zip(windstate.x_ref, x_ref))
67
+
68
+
69
+
70
+
71
+
wawi/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "0.0.8"
1
+ __version__ = "0.0.9"
2
2
 
3
3
  __pdoc__ = dict()
4
4
  __pdoc__['wawi.abq'] = False
wawi/ext/__init__.py ADDED
File without changes
wawi/ext/abq.py ADDED
@@ -0,0 +1,259 @@
1
+ import numpy as np
2
+ import numpy as np
3
+ import pdb
4
+
5
+ from abaqus import *
6
+ from abaqus import session
7
+ from abaqusConstants import *
8
+ import __main__
9
+ import section
10
+ import regionToolset
11
+ import displayGroupMdbToolset as dgm
12
+ import step
13
+ import part
14
+ import material
15
+ import assembly
16
+ import interaction
17
+ import load
18
+ import mesh
19
+ import optimization
20
+ import job
21
+ import sketch
22
+ import visualization
23
+ import xyPlot
24
+ import displayGroupOdbToolset as dgo
25
+ import connectorBehavior
26
+ import symbolicConstants
27
+ import odbAccess
28
+ import shutil
29
+
30
+ import regionToolset
31
+
32
+ import csv
33
+ from copy import deepcopy
34
+
35
+
36
+ def get_db(db_type):
37
+ """
38
+ Return the current database (either a model or an odb object).
39
+
40
+ If a model db is wanted and no model is active, the model in the mdb is selected regardless,
41
+ as long as there is only one model open in the mdb. If no database fits the requirements, None is returned.
42
+
43
+ Args:
44
+ db_type: 'odb' or 'model'
45
+ Returns:
46
+ db: database
47
+
48
+ NTNU / Knut Andreas Kvaale, 2018
49
+ """
50
+ if db_type is 'model' or db_type is 'mdb':
51
+ if not session_is_odb():
52
+ db = mdb.models[session.viewports['Viewport: 1'].displayedObject.modelName]
53
+ elif len(mdb.models.keys()) is 1:
54
+ db = mdb.models[mdb.models.keys()[0]]
55
+ elif len(mdb.models.keys()) > 1:
56
+ raise AttributeError('No model is not active, and more than one model is available in model database. Impossible to select correct.')
57
+ else:
58
+ db = None
59
+ else:
60
+ if session_is_odb():
61
+ db = session.viewports[session.currentViewportName].displayedObject
62
+ else:
63
+ db = None
64
+
65
+ return db
66
+
67
+ def session_is_odb():
68
+ """
69
+ Check if current session is ODB.
70
+
71
+ Returns:
72
+ is_odb: boolean indicating if the session is odb or not
73
+ """
74
+ is_odb =(('session' in locals() or 'session' in globals()) and
75
+ session.viewports['Viewport: 1'].displayedObject is not None and
76
+ hasattr(session.viewports['Viewport: 1'].displayedObject, 'jobData'))
77
+
78
+ return is_odb
79
+
80
+ def sort_nodes(nodes, sort_nodes_fun=lambda node: node.label):
81
+ if sort_nodes_fun is not None:
82
+ sort_val = [sort_nodes_fun(node) for node in nodes]
83
+ sort_ix = np.argsort(sort_val)
84
+ nodes_new = [None] * len(nodes)
85
+ for node,ix in zip(nodes,sort_ix):
86
+ nodes_new[ix] = node
87
+
88
+ return nodes_new
89
+ else:
90
+ return nodes
91
+
92
+ def get_element_matrices(region, obj=None, sort_nodes_fun=lambda node: node.label):
93
+
94
+ if region.nodes is None: #element region
95
+ if obj is None:
96
+ raise ValueError('If region is of element type, `obj` must be given as input. This is either an `instance` object or a `rootAssembly`')
97
+
98
+ elements = region.elements
99
+ element_labels = [el.label for el in elements]
100
+ element_matrix = np.zeros([len(element_labels), 3])
101
+
102
+ node_labels = []
103
+ for ix,el in enumerate(elements):
104
+ element_matrix[ix,0] = el.label
105
+ nodes = list(el.connectivity)
106
+ if len(nodes)==3:
107
+ __ = nodes.pop(1) #remove middle node
108
+ element_matrix[ix, 1:] = nodes
109
+
110
+ for node in nodes:
111
+ if node not in node_labels:
112
+ node_labels.append(node)
113
+
114
+ nodes = [obj.getNodeFromLabel(node) for node in node_labels]
115
+ nodes = sort_nodes(nodes, sort_nodes_fun=sort_nodes_fun)
116
+ node_matrix = create_node_matrix(nodes)
117
+ return node_matrix, element_matrix
118
+
119
+ else: # node region
120
+ if type(region.nodes) is tuple:
121
+ nodes = region.nodes[0]
122
+ else:
123
+ nodes = region.nodes
124
+ nodes = sort_nodes(nodes, sort_nodes_fun=sort_nodes_fun)
125
+ node_matrix = create_node_matrix(nodes)
126
+
127
+ return node_matrix
128
+
129
+
130
+ def create_list_of_nodes(region, node_labels):
131
+ return [region.getNodeFromLabel(int(label)) for label in node_labels]
132
+
133
+ def create_list_of_elements(region, element_labels):
134
+ return [region.getElementFromLabel(int(label)) for label in element_labels]
135
+
136
+ def create_node_matrix(nodes):
137
+ labels = np.hstack([node.label for node in nodes])[:,np.newaxis]
138
+ coordinates = np.vstack([node.coordinates for node in nodes])
139
+ node_matrix = np.hstack([labels, coordinates])
140
+
141
+ return node_matrix
142
+
143
+ def get_nodal_phi(step_obj, nodes, field_outputs=['U', 'UR'], flatten_components=True, return_base_disp=False):
144
+
145
+ if step_obj.domain != MODAL: #MODAL is a variable in abaqusConstants
146
+ raise TypeError('Type of input step is not modal!')
147
+
148
+ n_nodes = len(nodes)
149
+ n_modes = len(step_obj.frames) - 1
150
+
151
+ phi = dict()
152
+ basedisp = dict()
153
+ n_dofs = dict()
154
+
155
+ for iout, field_output in enumerate(field_outputs):
156
+ foobj0 = step_obj.frames[0].fieldOutputs[field_output]
157
+
158
+ n_dofs[field_output] = len(foobj0.values[0].data)
159
+ phio = np.zeros([n_dofs[field_output]*n_nodes, n_modes])
160
+
161
+ # Get correct data indices to get correct order (as given in node_labels)
162
+ basedisp[field_output] = np.array([foobj0.getSubset(region=node).values[0].data for node in nodes]).flatten()
163
+
164
+ for mode in range(0, n_modes):
165
+ foobj = step_obj.frames[mode+1].fieldOutputs[field_output]
166
+ phio[:, mode] = np.array([foobj.getSubset(region=node).values[0].data for node in nodes]).flatten()
167
+
168
+ phi[field_output] = phio*1
169
+
170
+ if flatten_components:
171
+ phi_merged = [None]*n_modes
172
+
173
+ for mode in range(n_modes):
174
+ phi_merged[mode] = np.hstack([np.array(phi[key][:, mode]).reshape([-1,n_dofs[key]]) for key in field_outputs]).flatten()
175
+
176
+ basedisp = np.hstack([np.array(basedisp[key]).reshape([-1,n_dofs[key]]) for key in field_outputs]).flatten()
177
+ phi = np.vstack(phi_merged).T
178
+
179
+ if return_base_disp:
180
+ return phi, basedisp
181
+ else:
182
+ return phi
183
+
184
+
185
+ def get_element_phi(step_obj, elements, field_outputs=['SF', 'SM'], flatten_components=True, return_integration_points=False):
186
+ if step_obj.domain != MODAL: #MODAL is a variable in abaqusConstants
187
+ raise TypeError('Type of input step is not modal!')
188
+
189
+ n_modes = len(step_obj.frames) - 1
190
+ n_dofs = dict()
191
+ phi = dict()
192
+ integration_points = dict()
193
+
194
+ for iout, field_output in enumerate(field_outputs):
195
+ foobj0 = step_obj.frames[0].fieldOutputs[field_output]
196
+ n_dofs[field_output] = len(foobj0.values[0].data)
197
+
198
+ # Get correct data indices to get correct order (as given in node_labels)
199
+ all_integration_points = [value.integrationPoint for value in foobj0.values]
200
+
201
+ n_int = len(elements) # number of integration points (same element label might appear multiple times if multiple integration points in element)
202
+ phio = np.zeros([n_dofs[field_output]*n_int, n_modes])
203
+
204
+ data_indices = [None]*n_int
205
+
206
+ for mode in range(0, n_modes):
207
+ foobj = step_obj.frames[mode+1].fieldOutputs[field_output]
208
+ phio[:, mode] = np.array([foobj.getSubset(region=el)[0].data for el in elements]).flatten()
209
+
210
+ integration_points[field_output] = [all_integration_points[ix] for ix in data_indices]
211
+ phi[field_output] = phio*1
212
+
213
+ if flatten_components:
214
+ phi_merged = [None]*n_modes
215
+
216
+ for mode in range(n_modes):
217
+ phi_merged[mode] = np.hstack([np.array(phi[key][:, mode]).reshape([-1,n_dofs[key]]) for key in field_outputs]).flatten()
218
+
219
+ integration_points = np.hstack([np.array(integration_points[key]).reshape([-1,n_dofs[key]]) for key in field_outputs]).flatten()
220
+ phi = np.vstack(phi_merged).T
221
+
222
+
223
+ if return_integration_points:
224
+ return phi, integration_points
225
+ else:
226
+ return phi
227
+
228
+ return phi, integration_points
229
+
230
+
231
+ def get_modal_parameters(frequency_step):
232
+ '''
233
+ Output the modal parameters from frequency step of current output database.
234
+
235
+ Parameters
236
+ -------------
237
+ frequency_step : str
238
+ name of step containing the modal results (frequency step)
239
+
240
+ Returns
241
+ --------------
242
+ f : float
243
+ numpy array with undamped natural frequencies in Hz of all modes computed
244
+ m : float
245
+ numpy array with modal mass for all modes computed
246
+ '''
247
+
248
+ odb = get_db('odb')
249
+ history_region_key = odb.steps[frequency_step].historyRegions.keys()[0]
250
+
251
+ ftemp = odb.steps[frequency_step].historyRegions[history_region_key].historyOutputs['EIGFREQ'].data
252
+ f = np.array([x[1] for x in ftemp])
253
+
254
+ if 'GM' in odb.steps[frequency_step].historyRegions[history_region_key].historyOutputs.keys():
255
+ mtemp = odb.steps[frequency_step].historyRegions[history_region_key].historyOutputs['GM'].data
256
+ m = np.array([x[1] for x in mtemp])
257
+ else:
258
+ m = np.ones(np.shape(f)) #if no GM field is available, mass normalization is assumed used on eigenvalues
259
+ return f, m