Coverage for src / sdynpy / fileio / sdynpy_uff_datasets / sdynpy_uff_dataset_55.py: 19%
351 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-11 16:22 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-11 16:22 +0000
1# -*- coding: utf-8 -*-
2"""
3Data at Nodes (Shapes)
5This dataset defines mode shapes, which are defined as data at nodes.
6"""
7"""
8Copyright 2022 National Technology & Engineering Solutions of Sandia,
9LLC (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S.
10Government retains certain rights in this software.
12This program is free software: you can redistribute it and/or modify
13it under the terms of the GNU General Public License as published by
14the Free Software Foundation, either version 3 of the License, or
15(at your option) any later version.
17This program is distributed in the hope that it will be useful,
18but WITHOUT ANY WARRANTY; without even the implied warranty of
19MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20GNU General Public License for more details.
22You should have received a copy of the GNU General Public License
23along with this program. If not, see <https://www.gnu.org/licenses/>.
24"""
26from ..sdynpy_uff import UFFReadError, parse_uff_line, parse_uff_lines, write_uff_line
27import numpy as np
29_analysis_types = {0:'Unknown',
30 1:'Static',
31 2:'Normal Mode',
32 3:'Complex Mode',
33 4:'Transient',
34 5:'Frequency Response',
35 6:'Buckling',
36 7:'Complex Mode Second Order'}
38class Sdynpy_UFF_Dataset_55:
39 def __init__(self, idline1, idline2, idline3, idline4, idline5, model_type,
40 analysis_type, data_characteristic, specific_data_type, data_type,
41 integer_data, real_data, node_data_dictionary):
42 self.idline1 = idline1
43 self.idline2 = idline2
44 self.idline3 = idline3
45 self.idline4 = idline4
46 self.idline5 = idline5
47 self.model_type = model_type
48 self.analysis_type = analysis_type
49 self.data_characteristic = data_characteristic
50 self.specific_data_type = specific_data_type
51 self.data_type = data_type
52 self.integer_data = integer_data
53 self.real_data = real_data
54 self.node_data_dictionary = node_data_dictionary
56 @property
57 def dataset_number(self):
58 return 55
60 # For Analysis Type = 0, Unknown
61 #
62 # RECORD 7:
63 #
64 # FIELD 1: 1
65 # FIELD 2: 1
66 # FIELD 3: ID Number - Done
67 #
68 # RECORD 8:
69 #
70 # FIELD 1: 0.0
71 #
72 # For Analysis Type = 1, Static
73 #
74 # RECORD 7:
75 # FIELD 1: 1
76 # FIELD 2: 1
77 # FIELD 3: Load Case Number - Done
78 #
79 # RECORD 8:
80 # FIELD 11: 0.0
81 #
82 # For Analysis Type = 2, Normal Mode
83 #
84 # RECORD 7:
85 #
86 # FIELD 1: 2
87 # FIELD 2: 4
88 # FIELD 3: Load Case Number - Done
89 # FIELD 4: Mode Number - Done
90 #
91 # RECORD 8:
92 # FIELD 1: Frequency (Hertz) - Done
93 # FIELD 2: Modal - Done
94 # FIELD 3: Modal Viscous Damping Ratio - Done
95 # FIELD 4: Modal Hysteretic Damping Ratio - Done
96 #
97 # For Analysis Type = 3, Complex Eigenvalue
98 #
99 # RECORD 7:
100 # FIELD 1: 2
101 # FIELD 2: 6
102 # FIELD 3: Load Case Number - Done
103 # FIELD 4: Mode Number - Done
104 #
105 # RECORD 8:
106 #
107 # FIELD 1: Real Part Eigenvalue - Done
108 # FIELD 2: Imaginary Part Eigenvalue - Done
109 # FIELD 3: Real Part Of Modal A - Done
110 # FIELD 4: Imaginary Part Of Modal A - Done
111 # FIELD 5: Real Part Of Modal B
112 # FIELD 6: Imaginary Part Of Modal B
113 #
114 #
115 # For Analysis Type = 4, Transient
116 #
117 # RECORD 7:
118 #
119 # FIELD 1: 2
120 # FIELD 2: 1
121 # FIELD 3: Load Case Number - Done
122 # FIELD 4: Time Step Number - Done
123 #
124 # RECORD 8:
125 # FIELD 1: Time (Seconds)
126 #
127 # For Analysis Type = 5, Frequency Response
128 #
129 # RECORD 7:
130 #
131 # FIELD 1: 2
132 # FIELD 2: 1
133 # FIELD 3: Load Case Number - Done
134 # FIELD 4: Frequency Step Number - Done
135 #
136 # RECORD 8:
137 # FIELD 1: Frequency (Hertz) - Done
138 #
139 # For Analysis Type = 6, Buckling
140 #
141 # RECORD 7:
142 #
143 # FIELD 1: 1
144 # FIELD 2: 1
145 # FIELD 3: Load Case Number - Done
146 #
147 # RECORD 8:
148 #
149 # FIELD 1: Eigenvalue - Done
151 @property
152 def id_number(self):
153 valid_types = [0]
154 index = 0
155 if self.analysis_type in valid_types:
156 return self.integer_data[index]
157 else:
158 raise AttributeError(
159 'id_number field only exists for analysis_types {:}'.format(
160 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
162 @id_number.setter
163 def id_number(self, value):
164 valid_types = [0]
165 index = 0
166 if self.analysis_type in valid_types:
167 try:
168 self.integer_data[index] = value
169 except IndexError:
170 print('Integer data currently only has {:} indices, tried to index {:}, expanding to {:}'.format(
171 len(self.integer_data), index, index + 1))
172 self.integer_data += ((index + 1) - (len(self.integer_data))) * [0]
173 self.integer_data[index] = value
174 else:
175 raise AttributeError(
176 'id_number field only exists for analysis_types {:}'.format(
177 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
179 @property
180 def load_case_number(self):
181 valid_types = [1,2,3,4,5,6]
182 index = 0
183 if self.analysis_type in valid_types:
184 return self.integer_data[index]
185 else:
186 raise AttributeError(
187 'load_case_number field only exists for analysis_types {:}'.format(
188 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
191 @load_case_number.setter
192 def load_case_number(self, value):
193 valid_types = [1,2,3,4,5,6]
194 index = 0
195 if self.analysis_type in valid_types:
196 try:
197 self.integer_data[index] = value
198 except IndexError:
199 print('Integer data currently only has {:} indices, tried to index {:}, expanding to {:}'.format(
200 len(self.integer_data), index, index + 1))
201 self.integer_data += ((index + 1) - (len(self.integer_data))) * [0]
202 self.integer_data[index] = value
203 else:
204 raise AttributeError(
205 'load_case_number field only exists for analysis_types {:}'.format(
206 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
208 @property
209 def mode_number(self):
210 valid_types = [2,3]
211 index = 1
212 if self.analysis_type in valid_types:
213 return self.integer_data[index]
214 else:
215 raise AttributeError(
216 'mode_number field only exists for analysis_types {:}'.format(
217 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
220 @mode_number.setter
221 def mode_number(self, value):
222 valid_types = [2,3]
223 index = 1
224 if self.analysis_type in valid_types:
225 try:
226 self.integer_data[index] = value
227 except IndexError:
228 print('Integer data currently only has {:} indices, tried to index {:}, expanding to {:}'.format(
229 len(self.integer_data), index, index + 1))
230 self.integer_data += ((index + 1) - (len(self.integer_data))) * [0]
231 self.integer_data[index] = value
232 else:
233 raise AttributeError(
234 'mode_number field only exists for analysis_types {:}'.format(
235 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
237 @property
238 def time_step_number(self):
239 valid_types = [4]
240 index = 1
241 if self.analysis_type in valid_types:
242 return self.integer_data[index]
243 else:
244 raise AttributeError(
245 'time_step_number field only exists for analysis_types {:}'.format(
246 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
249 @time_step_number.setter
250 def time_step_number(self, value):
251 valid_types = [4]
252 index = 1
253 if self.analysis_type in valid_types:
254 try:
255 self.integer_data[index] = value
256 except IndexError:
257 print('Integer data currently only has {:} indices, tried to index {:}, expanding to {:}'.format(
258 len(self.integer_data), index, index + 1))
259 self.integer_data += ((index + 1) - (len(self.integer_data))) * [0]
260 self.integer_data[index] = value
261 else:
262 raise AttributeError(
263 'time_step_number field only exists for analysis_types {:}'.format(
264 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
266 @property
267 def frequency_step_number(self):
268 valid_types = [4]
269 index = 1
270 if self.analysis_type in valid_types:
271 return self.integer_data[index]
272 else:
273 raise AttributeError(
274 'frequency_step_number field only exists for analysis_types {:}'.format(
275 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
278 @frequency_step_number.setter
279 def frequency_step_number(self, value):
280 valid_types = [5]
281 index = 1
282 if self.analysis_type in valid_types:
283 try:
284 self.integer_data[index] = value
285 except IndexError:
286 print('Integer data currently only has {:} indices, tried to index {:}, expanding to {:}'.format(
287 len(self.integer_data), index, index + 1))
288 self.integer_data += ((index + 1) - (len(self.integer_data))) * [0]
289 self.integer_data[index] = value
290 else:
291 raise AttributeError(
292 'frequency_step_number field only exists for analysis_types {:}'.format(
293 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
295 @property
296 def frequency(self):
297 valid_types = [2,5]
298 if self.analysis_type in valid_types:
299 index = 0
300 return self.real_data[index]
301 else:
302 raise AttributeError(
303 'frequency field only exists for analysis_types {:}'.format(
304 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
307 @frequency.setter
308 def frequency(self, value):
309 valid_types = [2,5]
310 index = 0
311 if self.analysis_type in valid_types:
312 try:
313 self.real_data[index] = value
314 except IndexError:
315 print('Real data currently only has {:} indices, tried to index {:}, expanding to {:}'.format(
316 len(self.real_data), index, index + 1))
317 self.real_data += ((index + 1) - (len(self.real_data))) * [0]
318 self.real_data[index] = value
319 else:
320 raise AttributeError(
321 'frequency field only exists for analysis_types {:}'.format(
322 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
324 @property
325 def modal_mass(self):
326 valid_types = [2]
327 index = 1
328 if self.analysis_type in valid_types:
329 return self.real_data[index]
330 else:
331 raise AttributeError(
332 'modal_mass field only exists for analysis_types {:}'.format(
333 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
336 @modal_mass.setter
337 def modal_mass(self, value):
338 valid_types = [2]
339 index = 1
340 if self.analysis_type in valid_types:
341 try:
342 self.real_data[index] = value
343 except IndexError:
344 print('Real data currently only has {:} indices, tried to index {:}, expanding to {:}'.format(
345 len(self.real_data), index, index + 1))
346 self.real_data += ((index + 1) - (len(self.real_data))) * [0]
347 self.real_data[index] = value
348 else:
349 raise AttributeError(
350 'modal_mass field only exists for analysis_types {:}'.format(
351 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
354 @property
355 def modal_viscous_damping(self):
356 valid_types = [2]
357 index = 2
358 if self.analysis_type in valid_types:
359 return self.real_data[index]
360 else:
361 raise AttributeError(
362 'modal_viscous_damping field only exists for analysis_types {:}'.format(
363 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
366 @modal_viscous_damping.setter
367 def modal_viscous_damping(self, value):
368 valid_types = [2]
369 index = 2
370 if self.analysis_type in valid_types:
371 try:
372 self.real_data[index] = value
373 except IndexError:
374 print('Real data currently only has {:} indices, tried to index {:}, expanding to {:}'.format(
375 len(self.real_data), index, index + 1))
376 self.real_data += ((index + 1) - (len(self.real_data))) * [0]
377 self.real_data[index] = value
378 else:
379 raise AttributeError(
380 'modal_viscous_damping field only exists for analysis_types {:}'.format(
381 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
383 @property
384 def modal_hysteretic_damping(self):
385 valid_types = [2]
386 index = 3
387 if self.analysis_type in valid_types:
388 return self.real_data[index]
389 else:
390 raise AttributeError(
391 'modal_hysteretic_damping field only exists for analysis_types {:}'.format(
392 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
395 @modal_hysteretic_damping.setter
396 def modal_hysteretic_damping(self, value):
397 valid_types = [2]
398 index = 3
399 if self.analysis_type in valid_types:
400 try:
401 self.real_data[index] = value
402 except IndexError:
403 print('Real data currently only has {:} indices, tried to index {:}, expanding to {:}'.format(
404 len(self.real_data), index, index + 1))
405 self.real_data += ((index + 1) - (len(self.real_data))) * [0]
406 self.real_data[index] = value
407 else:
408 raise AttributeError(
409 'modal_hysteretic_damping field only exists for analysis_types {:}'.format(
410 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
412 @property
413 def eigenvalue(self):
414 valid_types = [3,6]
415 if self.analysis_type in valid_types:
416 if self.analysis_type == 3:
417 return self.real_data[0] + 1j*self.real_data[1]
418 elif self.analysis_type == 6:
419 return self.real_data[0]
420 else:
421 raise AttributeError(
422 'eigenvalue field only exists for analysis_types {:}'.format(
423 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
426 @eigenvalue.setter
427 def eigenvalue(self, value):
428 valid_types = [3,6]
429 if self.analysis_type in valid_types:
430 if self.analysis_type == 3:
431 try:
432 self.real_data[0] = np.real(value)
433 self.real_data[1] = np.imag(value)
434 except IndexError:
435 print('Real data currently only has {:} indices, tried to index {:}, expanding to {:}'.format(
436 len(self.real_data), 1, 1 + 1))
437 self.real_data += ((1 + 1) - (len(self.real_data))) * [0]
438 self.real_data[0] = np.real(value)
439 self.real_data[1] = np.imag(value)
440 if self.analysis_type == 6:
441 index = 0
442 try:
443 self.real_data[index] = value
444 except IndexError:
445 print('Real data currently only has {:} indices, tried to index {:}, expanding to {:}'.format(
446 len(self.real_data), index, index + 1))
447 self.real_data += ((index + 1) - (len(self.real_data))) * [0]
448 self.real_data[index] = value
449 else:
450 raise AttributeError(
451 'eigenvalue field only exists for analysis_types {:}'.format(
452 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
455 @property
456 def modal_a(self):
457 valid_types = [3]
458 if self.analysis_type in valid_types:
459 return self.real_data[2] + 1j*self.real_data[3]
460 else:
461 raise AttributeError(
462 'modal_a field only exists for analysis_types {:}'.format(
463 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
466 @modal_a.setter
467 def modal_a(self, value):
468 valid_types = [3]
469 if self.analysis_type in valid_types:
470 try:
471 self.real_data[2] = np.real(value)
472 self.real_data[3] = np.imag(value)
473 except IndexError:
474 print('Real data currently only has {:} indices, tried to index {:}, expanding to {:}'.format(
475 len(self.real_data), 3, 3 + 1))
476 self.real_data += ((3 + 1) - (len(self.real_data))) * [0]
477 self.real_data[2] = np.real(value)
478 self.real_data[3] = np.imag(value)
479 else:
480 raise AttributeError(
481 'modal_a field only exists for analysis_types {:}'.format(
482 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
484 @property
485 def modal_b(self):
486 valid_types = [3]
487 if self.analysis_type in valid_types:
488 return self.real_data[2] + 1j*self.real_data[3]
489 else:
490 raise AttributeError(
491 'modal_b field only exists for analysis_types {:}'.format(
492 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
495 @modal_b.setter
496 def modal_b(self, value):
497 valid_types = [3]
498 if self.analysis_type in valid_types:
499 try:
500 self.real_data[4] = np.real(value)
501 self.real_data[5] = np.imag(value)
502 except IndexError:
503 print('Real data currently only has {:} indices, tried to index {:}, expanding to {:}'.format(
504 len(self.real_data), 5, 5 + 1))
505 self.real_data += ((5 + 1) - (len(self.real_data))) * [0]
506 self.real_data[4] = np.real(value)
507 self.real_data[5] = np.imag(value)
508 else:
509 raise AttributeError(
510 'modal_b field only exists for analysis_types {:}'.format(
511 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
513 @property
514 def time(self):
515 valid_types = [4]
516 index = 0
517 if self.analysis_type in valid_types:
518 return self.real_data[index]
519 else:
520 raise AttributeError(
521 'time field only exists for analysis_types {:}'.format(
522 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
525 @time.setter
526 def time(self, value):
527 valid_types = [4]
528 index = 0
529 if self.analysis_type in valid_types:
530 try:
531 self.real_data[index] = value
532 except IndexError:
533 print('Real data currently only has {:} indices, tried to index {:}, expanding to {:}'.format(
534 len(self.real_data), index, index + 1))
535 self.real_data += ((index + 1) - (len(self.real_data))) * [0]
536 self.real_data[index] = value
537 else:
538 raise AttributeError(
539 'time field only exists for analysis_types {:}'.format(
540 ', '.join(['{:} ({:})'.format(t,_analysis_types[t]) for t in valid_types])))
542 @classmethod
543 def from_uff_data_array(cls, data):
544 # Transform from binary to ascii
545 data = [line.decode() for line in data]
546 # RECORD 1: Format (40A2)
547 # FIELD 1: ID Line 1
548 idline1, = parse_uff_line(data[0], ['A80'])
549# RECORD 2: Format (40A2)
550# FIELD 1: ID Line 2
551 idline2, = parse_uff_line(data[1], ['A80'])
552# RECORD 3: Format (40A2)
553#
554# FIELD 1: ID Line 3
555 idline3, = parse_uff_line(data[2], ['A80'])
556# RECORD 4: Format (40A2)
557# FIELD 1: ID Line 4
558 idline4, = parse_uff_line(data[3], ['A80'])
559# RECORD 5: Format (40A2)
560# FIELD 1: ID Line 5
561 idline5, = parse_uff_line(data[4], ['A80'])
562# RECORD 6: Format (6I10)
563#
564# Data Definition Parameters
565#
566# FIELD 1: Model Type
567# 0: Unknown
568# 1: Structural
569# 2: Heat Transfer
570# 3: Fluid Flow
571#
572# FIELD 2: Analysis Type
573# 0: Unknown
574# 1: Static
575# 2: Normal Mode
576# 3: Complex eigenvalue first order
577# 4: Transient
578# 5: Frequency Response
579# 6: Buckling
580# 7: Complex eigenvalue second order
581#
582# FIELD 3: Data Characteristic
583# 0: Unknown
584# 1: Scalar
585# 2: 3 DOF Global Translation
586# Vector
587# 3: 6 DOF Global Translation
588# & Rotation Vector
589# 4: Symmetric Global Tensor
590# 5: General Global Tensor
591#
592#
593#
594# FIELD 4: Specific Data Type
595# 0: Unknown
596# 1: General
597# 2: Stress
598# 3: Strain (Engineering)
599# 4: Element Force
600# 5: Temperature
601# 6: Heat Flux
602# 7: Strain Energy
603# 8: Displacement
604# 9: Reaction Force
605# 10: Kinetic Energy
606# 11: Velocity
607# 12: Acceleration
608# 13: Strain Energy Density
609# 14: Kinetic Energy Density
610# 15: Hydro-Static Pressure
611# 16: Heat Gradient
612# 17: Code Checking Value
613# 18: Coefficient Of Pressure
614#
615# FIELD 5: Data Type
616# 2: Real
617# 5: Complex
618#
619# FIELD 6: Number Of Data Values Per Node (NDV)
620 model_type, analysis_type, data_characteristic, specific_data_type, data_type, num_data_per_node = (
621 parse_uff_line(data[5], 6 * ['I10']))
622 # Correct the number of values per node
623 if data_characteristic == 2:
624 required_data_values = 3
625 if num_data_per_node != required_data_values:
626 print('Warning: Dataset 55 has data characteristic "3 DOF Global Translation" but has {:} data values per node (should be {:})\nUniversal File is formatted incorrectly.'.format(num_data_per_node,required_data_values))
627 num_data_per_node = required_data_values
628 elif data_characteristic == 3:
629 required_data_values = 6
630 if num_data_per_node != required_data_values:
631 print('Warning: Dataset 55 has data characteristic "3 DOF Global Translation & Rotation Vector" but has {:} data values per node (should be {:})\nUniversal File is formatted incorrectly.'.format(num_data_per_node,required_data_values))
632 num_data_per_node = required_data_values
633 elif data_characteristic == 4:
634 required_data_values = 6
635 if num_data_per_node != required_data_values:
636 print('Warning: Dataset 55 has data characteristic "Symmetric GLobal Tensor" but has {:} data values per node (should be {:})\nUniversal File is formatted incorrectly.'.format(num_data_per_node,required_data_values))
637 num_data_per_node = required_data_values
638 elif data_characteristic == 5:
639 required_data_values = 9
640 if num_data_per_node != required_data_values:
641 print('Warning: Dataset 55 has data characteristic "General GLobal Tensor" but has {:} data values per node (should be {:})\nUniversal File is formatted incorrectly.'.format(num_data_per_node,required_data_values))
642 num_data_per_node = required_data_values
643 data_is_complex = data_type == 5
644# Records 7 And 8 Are Analysis Type Specific
645#
646# General Form
647#
648# RECORD 7: Format (8I10)
649#
650# FIELD 1: Number Of Integer Data Values
651# 1 < Or = Nint < Or = 10
652# FIELD 2: Number Of Real Data Values
653# 1 < Or = Nrval < Or = 12
654# FIELDS 3-N: Type Specific Integer Parameters
655#
656#
657# RECORD 8: Format (6E13.5)
658# FIELDS 1-N: Type Specific Real Parameters
659 # Initially just read the number of data that we will get
660 nints, nreals = parse_uff_line(data[6], 2 * ['I10'])
661 # Now read the whole of record 7
662 int_data, lines_read = parse_uff_lines(data[6:], 8 * ['I10'], 2 + nints)
663 next_line = 6 + lines_read
664 integer_data = int_data[2:]
665 real_data, lines_read = parse_uff_lines(data[next_line:], 6 * ['E13.5'], nreals)
666 next_line += lines_read
667# RECORD 9: Format (I10)
668#
669# FIELD 1: Node Number
670#
671# RECORD 10: Format (6E13.5)
672# FIELDS 1-N: Data At This Node (NDV Real Or
673# Complex Values)
674#
675# Records 9 And 10 Are Repeated For Each Node.
676 node_data_dictionary = {}
677 while next_line < len(data):
678 node, = parse_uff_line(data[next_line], ['I10'])
679 next_line += 1
680 node_data, read_lines = parse_uff_lines(
681 data[next_line:], 6 * ['E13.5'], num_data_per_node * (2 if data_is_complex else 1))
682 next_line += read_lines
683 if data_is_complex:
684 node_data_dictionary[node] = [real + 1j *
685 imag for real, imag in zip(node_data[::2], node_data[1::2])]
686 else:
687 node_data_dictionary[node] = node_data
689 ds_55 = cls(idline1, idline2, idline3, idline4, idline5, model_type,
690 analysis_type, data_characteristic, specific_data_type, data_type,
691 integer_data, real_data, node_data_dictionary)
692 return ds_55
694 def __repr__(self):
695 return 'Sdynpy_UFF_Dataset_55<Shape with {:} Nodes>'.format(len(self.node_data_dictionary))
697 def write_string(self):
698 return_string = ''
699 # See how many values are in each node
700 nodes = [key for key in self.node_data_dictionary.keys()]
701 if self.data_type == 5:
702 num_data = int(len(self.node_data_dictionary[nodes[0]]) // 2)
703 else:
704 num_data = int(len(self.node_data_dictionary[nodes[0]]))
705 return_string += write_uff_line(['NONE' if self.idline1 == '' else self.idline1,
706 'NONE' if self.idline2 == '' else self.idline2,
707 'NONE' if self.idline3 == '' else self.idline3,
708 'NONE' if self.idline4 == '' else self.idline4,
709 'NONE' if self.idline5 == '' else self.idline5,
710 ], ['A80'])
711 return_string += write_uff_line([self.model_type,
712 self.analysis_type,
713 self.data_characteristic,
714 self.specific_data_type,
715 self.data_type,
716 num_data], 6 * ['I10'])
717 nint = len(self.integer_data)
718 nfloat = len(self.real_data)
719 return_string += write_uff_line([nint, nfloat] + self.integer_data,
720 8 * ['I10'])
721 return_string += write_uff_line(self.real_data, 6 * ['E13.5'])
722 for node in sorted(self.node_data_dictionary.keys()):
723 return_string += write_uff_line([node], ['I10'])
724 return_string += write_uff_line(
725 [fn(val) for val in self.node_data_dictionary[node] for fn in (np.real, np.imag)]
726 if np.iscomplexobj(self.node_data_dictionary[node])
727 else self.node_data_dictionary[node], 6 * ['E13.5'])
728 return return_string
730 def __str__(self):
731 lines = self.write_string().split('\n')
732 if len(lines) > 8:
733 return 'Dataset 55: Shapes\n ' + '\n '.join(lines[0:5] + ['.', '.', '.'])
734 else:
735 return 'Dataset 55: Shapes\n ' + '\n '.join(lines)
738def read(data):
739 return Sdynpy_UFF_Dataset_55.from_uff_data_array(data)