wawi 0.0.1__py3-none-any.whl → 0.0.3__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- wawi/__init__.py +8 -4
- wawi/abq.py +1128 -0
- wawi/fe.py +134 -0
- wawi/general.py +473 -0
- wawi/identification.py +66 -0
- wawi/io.py +696 -0
- wawi/modal.py +608 -0
- wawi/plot.py +569 -0
- wawi/prob.py +9 -0
- wawi/random.py +38 -0
- wawi/signal.py +45 -0
- wawi/structural.py +278 -0
- wawi/time_domain.py +126 -0
- wawi/tools.py +7 -0
- wawi/wave.py +491 -0
- wawi/wind.py +1108 -0
- wawi/wind_code.py +14 -0
- {wawi-0.0.1.dist-info → wawi-0.0.3.dist-info}/METADATA +7 -6
- wawi-0.0.3.dist-info/RECORD +22 -0
- wawi-0.0.1.dist-info/RECORD +0 -6
- {wawi-0.0.1.dist-info → wawi-0.0.3.dist-info}/LICENSE +0 -0
- {wawi-0.0.1.dist-info → wawi-0.0.3.dist-info}/WHEEL +0 -0
- {wawi-0.0.1.dist-info → wawi-0.0.3.dist-info}/top_level.txt +0 -0
wawi/abq.py
ADDED
@@ -0,0 +1,1128 @@
|
|
1
|
+
import numpy as np
|
2
|
+
import pdb
|
3
|
+
|
4
|
+
from abaqus import *
|
5
|
+
from abaqus import session
|
6
|
+
from abaqusConstants import *
|
7
|
+
import __main__
|
8
|
+
import section
|
9
|
+
import regionToolset
|
10
|
+
import displayGroupMdbToolset as dgm
|
11
|
+
import step
|
12
|
+
import part
|
13
|
+
import material
|
14
|
+
import assembly
|
15
|
+
import interaction
|
16
|
+
import load
|
17
|
+
import mesh
|
18
|
+
import optimization
|
19
|
+
import job
|
20
|
+
import sketch
|
21
|
+
import visualization
|
22
|
+
import xyPlot
|
23
|
+
import displayGroupOdbToolset as dgo
|
24
|
+
import connectorBehavior
|
25
|
+
import symbolicConstants
|
26
|
+
import odbAccess
|
27
|
+
import shutil
|
28
|
+
|
29
|
+
import csv
|
30
|
+
from copy import deepcopy
|
31
|
+
|
32
|
+
import numpy as np
|
33
|
+
import os
|
34
|
+
|
35
|
+
from .general import merge_tr_phi
|
36
|
+
|
37
|
+
'''
|
38
|
+
Abaqus interaction module
|
39
|
+
'''
|
40
|
+
|
41
|
+
## Functions to retrieve data from ODB
|
42
|
+
|
43
|
+
def modalparameters(frequency_step):
|
44
|
+
'''
|
45
|
+
Output the modal parameters from frequency step of current output database.
|
46
|
+
|
47
|
+
Parameters
|
48
|
+
-------------
|
49
|
+
frequency_step : str
|
50
|
+
name of step containing the modal results (frequency step)
|
51
|
+
|
52
|
+
Returns
|
53
|
+
--------------
|
54
|
+
f : float
|
55
|
+
numpy array with undamped natural frequencies in Hz of all modes computed
|
56
|
+
m : float
|
57
|
+
numpy array with modal mass for all modes computed
|
58
|
+
'''
|
59
|
+
|
60
|
+
odb = get_db('odb')
|
61
|
+
history_region_key = odb.steps[frequency_step].historyRegions.keys()[0]
|
62
|
+
|
63
|
+
ftemp = odb.steps[frequency_step].historyRegions[history_region_key].historyOutputs['EIGFREQ'].data
|
64
|
+
f = np.array([x[1] for x in ftemp])
|
65
|
+
|
66
|
+
if 'GM' in odb.steps[frequency_step].historyRegions[history_region_key].historyOutputs.keys():
|
67
|
+
mtemp = odb.steps[frequency_step].historyRegions[history_region_key].historyOutputs['GM'].data
|
68
|
+
m = np.array([x[1] for x in mtemp])
|
69
|
+
else:
|
70
|
+
m = np.ones(np.shape(f)) #if no GM field is available, mass normalization is assumed used on eigenvalues
|
71
|
+
return f, m
|
72
|
+
|
73
|
+
|
74
|
+
def modeshapes_from_region(regionobjs, frequency_step, field_outputs):
|
75
|
+
"""
|
76
|
+
Get modes (shape, frequency and modal mass) from "Frequency step" (eigenvalue analysis) in active Abaqus ODB.
|
77
|
+
|
78
|
+
Args:
|
79
|
+
regionobjs: Abaqus region objects in list
|
80
|
+
frequency_step: name of frequency step
|
81
|
+
field_outputs: list of strings with field output quantities, e.g., ['U', 'UR']
|
82
|
+
Returns:
|
83
|
+
phi: mode shape transformation matrix, ordered as NumPy matrices in list for each specified outputs
|
84
|
+
f: undamped natural frequencies
|
85
|
+
m: modal mass
|
86
|
+
output_dict: dictionary to access correct index in output phi
|
87
|
+
|
88
|
+
AAJ / Knut Andreas Kvaale, 2017
|
89
|
+
Further developed NTNU / Knut Andreas Kvaale, 2018
|
90
|
+
"""
|
91
|
+
odb = get_db('odb')
|
92
|
+
|
93
|
+
if odb.steps[frequency_step].domain != MODAL: #MODAL is a variable in abaqusConstants
|
94
|
+
raise TypeError('Type of input step is not modal!')
|
95
|
+
|
96
|
+
Nmodes = len(odb.steps[frequency_step].frames)-1
|
97
|
+
phi = [None]*len(field_outputs)
|
98
|
+
|
99
|
+
for iout, field_output in enumerate(field_outputs):
|
100
|
+
Ndofs, point_ranges, dof_ranges = count_region(regionobjs, field_output, odb.steps[frequency_step].frames[0])
|
101
|
+
phio = np.zeros([np.sum(Ndofs), Nmodes])
|
102
|
+
foobj0 = odb.steps[frequency_step].frames[0].fieldOutputs[field_output]
|
103
|
+
|
104
|
+
for ix, regionobj in enumerate(regionobjs):
|
105
|
+
current_dof_range = np.arange(dof_ranges[ix], dof_ranges[ix+1])
|
106
|
+
|
107
|
+
for mode in range(0, Nmodes):
|
108
|
+
foobj = odb.steps[frequency_step].frames[mode+1].fieldOutputs[field_output]
|
109
|
+
phio[:, mode] = np.reshape((np.array([v.data for v in foobj.getSubset(region=regionobj).values])), [np.sum(Ndofs)])
|
110
|
+
|
111
|
+
phi[iout] = phio
|
112
|
+
|
113
|
+
return phi
|
114
|
+
|
115
|
+
|
116
|
+
def modeshapes_from_nodelist(node_labels, frequency_step, field_outputs):
|
117
|
+
"""
|
118
|
+
Get mode shapes from "Frequency step" (eigenvalue analysis) in active Abaqus ODB.
|
119
|
+
|
120
|
+
Args:
|
121
|
+
node_labels:
|
122
|
+
frequency_step:
|
123
|
+
field_outputs:
|
124
|
+
Returns:
|
125
|
+
phi: mode shape transformation matrix, ordered as NumPy matrices in list for each specified outputs
|
126
|
+
|
127
|
+
NTNU / Knut Andreas Kvaale, 2018
|
128
|
+
"""
|
129
|
+
odb = get_db('odb')
|
130
|
+
|
131
|
+
if odb.steps[frequency_step].domain != MODAL: #MODAL is a variable in abaqusConstants
|
132
|
+
raise TypeError('Type of input step is not modal!')
|
133
|
+
|
134
|
+
Nnodes = len(node_labels)
|
135
|
+
Nmodes = len(odb.steps[frequency_step].frames) - 1
|
136
|
+
phi = [None]*len(field_outputs)
|
137
|
+
basedisp = [None]*len(field_outputs)
|
138
|
+
|
139
|
+
for iout, field_output in enumerate(field_outputs):
|
140
|
+
foobj0 = odb.steps[frequency_step].frames[0].fieldOutputs[field_output]
|
141
|
+
|
142
|
+
Ndofs = len(foobj0.values[0].data)
|
143
|
+
phio = np.zeros([Ndofs*Nnodes, Nmodes])
|
144
|
+
|
145
|
+
# Get correct data indices to get correct order (as given in node_labels)
|
146
|
+
all_nodes = [value.nodeLabel for value in foobj0.values]
|
147
|
+
data_indices = [None]*Nnodes
|
148
|
+
|
149
|
+
for ix, node in enumerate(node_labels):
|
150
|
+
data_indices[ix] = all_nodes.index(node)
|
151
|
+
|
152
|
+
basedisp[iout] = np.array([foobj0.values[data_ix].data for data_ix in data_indices]).flatten()
|
153
|
+
|
154
|
+
for mode in range(0, Nmodes):
|
155
|
+
foobj = odb.steps[frequency_step].frames[mode+1].fieldOutputs[field_output]
|
156
|
+
phio[:, mode] = np.array([foobj.values[data_ix].data for data_ix in data_indices]).flatten()
|
157
|
+
|
158
|
+
phi[iout] = phio
|
159
|
+
|
160
|
+
return phi, basedisp
|
161
|
+
|
162
|
+
|
163
|
+
def modeshapes_from_elementlist(element_labels, frequency_step, field_outputs):
|
164
|
+
"""
|
165
|
+
Get mode shape from "Frequency step" (eigenvalue analysis) in active Abaqus ODB.
|
166
|
+
|
167
|
+
Args:
|
168
|
+
node_labels:
|
169
|
+
frequency_step:
|
170
|
+
field_outputs:
|
171
|
+
Returns:
|
172
|
+
phi: mode shape transformation matrix, ordered as NumPy matrices in list for each specified outputs
|
173
|
+
|
174
|
+
NTNU / Knut Andreas Kvaale, 2018
|
175
|
+
"""
|
176
|
+
odb = get_db('odb')
|
177
|
+
|
178
|
+
if odb.steps[frequency_step].domain != MODAL: #MODAL is a variable in abaqusConstants
|
179
|
+
raise TypeError('Type of input step is not modal!')
|
180
|
+
|
181
|
+
|
182
|
+
Nmodes = len(odb.steps[frequency_step].frames) - 1
|
183
|
+
phi = [None]*len(field_outputs)
|
184
|
+
integration_points = [None]*len(field_outputs)
|
185
|
+
|
186
|
+
for iout, field_output in enumerate(field_outputs):
|
187
|
+
foobj0 = odb.steps[frequency_step].frames[0].fieldOutputs[field_output]
|
188
|
+
Ndofs = len(foobj0.values[0].data)
|
189
|
+
|
190
|
+
# Get correct data indices to get correct order (as given in node_labels)
|
191
|
+
all_elements = [value.elementLabel for value in foobj0.values]
|
192
|
+
all_integration_points = [value.integrationPoint for value in foobj0.values]
|
193
|
+
|
194
|
+
Nintpoints = len(element_labels) # number of integration points (same element label might appear multiple times if multiple integration points in element)
|
195
|
+
phio = np.zeros([Ndofs*Nintpoints, Nmodes])
|
196
|
+
|
197
|
+
data_indices = [None]*Nintpoints
|
198
|
+
|
199
|
+
for ix, element in enumerate(element_labels):
|
200
|
+
data_indices[ix] = all_elements.index(element)
|
201
|
+
|
202
|
+
for mode in range(0, Nmodes):
|
203
|
+
foobj = odb.steps[frequency_step].frames[mode+1].fieldOutputs[field_output]
|
204
|
+
phio[:, mode] = np.array([foobj.values[data_ix].data for data_ix in data_indices]).flatten()
|
205
|
+
|
206
|
+
integration_points[iout] = [all_integration_points[ix] for ix in data_indices]
|
207
|
+
phi[iout] = phio
|
208
|
+
|
209
|
+
|
210
|
+
return phi, integration_points
|
211
|
+
|
212
|
+
|
213
|
+
def modeshapes_from_set_xydata(field_output, components, output_position, instance_name, set_name, region_type):
|
214
|
+
"""
|
215
|
+
Get mode shapes from "Frequency step" (eigenvalue analysis) in active Abaqus ODB from specified sets.
|
216
|
+
|
217
|
+
Args: NOT FINISHED
|
218
|
+
field_output:
|
219
|
+
components:
|
220
|
+
data_position:
|
221
|
+
output_position:
|
222
|
+
set_name:
|
223
|
+
region_type:
|
224
|
+
Returns:
|
225
|
+
phi: mode shape transformation matrix (Numpy array)
|
226
|
+
|
227
|
+
NTNU / Knut Andreas Kvaale, 2018
|
228
|
+
"""
|
229
|
+
|
230
|
+
set_names = [(instance_name + '.' +set_name)]
|
231
|
+
|
232
|
+
odb = get_db('odb')
|
233
|
+
n_components = len(components)
|
234
|
+
xy_data = [None]*n_components
|
235
|
+
|
236
|
+
if region_type == 'element':
|
237
|
+
data_position = INTEGRATION_POINT
|
238
|
+
elif region_type == 'node':
|
239
|
+
data_position = NODAL
|
240
|
+
|
241
|
+
if output_position == 'element':
|
242
|
+
output_position = ELEMENT_NODAL
|
243
|
+
|
244
|
+
for ix, component in enumerate(components):
|
245
|
+
refinement = [[COMPONENT, component]]
|
246
|
+
variable = [[field_output, data_position, refinement]]
|
247
|
+
|
248
|
+
if region_type == 'element':
|
249
|
+
xy_data[ix] = session.xyDataListFromField(odb=odb, outputPosition=output_position, variable=variable, elementSets=set_names)
|
250
|
+
else:
|
251
|
+
xy_data[ix] = session.xyDataListFromField(odb=odb, outputPosition=output_position, variable=variable, nodeSets=set_names)
|
252
|
+
|
253
|
+
n_elements = len(xy_data[0])
|
254
|
+
n_modes = len(xy_data[0][0])
|
255
|
+
|
256
|
+
phi = np.zeros([n_components*n_elements, n_modes])
|
257
|
+
for compix, component in enumerate(xy_data):
|
258
|
+
for elix, element in enumerate(component):
|
259
|
+
for mode in range(0, n_modes):
|
260
|
+
phi[elix*n_components + compix, mode] = element[mode][1]
|
261
|
+
|
262
|
+
|
263
|
+
return phi, xy_data
|
264
|
+
|
265
|
+
## MODIFY ODB OR MDB
|
266
|
+
def set_view_variable(var, component):
|
267
|
+
"""
|
268
|
+
Set a new view variable and component in current odb session.
|
269
|
+
|
270
|
+
Args:
|
271
|
+
var: variable name
|
272
|
+
component: component to display
|
273
|
+
|
274
|
+
NTNU / Knut Andreas Kvaale, 2018
|
275
|
+
"""
|
276
|
+
position = {NODAL}
|
277
|
+
session.viewports['Viewport: 1'].odbDisplay.setPrimaryVariable(variableLabel=var, outputPosition=NODAL, refinement=(COMPONENT, component),)
|
278
|
+
|
279
|
+
|
280
|
+
def get_db(db_type):
|
281
|
+
"""
|
282
|
+
Return the current database (either a model or an odb object).
|
283
|
+
|
284
|
+
If a model db is wanted and no model is active, the model in the mdb is selected regardless,
|
285
|
+
as long as there is only one model open in the mdb. If no database fits the requirements, None is returned.
|
286
|
+
|
287
|
+
Args:
|
288
|
+
db_type: 'odb' or 'model'
|
289
|
+
Returns:
|
290
|
+
db: database
|
291
|
+
|
292
|
+
NTNU / Knut Andreas Kvaale, 2018
|
293
|
+
"""
|
294
|
+
if db_type is 'model' or db_type is 'mdb':
|
295
|
+
if not session_is_odb():
|
296
|
+
db = mdb.models[session.viewports['Viewport: 1'].displayedObject.modelName]
|
297
|
+
elif len(mdb.models.keys()) is 1:
|
298
|
+
db = mdb.models[mdb.models.keys()[0]]
|
299
|
+
elif len(mdb.models.keys()) > 1:
|
300
|
+
raise AttributeError('No model is not active, and more than one model is available in model database. Impossible to select correct.')
|
301
|
+
else:
|
302
|
+
db = None
|
303
|
+
else:
|
304
|
+
if session_is_odb():
|
305
|
+
db = session.viewports[session.currentViewportName].displayedObject
|
306
|
+
else:
|
307
|
+
db = None
|
308
|
+
|
309
|
+
return db
|
310
|
+
|
311
|
+
|
312
|
+
|
313
|
+
## MODIFY ODB
|
314
|
+
def unlock_odb():
|
315
|
+
"""
|
316
|
+
Unlock current ODB file.
|
317
|
+
|
318
|
+
Returns:
|
319
|
+
odb: database (odb) object
|
320
|
+
|
321
|
+
NTNU / Knut Andreas Kvaale, 2018
|
322
|
+
"""
|
323
|
+
odb = session.viewports[session.currentViewportName].displayedObject
|
324
|
+
|
325
|
+
if odb.isReadOnly:
|
326
|
+
load_path = odb.path
|
327
|
+
odb.close()
|
328
|
+
odb = odbAccess.openOdb(load_path, readOnly=False)
|
329
|
+
session.viewports['Viewport: 1'].setValues(displayedObject=session.odbs[load_path])
|
330
|
+
|
331
|
+
return odb
|
332
|
+
|
333
|
+
|
334
|
+
def copy_and_unlock_odb():
|
335
|
+
"""
|
336
|
+
Copy and unlock current ODB file.
|
337
|
+
|
338
|
+
Returns:
|
339
|
+
odb: database (odb) object
|
340
|
+
|
341
|
+
NTNU / Knut Andreas Kvaale, 2018
|
342
|
+
"""
|
343
|
+
odb = session.viewports[session.currentViewportName].displayedObject
|
344
|
+
old_file_path = odb.path
|
345
|
+
new_file_path = odb.path.split('.odb')[0]+'_org.odb'
|
346
|
+
|
347
|
+
shutil.copyfile(old_file_path, new_file_path) #copy the old file
|
348
|
+
|
349
|
+
odb.close()
|
350
|
+
odb = odbAccess.openOdb(old_file_path, readOnly=False)
|
351
|
+
session.viewports['Viewport: 1'].setValues(displayedObject=session.odbs[old_file_path])
|
352
|
+
|
353
|
+
return odb
|
354
|
+
|
355
|
+
|
356
|
+
def session_is_odb():
|
357
|
+
"""
|
358
|
+
Check if current session is ODB.
|
359
|
+
|
360
|
+
Returns:
|
361
|
+
is_odb: boolean indicating if the session is odb or not
|
362
|
+
|
363
|
+
NTNU / Knut Andreas Kvaale, 2018
|
364
|
+
"""
|
365
|
+
is_odb =(('session' in locals() or 'session' in globals()) and
|
366
|
+
session.viewports['Viewport: 1'].displayedObject is not None and
|
367
|
+
hasattr(session.viewports['Viewport: 1'].displayedObject, 'jobData'))
|
368
|
+
|
369
|
+
return is_odb
|
370
|
+
|
371
|
+
|
372
|
+
def save_and_reopen_odb():
|
373
|
+
"""
|
374
|
+
Save and reopen database (odb) as read-only.
|
375
|
+
|
376
|
+
Returns:
|
377
|
+
odb: odb object
|
378
|
+
|
379
|
+
NTNU / Knut Andreas Kvaale, 2018
|
380
|
+
"""
|
381
|
+
odb = get_db('odb')
|
382
|
+
odb.save()
|
383
|
+
load_path = odb.path
|
384
|
+
odb.close()
|
385
|
+
|
386
|
+
odb = odbAccess.openOdb(load_path, readOnly=True)
|
387
|
+
|
388
|
+
return odb
|
389
|
+
|
390
|
+
|
391
|
+
def add_response_step_from_modal(phi_response, field_outputs, modal_var, frequency_step, step_name, region_strings, region_type, instance_name, description):
|
392
|
+
"""
|
393
|
+
Add an artificial step in Abaqus ODB for response data.
|
394
|
+
|
395
|
+
Args:
|
396
|
+
phi_response: phi of the requested response quantities (list with one matrix for each response quantities)
|
397
|
+
field_outputs: names of field output variables
|
398
|
+
modal_var: covariance matrix for the generalized (modal) DOFs
|
399
|
+
frequency_step: name of the new artificial step_name
|
400
|
+
step_name: node set name or region object that define what nodes / DOFs phi refers to
|
401
|
+
regionobjs: Abaqus region objects in list
|
402
|
+
instance_name: name of the instance
|
403
|
+
description: frame description
|
404
|
+
|
405
|
+
NTNU / Knut Andreas Kvaale, 2018
|
406
|
+
"""
|
407
|
+
|
408
|
+
odb = copy_and_unlock_odb()
|
409
|
+
regionobjs = str2region(instance_name, region_strings, region_type, 'odb')
|
410
|
+
instance = odb.rootAssembly.instances[instance_name]
|
411
|
+
|
412
|
+
step_data = odb.Step(name=step_name, description='Response step', domain=TIME, timePeriod=0)
|
413
|
+
frame = step_data.Frame(incrementNumber=0, description='Response', frameValue=0)
|
414
|
+
|
415
|
+
type_dict = {'SF': [TENSOR_3D_SURFACE, INTEGRATION_POINT, 'Section forces'], 'SM': [TENSOR_3D_SURFACE, INTEGRATION_POINT, 'Section moments'], 'U': [VECTOR, NODAL, 'Spatial displacement'], 'UR': [VECTOR, NODAL, 'Rotational displacement'] }
|
416
|
+
|
417
|
+
for ix, field_output in enumerate(field_outputs):
|
418
|
+
foobj_ref = odb.steps[frequency_step].frames[0].fieldOutputs[field_output]
|
419
|
+
phi = phi_response[ix]
|
420
|
+
region_type = type_dict[field_output][1]
|
421
|
+
comps = len(odb.steps[frequency_step].frames[0].fieldOutputs[field_output].componentLabels)
|
422
|
+
|
423
|
+
sigma = np.sqrt(np.sum((np.dot(phi, modal_var) * phi), axis=1)) # Calculate sigma (square root of covariance matrix) from modal coordinates
|
424
|
+
sigma_comp = np.reshape(sigma, [-1, 3]).astype('float')
|
425
|
+
data = [list(this) for this in sigma_comp]
|
426
|
+
|
427
|
+
foobj = frame.FieldOutput(name=field_output, description=type_dict[field_output][2], type=type_dict[field_output][0], validInvariants=())
|
428
|
+
|
429
|
+
N = len(odb.steps[frequency_step].frames[0].fieldOutputs[field_output].values)
|
430
|
+
Ndofs, point_ranges, dof_ranges = count_region(regionobjs, field_output, odb.steps[frequency_step].frames[0])
|
431
|
+
|
432
|
+
for regix,regionobj in enumerate(regionobjs):
|
433
|
+
good_ix, good_entries = good_element_ix(foobj_ref, regionobj)
|
434
|
+
point_range = range(point_ranges[regix],point_ranges[regix+1])
|
435
|
+
|
436
|
+
foobj.addData(position=region_type, instance=instance, labels=good_entries, data=data)
|
437
|
+
|
438
|
+
step_data.setDefaultField(foobj)
|
439
|
+
|
440
|
+
odb = save_and_reopen_odb()
|
441
|
+
|
442
|
+
return odb
|
443
|
+
|
444
|
+
|
445
|
+
def add_std_to_frame(odb, frame, instance_name, modal_var, phi, regionobj, field_output, reference_step):
|
446
|
+
'''
|
447
|
+
Under development. Not verified.
|
448
|
+
'''
|
449
|
+
if odb.isReadOnly:
|
450
|
+
raise TypeError('ODB is read only. Unable to add data.')
|
451
|
+
|
452
|
+
type_dict = {'SF': [TENSOR_3D_SURFACE, INTEGRATION_POINT, 'Section forces'], 'SM': [TENSOR_3D_SURFACE, INTEGRATION_POINT, 'Section moments'], 'U': [VECTOR, NODAL, 'Spatial displacement'], 'UR': [VECTOR, NODAL, 'Rotational displacement'] }
|
453
|
+
foobj_ref = odb.steps[reference_step].frames[0].fieldOutputs[field_output]
|
454
|
+
|
455
|
+
region_type = type_dict[field_output][1]
|
456
|
+
comps = len(odb.steps[reference_step].frames[0].fieldOutputs[field_output].componentLabels)
|
457
|
+
|
458
|
+
sigma = np.sqrt(np.sum((np.dot(phi, modal_var) * phi), axis=1)) # Calculate sigma (square root of covariance matrix) from modal coordinates
|
459
|
+
sigma_comp = np.reshape(sigma, [-1, comps]).astype('float')
|
460
|
+
data = [list(this) for this in sigma_comp]
|
461
|
+
|
462
|
+
# If already exists, don't create new, but assign to that.
|
463
|
+
if field_output not in frame.fieldOutputs.keys():
|
464
|
+
foobj = frame.FieldOutput(name=field_output, description=type_dict[field_output][2], type=type_dict[field_output][0], validInvariants=())
|
465
|
+
else:
|
466
|
+
foobj = frame.fieldOutputs[field_output]
|
467
|
+
|
468
|
+
N = len(odb.steps[reference_step].frames[0].fieldOutputs[field_output].values)
|
469
|
+
good_ix, good_entries = good_element_ix(foobj_ref, regionobj)
|
470
|
+
instance = odb.rootAssembly.instances[instance_name]
|
471
|
+
|
472
|
+
foobj.addData(position=region_type, instance=instance, labels=good_entries, data=data)
|
473
|
+
step_data.setDefaultField(foobj)
|
474
|
+
|
475
|
+
|
476
|
+
|
477
|
+
def add_complex_mode_step(phi, eigvals, instance_name, step_name, region):
|
478
|
+
"""
|
479
|
+
Add an artificial step in Abaqus ODB for complex modes.
|
480
|
+
|
481
|
+
Args:
|
482
|
+
phi: complex eigenvector matrix
|
483
|
+
eigvals: complex eigenvalues
|
484
|
+
instance_name: name of the instance
|
485
|
+
step_name: name of the new artificial step_name
|
486
|
+
regionobj: Abaqus region object
|
487
|
+
|
488
|
+
Knut Andreas Kvaale, 2018
|
489
|
+
"""
|
490
|
+
|
491
|
+
odb = unlock_odb()
|
492
|
+
complex_step = odb.Step(name=step_name, description='Complex modes', domain=MODAL)
|
493
|
+
frame0 = complex_step.Frame(incrementNumber=0, description='Base state', frameValue=0)
|
494
|
+
frame_data = frame0.FieldOutput(name='U', description='Spatial displacement', type=VECTOR, validInvariants=(MAGNITUDE,))
|
495
|
+
instance = odb.rootAssembly.instances[instance_name]
|
496
|
+
|
497
|
+
for m, lambdam in enumerate(eigvals):
|
498
|
+
phim = np.reshape(phi[:, m], (-1, 3)).astype('float')
|
499
|
+
xim = -np.real(lambdam)/abs(lambdam)
|
500
|
+
|
501
|
+
freqm_ud_rad = abs(lambdam)
|
502
|
+
freqm_d_rad = abs(np.imag(lambdam))
|
503
|
+
freqm_ud_Hz = freqm_ud_rad/(2*np.pi)
|
504
|
+
|
505
|
+
periodm_ud = 2*np.pi/abs(lambdam)
|
506
|
+
|
507
|
+
description_m = 'Mode ' + str(m+1) + ': f = ' + str(freqm_ud_Hz) + 'Hz | om = ' + str(freqm_ud_rad) + 'rad/s | T = ' + str(periodm_ud) + 's | xi = ' + str(xim*100) + '%'
|
508
|
+
|
509
|
+
frame_m = complex_step.Frame(incrementNumber=m+1, description=description_m, frameValue=freqm_ud_Hz)
|
510
|
+
frame_data = frame_m.FieldOutput(name='U', description='Spatial displacement', type=VECTOR, validInvariants=(MAGNITUDE,))
|
511
|
+
nodelabels = np.array([node.label for node in regionobj.nodes[0]]).astype('int')
|
512
|
+
|
513
|
+
frame_data.addData(position=NODAL, instance=instance, labels=nodelabels, data=np.real(phim), conjugateData=np.imag(phim))
|
514
|
+
|
515
|
+
odb.save()
|
516
|
+
load_path = odb.path
|
517
|
+
odb.close()
|
518
|
+
odb = odbAccess.openOdb(load_path, readOnly=True)
|
519
|
+
|
520
|
+
## MODIFY MDB
|
521
|
+
def mass_and_stiffness_input(stiffness,mass,pontoon_set_names,pont_nodes,trans_mats,filename):
|
522
|
+
pontoons = len(pontoon_set_names)
|
523
|
+
if len(pont_nodes) != pontoons or len(trans_mats)!=pontoons:
|
524
|
+
raise ValueError('Mismatch between dimensions for input variables: pontoon_set_names, pont_nodes and trans_mats')
|
525
|
+
f = open(filename, 'w')
|
526
|
+
|
527
|
+
for pontoon in range(0,pontoons):
|
528
|
+
f.write('********************************PONTOON NUMBER {0} ************************************* \n'.format(str(pontoon+1)))
|
529
|
+
f.write('*USER ELEMENT, LINEAR, NODES=1, UNSYM, TYPE=U{0}00 \n'.format(str(pontoon+1))) # Defines a linear user element
|
530
|
+
f.write('1, 2, 3, 4, 5, 6 \n') # The element has one node with 6 DOFS
|
531
|
+
|
532
|
+
T = trans_mats[pontoon]
|
533
|
+
|
534
|
+
K = np.dot(np.dot(T.transpose(), stiffness),T)
|
535
|
+
M = np.dot(np.dot(T.transpose(), mass),T)
|
536
|
+
|
537
|
+
f.write('*MATRIX, TYPE=MASS \n') # Defines the mass matrix in GLOBAL coordinate system
|
538
|
+
for n in range(0,6):
|
539
|
+
string1 = ','.join(map(str, M[n, 0:4]))
|
540
|
+
string2 = ','.join(map(str, M[n, 4:6]))
|
541
|
+
f.write(string1 + '\n' + string2 +'\n')
|
542
|
+
|
543
|
+
f.write('*MATRIX, TYPE=STIFFNESS \n')
|
544
|
+
for n in range(0,6):
|
545
|
+
string1 = ','.join(map(str, K[n, 0:4]))
|
546
|
+
string2 = ','.join(map(str, K[n, 4:6]))
|
547
|
+
f.write(string1 + '\n' + string2 +'\n')
|
548
|
+
|
549
|
+
f.write('*ELEMENT, TYPE=U{0}00, ELSET={1} \n'.format(str(pontoon+1),pontoon_set_names[pontoon])) #Introduce one user element into the FE model
|
550
|
+
f.write('800{0}, {1} \n'.format(str(pontoon+1),pont_nodes[pontoon])) #Numbering elements as 8001,8002,...,8007, followed by first node number forming the element
|
551
|
+
f.write('*UEL PROPERTY, ELSET={0} \n'.format(pontoon_set_names[pontoon]))
|
552
|
+
|
553
|
+
|
554
|
+
def update_input(freq,wadam_file,input_file,pontoon_set_names,pont_nodes,trans_mats):
|
555
|
+
from .io import import_wadam_mat
|
556
|
+
static_mass, stiffness, added_mass, damping, frequency = import_wadam_mat(wadam_file)
|
557
|
+
mass = freq_sysmat(added_mass,frequency,freq)+static_mass
|
558
|
+
mass_and_stiffness_input(stiffness,mass,pontoon_set_names,pont_nodes,trans_mats,input_file)
|
559
|
+
print('Input file '+ input_file + ' is modified to correspond to added mass at f = ' + str(freq) + ' Hz.')
|
560
|
+
|
561
|
+
|
562
|
+
def imperfection_input(node_labels, displacement_vector, input_file=None, rotations=False):
|
563
|
+
|
564
|
+
d = np.array(displacement_vector)
|
565
|
+
|
566
|
+
if rotations is True:
|
567
|
+
n_nodes = len(d)/6
|
568
|
+
d_trans = np.zeros([n_nodes*3])
|
569
|
+
for node in range(0, n_nodes):
|
570
|
+
d_trans[node*3:node*3+3] = d[node*6:node*6+3]
|
571
|
+
|
572
|
+
d = d_trans
|
573
|
+
else:
|
574
|
+
n_nodes = len(d)/3
|
575
|
+
|
576
|
+
mat = np.hstack([np.array(node_labels)[:, np.newaxis], d.reshape(-1, 3)])
|
577
|
+
|
578
|
+
if input_file != None:
|
579
|
+
open(input_file, 'w').close()
|
580
|
+
|
581
|
+
with open(input_file, 'a') as f:
|
582
|
+
f.write('*IMPERFECTION \n')
|
583
|
+
np.savetxt(f, mat, delimiter=',', fmt='%i,%.8e,%.8e,%.8e')
|
584
|
+
|
585
|
+
return mat
|
586
|
+
|
587
|
+
|
588
|
+
def add_input_file(model, input_file_path, pos, target_string=None, relative_pos=0):
|
589
|
+
|
590
|
+
if target_string != None:
|
591
|
+
pos = model.keywordBlock.sieBlocks.index(target_string)
|
592
|
+
|
593
|
+
model.keywordBlock.insert(pos+relative_pos, '*INCLUDE, INPUT={0}'.format(input_file_path))
|
594
|
+
|
595
|
+
|
596
|
+
def add_springs(assem, Kh, region, name):
|
597
|
+
|
598
|
+
ON = symbolicConstants.AbaqusBoolean(1)
|
599
|
+
|
600
|
+
Kpos = (Kh+abs(Kh))/2
|
601
|
+
Krem = (Kh-abs(Kh))/2
|
602
|
+
|
603
|
+
for dof in range(2, 5):
|
604
|
+
if Kpos[dof, dof] != 0:
|
605
|
+
assem.engineeringFeatures.SpringDashpotToGround(name=name+'_K%i%i' % (dof+1, dof+1), region=region, orientation=None, dof=dof+1, springBehavior=ON, springStiffness=Kpos[dof, dof])
|
606
|
+
|
607
|
+
return Krem
|
608
|
+
|
609
|
+
|
610
|
+
def add_inertia(assem, M0, region, name, specify_rot=False):
|
611
|
+
if specify_rot is True:
|
612
|
+
assem.engineeringFeatures.PointMassInertia(alpha=0.0, composite=0.0, i11=M0[3, 3], i12=M0[3, 4], i13=M0[3, 5], i22=M0[4, 4], i23=M0[4, 5],
|
613
|
+
i33=M0[5, 5], mass1=M0[0, 0], mass2=M0[1, 1], mass3=M0[2, 2], name=name+'_M0', region=region)
|
614
|
+
comps = range(0, 6)
|
615
|
+
elif specify_rot is False:
|
616
|
+
assem.engineeringFeatures.PointMassInertia(alpha=0.0, composite=0.0, mass1=M0[0, 0], mass2=M0[1, 1], mass3=M0[2, 2], name=name+'_M0', region=region)
|
617
|
+
comps = range(0, 3)
|
618
|
+
|
619
|
+
Mrem = deepcopy(M0)
|
620
|
+
|
621
|
+
for comp in comps:
|
622
|
+
Mrem[comp, comp] = 0
|
623
|
+
|
624
|
+
return Mrem
|
625
|
+
|
626
|
+
|
627
|
+
#%% USEFUL FUNCTIONS FOR DEALING WITH REGIONS IN DATABASE
|
628
|
+
def count_region(regionobjs, field_output, frame):
|
629
|
+
"""
|
630
|
+
Count the number of DOFs and points in the specified region objects for given field output and frame object.
|
631
|
+
|
632
|
+
Args:
|
633
|
+
regionobjs: list of region objects to query
|
634
|
+
field_output: string specifying field output
|
635
|
+
frame: frame object (from where fieldOutputs field is accessible)
|
636
|
+
Returns:
|
637
|
+
Ndofs: number of DOFs for each region (list)
|
638
|
+
point_ranges: point/node ranges for each region (list of lists)
|
639
|
+
dof_ranges: dof ranges for each region (list of lists)
|
640
|
+
|
641
|
+
NTNU / Knut Andreas Kvaale, 2018
|
642
|
+
"""
|
643
|
+
odb = get_db('odb')
|
644
|
+
|
645
|
+
Npoints = [len(frame.fieldOutputs[field_output].getSubset(region=regionobj).values) for regionobj in regionobjs]
|
646
|
+
Ndofs = np.dot(Npoints, len(frame.fieldOutputs[field_output].componentLabels))
|
647
|
+
|
648
|
+
dof_ranges = np.cumsum(np.append([0], Ndofs))
|
649
|
+
point_ranges = np.cumsum(np.append([0], Npoints))
|
650
|
+
|
651
|
+
return Ndofs, point_ranges, dof_ranges
|
652
|
+
|
653
|
+
|
654
|
+
def good_element_ix(foobj, regionobj):
|
655
|
+
"""
|
656
|
+
Get the indices of the good (??) elements.
|
657
|
+
|
658
|
+
Args:
|
659
|
+
foobj: field object
|
660
|
+
regionobj: region object
|
661
|
+
Returns:
|
662
|
+
good_ix: ?
|
663
|
+
good_entries: ?
|
664
|
+
|
665
|
+
NTNU / Knut Andreas Kvaale, 2018
|
666
|
+
"""
|
667
|
+
foobj_values = foobj.getSubset(region=regionobj).values
|
668
|
+
region_type = obtain_region_types([regionobj])[0]
|
669
|
+
|
670
|
+
if region_type is 'elements':
|
671
|
+
rootobj = regionobj.elements
|
672
|
+
label_string = 'elementLabel'
|
673
|
+
elif region_type is 'nodes':
|
674
|
+
rootobj = regionobj.nodes
|
675
|
+
label_string = 'nodeLabel'
|
676
|
+
|
677
|
+
if type(rootobj) is tuple:
|
678
|
+
rootobj = rootobj[0]
|
679
|
+
|
680
|
+
good_entries = [getattr(val, label_string) for val in foobj_values]
|
681
|
+
all_entries = [obj.label for obj in rootobj]
|
682
|
+
|
683
|
+
good_ix = [all_entries.index(this_entry) for this_entry in good_entries]
|
684
|
+
|
685
|
+
return good_ix, good_entries
|
686
|
+
|
687
|
+
|
688
|
+
def obtain_region_types(regionobjs):
|
689
|
+
"""
|
690
|
+
Get the region types of list of region objects.
|
691
|
+
|
692
|
+
Args:
|
693
|
+
regionobjs: list of region objects
|
694
|
+
Returns:
|
695
|
+
region_type: list of region types
|
696
|
+
|
697
|
+
NTNU / Knut Andreas Kvaale, 2018
|
698
|
+
"""
|
699
|
+
elementsets = [regionobj.nodes is None for regionobj in regionobjs] # true if regionobjects are element sets
|
700
|
+
settypedict = {False: 'nodes', True: 'elements'}
|
701
|
+
region_type = [settypedict[elementset] for elementset in elementsets]
|
702
|
+
|
703
|
+
return region_type
|
704
|
+
|
705
|
+
|
706
|
+
def str2region(instance_name, setnames, region_type, db_type, *args):
|
707
|
+
"""
|
708
|
+
Construct a region object from a string defining the set name or a region object.
|
709
|
+
|
710
|
+
Args:
|
711
|
+
instance_name: string defining the set name (either node or element set) or a region object
|
712
|
+
setnames: name of set asked for
|
713
|
+
region_type: type of set ('elements' or 'nodes')
|
714
|
+
db_type: 'odb' or 'model'
|
715
|
+
Optional args:
|
716
|
+
db: database object, either mdb.model[...] or session.openOdb(...) - will get from viewport 1 if not given
|
717
|
+
Returns:
|
718
|
+
regionobjs: region objects
|
719
|
+
|
720
|
+
AAJ / Knut Andreas Kvaale, 2017
|
721
|
+
Further developed NTNU / Knut Andreas Kvaale, 2018
|
722
|
+
"""
|
723
|
+
|
724
|
+
is_assembly = instance_name is None
|
725
|
+
|
726
|
+
set_type = settype(region_type, db_type)
|
727
|
+
standard_sets = {'nodes': [' ALL NODES'], 'elements': [' ALL ELEMENTS']}
|
728
|
+
|
729
|
+
if setnames is None:
|
730
|
+
setnames = standard_sets[region_type]
|
731
|
+
|
732
|
+
if len(args)==1: # a db has been input
|
733
|
+
db = args[0]
|
734
|
+
isodb = hasattr(db,'jobData') #check if the input db is reffering to result/odb or model
|
735
|
+
|
736
|
+
else:
|
737
|
+
db = get_db(db_type)
|
738
|
+
|
739
|
+
if db is None:
|
740
|
+
raise TypeError('The database is empty. Please input a database object, or input parameters that matches one. Remember that odbs have to be active to get the db automatically!')
|
741
|
+
|
742
|
+
if is_assembly: # Instance name is given
|
743
|
+
regroot = db.rootAssembly
|
744
|
+
else:
|
745
|
+
regroot = db.rootAssembly.instances[instance_name]
|
746
|
+
|
747
|
+
regionobjs = [None] * np.size(setnames)
|
748
|
+
|
749
|
+
for ix,thisname in enumerate(setnames):
|
750
|
+
regionobjs[ix] = getattr(regroot, set_type)[thisname]
|
751
|
+
|
752
|
+
return regionobjs
|
753
|
+
|
754
|
+
|
755
|
+
def region2nodes(regionobj, sortfun=None):
|
756
|
+
"""
|
757
|
+
Give node labels (indices) of nodes in specified node set(s).
|
758
|
+
|
759
|
+
Args:
|
760
|
+
regionobj: region object to query for node labels
|
761
|
+
|
762
|
+
Optional args:
|
763
|
+
sortfun: function with three inputs (1: x, 2: y, 3:z) to sort nodes by
|
764
|
+
examples: sortfun = lambda x, y, z: -np.arctan2(y,x)
|
765
|
+
sortfun = lambda x, y, z: x
|
766
|
+
|
767
|
+
Returns:
|
768
|
+
node_labels: list with nodelabels
|
769
|
+
|
770
|
+
NTNU / Knut Andreas Kvaale, 2018
|
771
|
+
"""
|
772
|
+
|
773
|
+
set_name = regionobj.__repr__().split("ets[")[1].split("'")[1]
|
774
|
+
|
775
|
+
if len(np.shape(regionobj.nodes))>1:
|
776
|
+
nodes = regionobj.nodes[0]
|
777
|
+
else:
|
778
|
+
nodes = regionobj.nodes
|
779
|
+
|
780
|
+
node_labels = np.array([node.label for node in nodes])
|
781
|
+
node_coordinates = np.array([node.coordinates for node in nodes])
|
782
|
+
|
783
|
+
if sortfun != None:
|
784
|
+
vals = sortfun(x=node_coordinates[:,0], y=node_coordinates[:,1], z=node_coordinates[:,2])
|
785
|
+
sort_ix = np.argsort(vals)
|
786
|
+
node_labels = node_labels[:, sort_ix]
|
787
|
+
node_coordinates = node_coordinates[sort_ix, :]
|
788
|
+
|
789
|
+
return node_labels, node_coordinates
|
790
|
+
|
791
|
+
def region2elnodes(regionobj, avoid_central_nodes=True, db_type='odb'):
|
792
|
+
"""
|
793
|
+
Give node labels (indices) for each node in specified element set.
|
794
|
+
|
795
|
+
Args:
|
796
|
+
regionobj: region object to query for labels
|
797
|
+
|
798
|
+
Returns:
|
799
|
+
element_labels: the labels (indices) of the elements in list
|
800
|
+
element_node_indices: the labels (indices) of the ndoes in each element; list of lists
|
801
|
+
node_labels: all the nodes labels (indices) in a flattened list
|
802
|
+
node_coordinates: node coordinates for each element (list of lists)
|
803
|
+
|
804
|
+
NTNU / Knut Andreas Kvaale, 2018
|
805
|
+
"""
|
806
|
+
|
807
|
+
db = get_db(db_type)
|
808
|
+
objstr = regionobj.__repr__()
|
809
|
+
if 'instances' in objstr:
|
810
|
+
instance_name = objstr.split(".instances['")[1].split("'].")[0]
|
811
|
+
else:
|
812
|
+
instance_name = None
|
813
|
+
|
814
|
+
if instance_name is None:
|
815
|
+
instance = db.rootAssembly
|
816
|
+
else:
|
817
|
+
instance = db.rootAssembly.instances[instance_name]
|
818
|
+
|
819
|
+
# Get the elements object root
|
820
|
+
if len(np.shape(regionobj.elements))>1:
|
821
|
+
elements = regionobj.elements[0]
|
822
|
+
else:
|
823
|
+
elements = regionobj.elements
|
824
|
+
|
825
|
+
# Get all element labels and corresponding connectivity (node labels)
|
826
|
+
element_labels = np.array([element.label for element in elements])
|
827
|
+
node_labels = [el.connectivity for el in elements]
|
828
|
+
|
829
|
+
if avoid_central_nodes:
|
830
|
+
node_labels = np.unique([item for sublist in node_labels for item in sublist[:1]+sublist[-1:]])
|
831
|
+
else:
|
832
|
+
node_labels = [item for sublist in node_labels for item in sublist]
|
833
|
+
|
834
|
+
element_matrix = None
|
835
|
+
|
836
|
+
return element_labels, node_labels, element_matrix
|
837
|
+
|
838
|
+
|
839
|
+
def get_element_matrix(element_labels=None): #if None is specified, full model is exported
|
840
|
+
pass
|
841
|
+
|
842
|
+
def get_node_matrix(node_labels=None): #if None is specified, full model is exported
|
843
|
+
pass
|
844
|
+
|
845
|
+
def region2elnodes_legacy(regionobjs, avoid_central_nodes=True):
|
846
|
+
"""
|
847
|
+
Give node labels (indices) for each node in specified element set.
|
848
|
+
|
849
|
+
Args:
|
850
|
+
regionobjs: region objects to query for node labels
|
851
|
+
|
852
|
+
Returns:
|
853
|
+
element_labels: the labels (indices) of the elements in list
|
854
|
+
element_node_indices: the labels (indices) of the ndoes in each element; list of lists
|
855
|
+
node_labels: all the nodes labels (indices) in a flattened list
|
856
|
+
node_coordinates: node coordinates for each element (list of lists)
|
857
|
+
|
858
|
+
NTNU / Knut Andreas Kvaale, 2018
|
859
|
+
"""
|
860
|
+
|
861
|
+
objstr = regionobjs.__repr__()
|
862
|
+
instance_name = objstr.split(".instances['")[1].split("'].")[0]
|
863
|
+
|
864
|
+
if '.odb' in objstr:
|
865
|
+
db = get_db('odb')
|
866
|
+
dbtype = 'odb'
|
867
|
+
else:
|
868
|
+
db = get_db('mdb')
|
869
|
+
dbtype = 'mdb'
|
870
|
+
|
871
|
+
# Get the elements object root
|
872
|
+
if len(np.shape(regionobjs.elements))>1:
|
873
|
+
elements = regionobjs.elements[0]
|
874
|
+
else:
|
875
|
+
elements = regionobjs.elements
|
876
|
+
|
877
|
+
# Get all element labels and corresponding connectivity (node labels)
|
878
|
+
element_labels = np.array([element.label for element in elements])
|
879
|
+
|
880
|
+
# Instance object
|
881
|
+
instance = db.rootAssembly.instances[instance_name]
|
882
|
+
|
883
|
+
# Full arrays labels and coordinates
|
884
|
+
all_node_labels = np.array([node.label for node in instance.nodes]).flatten([-1])
|
885
|
+
all_node_coords = np.array([node.coordinates for node in instance.nodes])
|
886
|
+
|
887
|
+
# Nodes belonging to all the elements
|
888
|
+
if dbtype is 'odb':
|
889
|
+
element_node_labels = [element.connectivity for element in elements]
|
890
|
+
else:
|
891
|
+
element_node_labels = [[all_node_labels[ix] for ix in element.connectivity] for element in elements]
|
892
|
+
|
893
|
+
if avoid_central_nodes:
|
894
|
+
element_node_labels = [[node_lb[0], node_lb[-1]] for node_lb in element_node_labels]
|
895
|
+
|
896
|
+
node_labels = np.unique(np.array(element_node_labels).flatten())
|
897
|
+
|
898
|
+
nodeixs = np.array([np.where(all_node_labels==node)[0] for node in node_labels]).flatten()
|
899
|
+
node_coordinates = all_node_coords[nodeixs, :]
|
900
|
+
element_node_indices = np.array([np.array([np.where(node_labels==node_label) for node_label in node_labels_for_element]).flatten() for node_labels_for_element in element_node_labels])
|
901
|
+
|
902
|
+
return element_labels, element_node_indices, node_labels, node_coordinates
|
903
|
+
|
904
|
+
|
905
|
+
#%% RETRIEVE THINGS FROM DATABASE
|
906
|
+
def element_orientations(element_labels, instance_name):
|
907
|
+
"""
|
908
|
+
Provide transformation matrices describing the three unit vectors of the local CSYS of all elements in element_labels.
|
909
|
+
|
910
|
+
Args:
|
911
|
+
element_labels: element labels to query
|
912
|
+
instance_name: name of instance to find beam orientations
|
913
|
+
|
914
|
+
Returns:
|
915
|
+
element_orientations: array of numpy 2d-arrays with transformation matrices of all elements in element_labels
|
916
|
+
|
917
|
+
NTNU / Knut Andreas Kvaale, 2018
|
918
|
+
"""
|
919
|
+
db_type = 'odb' # may consider mdb option later
|
920
|
+
db = get_db(db_type)
|
921
|
+
|
922
|
+
all_elements = db.rootAssembly.elementSets[' ALL ELEMENTS'].elements[0]
|
923
|
+
all_nodes = db.rootAssembly.nodeSets[' ALL NODES'].nodes[0]
|
924
|
+
all_element_labels = [value.label for value in all_elements]
|
925
|
+
all_node_labels = [value.label for value in all_nodes]
|
926
|
+
element_orientations = [None]*len(element_labels)
|
927
|
+
|
928
|
+
beam_orientations = db.rootAssembly.instances[instance_name].beamOrientations
|
929
|
+
|
930
|
+
for beam_orientation in beam_orientations:
|
931
|
+
bo_elements = [value.label for value in beam_orientation.region.elements]
|
932
|
+
for this_element_label in bo_elements:
|
933
|
+
if this_element_label in element_labels:
|
934
|
+
n1_temp = np.array(beam_orientation.vector)
|
935
|
+
node_labels = all_elements[all_element_labels.index(this_element_label)].connectivity
|
936
|
+
|
937
|
+
node_start_coor = all_nodes[all_node_labels.index(node_labels[0])].coordinates
|
938
|
+
node_end_coor = all_nodes[all_node_labels.index(node_labels[-1])].coordinates
|
939
|
+
t = (node_end_coor-node_start_coor)
|
940
|
+
t = t/np.linalg.norm(t)
|
941
|
+
|
942
|
+
n2 = np.cross(t, n1_temp)
|
943
|
+
n2 = n2/np.linalg.norm(n2)
|
944
|
+
|
945
|
+
n1 = np.cross(n2, t) #does this actually work?
|
946
|
+
|
947
|
+
element_orientations[np.where(element_labels == this_element_label)[0]] = np.array([t,n1,n2])
|
948
|
+
|
949
|
+
return element_orientations
|
950
|
+
|
951
|
+
|
952
|
+
def freq_sysmat(mat,freqs,freq):
|
953
|
+
"""
|
954
|
+
Interpolate frequency dependent matrix, for given frequency value. !! Deprecated - use numpy functions directly instead !!
|
955
|
+
|
956
|
+
Args:
|
957
|
+
mat: 3D matrix (Numpy array)
|
958
|
+
freqs: frequency axis (Numpy array)
|
959
|
+
freq: selected frequency value (scalar)
|
960
|
+
Returns:
|
961
|
+
mat_sel: 2D matrix corresponding to queried frequency value (Numpy array)
|
962
|
+
|
963
|
+
NTNU / AAJ / Knut Andreas Kvaale, 2018
|
964
|
+
"""
|
965
|
+
from .general import interp1z
|
966
|
+
|
967
|
+
if freq == []:
|
968
|
+
mat_sel = 0
|
969
|
+
else:
|
970
|
+
mat_sel = interp1z(freqs[:,0,0],mat,freq)
|
971
|
+
return mat_sel
|
972
|
+
|
973
|
+
|
974
|
+
def wind_set_data(set_strings, frequency_step, instance, db_type, field_outputs, mode_type='nodes', use_node_region_acronym=False):
|
975
|
+
# use_node_region_acronym: if True, a node set with identical name as the element set given in set_strings is picked and the nodes assumed to correspond to the element. If not the case, the element set is used to establish the nodes (and thus phi)
|
976
|
+
wind_element_regions = str2region(instance, set_strings, 'elements', db_type) # index 0 is girder, index 1 is columns
|
977
|
+
|
978
|
+
if use_node_region_acronym:
|
979
|
+
wind_node_regions = str2region(instance, set_strings, 'nodes', db_type)
|
980
|
+
|
981
|
+
element_labels = [None]*len(set_strings)
|
982
|
+
element_node_indices = [None]*len(set_strings)
|
983
|
+
node_labels = [None]*len(set_strings)
|
984
|
+
node_coordinates = [None]*len(set_strings)
|
985
|
+
phi_ae = [None]*len(set_strings)
|
986
|
+
|
987
|
+
for set_ix, set_string in enumerate(set_strings):
|
988
|
+
element_labels[set_ix], element_node_indices[set_ix], nl, nc = region2elnodes_legacy(wind_element_regions[set_ix])
|
989
|
+
if use_node_region_acronym:
|
990
|
+
nl, nc = region2nodes(wind_node_regions[set_ix])
|
991
|
+
|
992
|
+
node_labels[set_ix] = nl
|
993
|
+
node_coordinates[set_ix] = nc
|
994
|
+
|
995
|
+
# Establish modal transformation matrix, phi
|
996
|
+
if mode_type=='nodes':
|
997
|
+
for set_ix, set_string in enumerate(set_strings):
|
998
|
+
phi_ae_temp = modeshapes_from_nodelist(node_labels[set_ix], frequency_step, field_outputs)
|
999
|
+
phi_ae[set_ix] = merge_tr_phi(phi_ae_temp[0][0], phi_ae_temp[0][1])
|
1000
|
+
elif mode_type=='elements':
|
1001
|
+
for set_ix, set_string in enumerate(set_strings):
|
1002
|
+
phi_ae_temp, integration_points = modeshapes_from_elementlist(element_labels[set_ix], frequency_step, field_outputs)
|
1003
|
+
phi_ae[set_ix] = merge_tr_phi(phi_ae_temp[0], phi_ae_temp[1])
|
1004
|
+
|
1005
|
+
return element_labels, element_node_indices, node_labels, node_coordinates, phi_ae
|
1006
|
+
|
1007
|
+
|
1008
|
+
|
1009
|
+
def settype(region_type, db_type):
|
1010
|
+
"""
|
1011
|
+
Define the string used to get set based on region type and database type.
|
1012
|
+
|
1013
|
+
Args:
|
1014
|
+
region_type: 'element' or 'node'
|
1015
|
+
db_type: 'odb' or 'mdb'
|
1016
|
+
Returns:
|
1017
|
+
set_string: string used to obtain set data from database object (odb or mdb)
|
1018
|
+
|
1019
|
+
NTNU / Knut Andreas Kvaale, 2018
|
1020
|
+
"""
|
1021
|
+
if db_type is 'odb':
|
1022
|
+
if 'element' in region_type.lower():
|
1023
|
+
set_string = 'elementSets'
|
1024
|
+
elif 'node' in region_type.lower():
|
1025
|
+
set_string = 'nodeSets'
|
1026
|
+
else:
|
1027
|
+
raise TypeError('Wrong input!')
|
1028
|
+
elif db_type == 'mdb' or db_type == 'model':
|
1029
|
+
set_string = 'sets'
|
1030
|
+
|
1031
|
+
return set_string
|
1032
|
+
|
1033
|
+
#%% EXPORT THINGS
|
1034
|
+
def save_nodes_and_elements(folder, element_labels, element_node_indices, node_labels, node_coordinates, element_orientations=None, set_strings=None):
|
1035
|
+
for ix, element_labels_i in enumerate(element_labels):
|
1036
|
+
element_info = np.column_stack([element_labels[ix], element_node_indices[ix]])
|
1037
|
+
node_info = np.column_stack([node_labels[ix], node_coordinates[ix]])
|
1038
|
+
np.savetxt(os.path.join(folder, 'node_info_%i.dat' % (ix)), node_info)
|
1039
|
+
np.savetxt(os.path.join(folder, 'element_info_%i.dat' % (ix)), element_info)
|
1040
|
+
|
1041
|
+
if element_orientations:
|
1042
|
+
np.savetxt(os.path.join(folder, 'element_orientations_%i.dat' % (ix)), element_orientations)
|
1043
|
+
|
1044
|
+
if set_strings:
|
1045
|
+
np.savetxt(os.path.join(folder, 'node_and_element_sets.txt'), set_strings, fmt='%s', delimiter=',')
|
1046
|
+
|
1047
|
+
|
1048
|
+
def save_pontoon_info(folder, node_labels, node_coordinates, pontoon_labels=None, pontoon_angles=None):
|
1049
|
+
if pontoon_labels==None: # standard if no pontoon_labels are provided (integers!)
|
1050
|
+
pontoon_labels = np.linspace(1, len(node_labels), len(node_labels)).astype(int)
|
1051
|
+
|
1052
|
+
if pontoon_angles==None:
|
1053
|
+
pontoon_angles = np.zeros(len(node_labels)) #if no angles are given, output zero for all pontoon angles
|
1054
|
+
|
1055
|
+
pontooninfo = np.column_stack([pontoon_labels, node_coordinates, node_labels, pontoon_angles])
|
1056
|
+
np.savetxt(os.path.join(folder, 'pontoon_info.dat'), pontooninfo)
|
1057
|
+
|
1058
|
+
|
1059
|
+
def save_all_modal(folder, phi, suffix='', f=None, m=None, set_strings=None):
|
1060
|
+
|
1061
|
+
if isinstance(phi, list):
|
1062
|
+
for ix, phi_i in enumerate(phi):
|
1063
|
+
np.savetxt(os.path.join(folder, 'phi_%s_%i.dat' % (suffix, ix)), phi_i)
|
1064
|
+
|
1065
|
+
if set_strings:
|
1066
|
+
np.savetxt(os.path.join(folder, 'phi_%s_sets.txt' % (suffix)), set_strings, fmt='%s', delimiter=',')
|
1067
|
+
|
1068
|
+
elif isinstance(phi, np.ndarray):
|
1069
|
+
np.savetxt(os.path.join(folder, 'phi_%s_%i.dat' % (suffix, 0)), phi)
|
1070
|
+
|
1071
|
+
if f is not None:
|
1072
|
+
np.savetxt(os.path.join(folder, 'f.dat'), f)
|
1073
|
+
if m is not None:
|
1074
|
+
np.savetxt(os.path.join(folder, 'm.dat'), m)
|
1075
|
+
|
1076
|
+
|
1077
|
+
#%% ONLY DEBUGGED IN BRIGADE
|
1078
|
+
def mode2df(model, node_labels, phi, name, instance_name):
|
1079
|
+
nodes = tuple(np.repeat(node_labels,6).tolist())
|
1080
|
+
dofs = np.tile(np.arange(1,6+1), len(node_labels))
|
1081
|
+
|
1082
|
+
dofs_and_mags = np.empty([np.shape(dofs)[0],2])
|
1083
|
+
dofs_and_mags[:, 0::2] = dofs[:, np.newaxis]
|
1084
|
+
dofs_and_mags[:, 1::2] = phi[:, np.newaxis]
|
1085
|
+
|
1086
|
+
data = ((instance_name, 2, nodes, tuple(dofs_and_mags.flatten().tolist())),)
|
1087
|
+
df = model.DiscreteField(data=data, dataWidth=2, defaultValues=(0.0, 0.0, 0.0, 0.0, 0.0, 0.0), description='Mode displacement', fieldType=PRESCRIBEDCONDITION_DOF, location=NODES, name=name)
|
1088
|
+
|
1089
|
+
return df
|
1090
|
+
|
1091
|
+
|
1092
|
+
def apply_nodal_load(model, node_labels, step_name, loads, instance_name, prefix=''):
|
1093
|
+
instance = model.rootAssembly.instances[instance_name]
|
1094
|
+
all_node_labels = [node.label for node in instance.nodes]
|
1095
|
+
ndof = 6 # assumes 6 DOFs for all nodes - be aware!
|
1096
|
+
for node_ix, node_label in enumerate(node_labels):
|
1097
|
+
if all_node_labels.count(node_label) != None: # if in node labels
|
1098
|
+
global_node_ix = all_node_labels.index(node_label)
|
1099
|
+
node_set = model.rootAssembly.Set(name='node_%i' % (node_label), nodes=instance.nodes[global_node_ix:global_node_ix+1])
|
1100
|
+
nodeloads = loads[node_ix*6:node_ix*6+6]
|
1101
|
+
|
1102
|
+
if not np.all(nodeloads[0:3]==0):
|
1103
|
+
model.ConcentratedForce(cf1=nodeloads[0], cf2=nodeloads[1], cf3=nodeloads[2], createStepName=step_name, distributionType=UNIFORM, field='', localCsys=None, name='%sforces_node_%i' % (prefix, node_label), region=node_set)
|
1104
|
+
|
1105
|
+
if not np.all(nodeloads[3:6]==0):
|
1106
|
+
model.Moment(cm1=nodeloads[3], cm2=nodeloads[4], cm3=nodeloads[5], createStepName=step_name, distributionType=UNIFORM, field='', localCsys=None, name='%smoments_node_%i' % (prefix, node_label), region=node_set)
|
1107
|
+
|
1108
|
+
else:
|
1109
|
+
raise ValueError('Node %i does not exist in selected instance.' % (node_label))
|
1110
|
+
|
1111
|
+
|
1112
|
+
def assign_modal_constraint_equation(model, instance_name, name, node_labels, displacement):
|
1113
|
+
ndof = 6 # assumes 6 DOFs for all nodes - be aware!
|
1114
|
+
instance = model.rootAssembly.instances[instance_name]
|
1115
|
+
all_node_labels = [node.label for node in instance.nodes]
|
1116
|
+
terms = []
|
1117
|
+
for node_ix, node_label in enumerate(node_labels):
|
1118
|
+
if all_node_labels.count(node_label) != None: # if in node labels
|
1119
|
+
global_node_ix = all_node_labels.index(node_label)
|
1120
|
+
node_set_name = 'node_%i' % (node_label)
|
1121
|
+
node_set = model.rootAssembly.Set(name=node_set_name, nodes=instance.nodes[global_node_ix:global_node_ix+1])
|
1122
|
+
displacement_of_node = displacement[node_ix*ndof:node_ix*ndof+ndof]
|
1123
|
+
non_zero = np.where(displacement_of_node !=0 )[0]
|
1124
|
+
terms.append([(displacement_of_node[ldof], node_set_name, ldof+1) for ldof in non_zero])
|
1125
|
+
|
1126
|
+
terms = tuple([term for sublist in terms for term in sublist])
|
1127
|
+
model.Equation(name=name, terms=terms)
|
1128
|
+
|