wawi 0.0.7__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.
- examples/3 Software interfacing/Abaqus model export/bergsoysund-export.py +72 -0
- examples/3 Software interfacing/Abaqus model export/test.py +67 -0
- tests/test_IABSE_step11a.py +217 -0
- tests/test_IABSE_step11c.py +281 -0
- tests/test_IABSE_step2a.py +263 -0
- tests/test_wind.py +71 -0
- wawi/__init__.py +1 -1
- wawi/ext/__init__.py +0 -0
- wawi/ext/abq.py +259 -0
- wawi/ext/abq_legacy.py +462 -0
- wawi/ext/ansys.py +0 -0
- wawi/ext/orcaflex.py +0 -0
- wawi/ext/sofistik.py +0 -0
- wawi/io.py +15 -15
- wawi/model/__init__.py +11 -0
- wawi/model/_aero.py +363 -0
- wawi/model/_dry.py +141 -0
- wawi/model/_hydro.py +882 -0
- wawi/model/_model.py +1324 -0
- wawi/model/_screening.py +124 -0
- wawi/plot.py +9 -6
- {wawi-0.0.7.dist-info → wawi-0.0.9.dist-info}/METADATA +1 -1
- wawi-0.0.9.dist-info/RECORD +39 -0
- wawi-0.0.9.dist-info/top_level.txt +3 -0
- wawi-0.0.7.dist-info/RECORD +0 -21
- wawi-0.0.7.dist-info/top_level.txt +0 -1
- {wawi-0.0.7.dist-info → wawi-0.0.9.dist-info}/LICENSE +0 -0
- {wawi-0.0.7.dist-info → wawi-0.0.9.dist-info}/WHEEL +0 -0
@@ -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
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
|