pyuff 2.5.3__tar.gz → 2.5.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyuff
3
- Version: 2.5.3
3
+ Version: 2.5.5
4
4
  Summary: UFF (Universal File Format) read/write.
5
5
  Project-URL: homepage, https://github.com/ladisk/pyuff
6
6
  Project-URL: documentation, https://pyuff.readthedocs.io/en/latest/
@@ -15,7 +15,7 @@ Classifier: Intended Audience :: Developers
15
15
  Classifier: License :: OSI Approved :: MIT License
16
16
  Classifier: Programming Language :: Python :: 3.10
17
17
  Classifier: Topic :: Scientific/Engineering
18
- Requires-Python: >=3.10
18
+ Requires-Python: >=3.11
19
19
  Requires-Dist: numpy
20
20
  Provides-Extra: dev
21
21
  Requires-Dist: build; extra == 'dev'
@@ -36,7 +36,7 @@ Universal File Format read and write
36
36
  ------------------------------------
37
37
  This module defines an UFF class to manipulate with the UFF (Universal File Format) files.
38
38
 
39
- Read from and write of data-set types **15, 55, 58, 58b, 82, 151, 164, 1858, 2411, 2412, 2414, 2420, 2429, 2467** are supported.
39
+ Read from and write of data-set types **15, 55, 58, 58b, 82, 151, 164, 1858, 2400, 2411, 2412, 2414, 2420, 2429, 2467** are supported.
40
40
 
41
41
  Check out the `documentation <https://pyuff.readthedocs.io/en/latest/index.html>`_.
42
42
 
@@ -7,7 +7,7 @@ Universal File Format read and write
7
7
  ------------------------------------
8
8
  This module defines an UFF class to manipulate with the UFF (Universal File Format) files.
9
9
 
10
- Read from and write of data-set types **15, 55, 58, 58b, 82, 151, 164, 1858, 2411, 2412, 2414, 2420, 2429, 2467** are supported.
10
+ Read from and write of data-set types **15, 55, 58, 58b, 82, 151, 164, 1858, 2400, 2411, 2412, 2414, 2420, 2429, 2467** are supported.
11
11
 
12
12
  Check out the `documentation <https://pyuff.readthedocs.io/en/latest/index.html>`_.
13
13
 
@@ -4,14 +4,14 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pyuff"
7
- version = "2.5.3"
7
+ version = "2.5.5"
8
8
  authors = [{name = "Primož Čermelj, Janko Slavič", email = "janko.slavic@fs.uni-lj.si"}]
9
9
  maintainers = [{name = "Janko Slavič et al.", email = "janko.slavic@fs.uni-lj.si"}]
10
10
  license = "MIT"
11
11
  description = "UFF (Universal File Format) read/write."
12
12
  readme = "README.rst"
13
13
  keywords = ['UFF', 'UNV', 'Universal File Format', 'read/write']
14
- requires-python = ">=3.10"
14
+ requires-python = ">=3.11"
15
15
  dependencies = [
16
16
  "numpy",
17
17
  ]
@@ -1,4 +1,4 @@
1
- __version__ = "2.5.3"
1
+ __version__ = "2.5.5"
2
2
  from .pyuff import *
3
3
  from .datasets import *
4
4
 
@@ -5,6 +5,7 @@ from .dataset_82 import prepare_82
5
5
  from .dataset_151 import prepare_151
6
6
  from .dataset_164 import prepare_164
7
7
  from .dataset_1858 import prepare_1858
8
+ from .dataset_2400 import prepare_2400
8
9
  from .dataset_2411 import prepare_2411
9
10
  from .dataset_2412 import prepare_2412
10
11
  from .dataset_2414 import prepare_2414
@@ -0,0 +1,208 @@
1
+ import numpy as np
2
+
3
+ from ..tools import _opt_fields, _parse_header_line, check_dict_for_none
4
+
5
+
6
+ def get_structure_2400(raw=False):
7
+ """(source: https://www.ceas3.uc.edu/sdrluff/"""
8
+ out = """
9
+ Universal Dataset Number: 2400
10
+
11
+ Name: Model Header
12
+ -----------------------------------------------------------------------
13
+
14
+ Record 1: FORMAT(I12,2I6,I12)
15
+ Field 1 -- model UID
16
+ Field 2 -- entity type
17
+ Field 3 -- entity subtype
18
+ Field 4 -- version number
19
+ Record 2: FORMAT(40A2)
20
+ Field 1 -- entity name
21
+ Record 3: FORMAT(40A2)
22
+ Field 1 -- part number
23
+ Record 4: FORMAT(32I2)
24
+ Field 1 -- status mask (32 values)
25
+ Record 5: FORMAT(10A1,10A1,3I12)
26
+ Field 1 -- date (DD-MMM-YY)
27
+ Field 2 -- time (HH:MM:SS)
28
+ Field 3 -- IDM version ID
29
+ Field 4 -- IDM item ID
30
+ Field 5 -- primary parent UID
31
+ Record 6: FORMAT(I12)
32
+ Field 1 -- optimization switches
33
+ =0 geometry OFF, analysis OFF
34
+ =1 geometry ON, analysis OFF
35
+ =2 geometry OFF, analysis ON
36
+ =3 geometry ON, analysis ON
37
+
38
+ -----------------------------------------------------------------
39
+ """
40
+ if raw:
41
+ return out
42
+ else:
43
+ print(out)
44
+
45
+
46
+ def _write2400(fh, dset):
47
+ """Writes dset data - data-set 2400 - to an open file fh."""
48
+ try:
49
+ dset = _opt_fields(dset, {
50
+ 'model_uid': 0,
51
+ 'entity_type': 0,
52
+ 'entity_subtype': 0,
53
+ 'version_number': 0,
54
+ 'entity_name': '',
55
+ 'part_number': '',
56
+ 'status_mask': [0] * 32,
57
+ 'date': '',
58
+ 'time': '',
59
+ 'idm_version_id': 0,
60
+ 'idm_item_id': 0,
61
+ 'primary_parent_uid': 0,
62
+ 'optimization_switches': 0,
63
+ })
64
+ fh.write('%6i\n%6i%74s\n' % (-1, 2400, ' '))
65
+ fh.write('%12i%6i%6i%12i\n' % (dset['model_uid'], dset['entity_type'],
66
+ dset['entity_subtype'], dset['version_number']))
67
+ fh.write('%-80s\n' % dset['entity_name'])
68
+ fh.write('%-80s\n' % dset['part_number'])
69
+ fh.write('%s\n' % ''.join(['%2i' % v for v in dset['status_mask']]))
70
+ fh.write('%-10s%-10s%12i%12i%12i\n' % (dset['date'], dset['time'],
71
+ dset['idm_version_id'], dset['idm_item_id'],
72
+ dset['primary_parent_uid']))
73
+ fh.write('%12i\n' % dset['optimization_switches'])
74
+ fh.write('%6i\n' % -1)
75
+ except KeyError as msg:
76
+ raise Exception('The required key \'' + msg.args[0] + '\' not present when writing data-set #2400')
77
+ except:
78
+ raise Exception('Error writing data-set #2400')
79
+
80
+
81
+ def _extract2400(block_data):
82
+ """Extract dset data - data-set 2400."""
83
+ dset = {'type': 2400}
84
+ try:
85
+ split_data = block_data.splitlines(True)
86
+ dset.update(_parse_header_line(split_data[2], 4, [12, 6, 6, 12], [2, 2, 2, 2],
87
+ ['model_uid', 'entity_type', 'entity_subtype', 'version_number']))
88
+ dset.update(_parse_header_line(split_data[3], 1, [80], [1], ['entity_name']))
89
+ dset.update(_parse_header_line(split_data[4], 1, [80], [1], ['part_number']))
90
+ # Record 4: 32 consecutive I2 fields
91
+ status_line = split_data[5]
92
+ dset['status_mask'] = [int(status_line[i*2:(i*2)+2]) for i in range(32)]
93
+ dset.update(_parse_header_line(split_data[6], 5, [10, 10, 12, 12, 12], [1, 1, 2, 2, 2],
94
+ ['date', 'time', 'idm_version_id', 'idm_item_id', 'primary_parent_uid']))
95
+ dset.update(_parse_header_line(split_data[7], 1, [12], [2], ['optimization_switches']))
96
+ except:
97
+ raise Exception('Error reading data-set #2400')
98
+ return dset
99
+
100
+
101
+ def prepare_2400(
102
+ model_uid=None,
103
+ entity_type=None,
104
+ entity_subtype=None,
105
+ version_number=None,
106
+ entity_name=None,
107
+ part_number=None,
108
+ status_mask=None,
109
+ date=None,
110
+ time=None,
111
+ idm_version_id=None,
112
+ idm_item_id=None,
113
+ primary_parent_uid=None,
114
+ optimization_switches=None,
115
+ return_full_dict=False):
116
+ """Name: Model Header
117
+
118
+ R-Record, F-Field
119
+
120
+ :param model_uid: R1 F1, Model UID
121
+ :param entity_type: R1 F2, Entity type
122
+ :param entity_subtype: R1 F3, Entity subtype
123
+ :param version_number: R1 F4, Version number
124
+ :param entity_name: R2 F1, Entity name
125
+ :param part_number: R3 F1, Part number
126
+ :param status_mask: R4 F1, Status mask (list of 32 integers)
127
+ :param date: R5 F1, Date (DD-MMM-YY)
128
+ :param time: R5 F2, Time (HH:MM:SS)
129
+ :param idm_version_id: R5 F3, IDM version ID
130
+ :param idm_item_id: R5 F4, IDM item ID
131
+ :param primary_parent_uid: R5 F5, Primary parent UID
132
+ :param optimization_switches: R6 F1, Optimization switches
133
+ :param return_full_dict: If True full dict with all keys is returned, else only specified arguments are included
134
+
135
+ **Test prepare_2400**
136
+
137
+ >>> import pyuff
138
+ >>> import os
139
+ >>> save_to_file = 'test_pyuff'
140
+ >>> dataset = pyuff.prepare_2400(
141
+ >>> model_uid=1,
142
+ >>> entity_type=7,
143
+ >>> entity_subtype=-1,
144
+ >>> version_number=0,
145
+ >>> entity_name='MyModel',
146
+ >>> part_number='PART-001',
147
+ >>> status_mask=[0]*32,
148
+ >>> date='27-FEB-26',
149
+ >>> time='12:00:00',
150
+ >>> idm_version_id=0,
151
+ >>> idm_item_id=0,
152
+ >>> primary_parent_uid=0,
153
+ >>> optimization_switches=0)
154
+ >>> if save_to_file:
155
+ >>> if os.path.exists(save_to_file):
156
+ >>> os.remove(save_to_file)
157
+ >>> uffwrite = pyuff.UFF(save_to_file)
158
+ >>> uffwrite._write_set(dataset, 'add')
159
+ >>> dataset
160
+ """
161
+ if np.array(model_uid).dtype != int and model_uid != None:
162
+ raise TypeError('model_uid must be integer')
163
+ if np.array(entity_type).dtype != int and entity_type != None:
164
+ raise TypeError('entity_type must be integer')
165
+ if np.array(entity_subtype).dtype != int and entity_subtype != None:
166
+ raise TypeError('entity_subtype must be integer')
167
+ if np.array(version_number).dtype != int and version_number != None:
168
+ raise TypeError('version_number must be integer')
169
+ if type(entity_name) != str and entity_name != None:
170
+ raise TypeError('entity_name must be string')
171
+ if type(part_number) != str and part_number != None:
172
+ raise TypeError('part_number must be string')
173
+ if status_mask != None and (not hasattr(status_mask, '__len__') or len(status_mask) != 32):
174
+ raise ValueError('status_mask must be a list of 32 integers')
175
+ if type(date) != str and date != None:
176
+ raise TypeError('date must be string')
177
+ if type(time) != str and time != None:
178
+ raise TypeError('time must be string')
179
+ if np.array(idm_version_id).dtype != int and idm_version_id != None:
180
+ raise TypeError('idm_version_id must be integer')
181
+ if np.array(idm_item_id).dtype != int and idm_item_id != None:
182
+ raise TypeError('idm_item_id must be integer')
183
+ if np.array(primary_parent_uid).dtype != int and primary_parent_uid != None:
184
+ raise TypeError('primary_parent_uid must be integer')
185
+ if np.array(optimization_switches).dtype != int and optimization_switches != None:
186
+ raise TypeError('optimization_switches must be integer')
187
+
188
+ dataset = {
189
+ 'type': 2400,
190
+ 'model_uid': model_uid,
191
+ 'entity_type': entity_type,
192
+ 'entity_subtype': entity_subtype,
193
+ 'version_number': version_number,
194
+ 'entity_name': entity_name,
195
+ 'part_number': part_number,
196
+ 'status_mask': status_mask,
197
+ 'date': date,
198
+ 'time': time,
199
+ 'idm_version_id': idm_version_id,
200
+ 'idm_item_id': idm_item_id,
201
+ 'primary_parent_uid': primary_parent_uid,
202
+ 'optimization_switches': optimization_switches,
203
+ }
204
+
205
+ if return_full_dict is False:
206
+ dataset = check_dict_for_none(dataset)
207
+
208
+ return dataset
@@ -672,18 +672,18 @@ def prepare_55(
672
672
  raise ValueError('data_type can be 2:Real or 5:Complex')
673
673
  if np.array(n_data_per_node).dtype != int and n_data_per_node != None:
674
674
  raise TypeError('n_data_per_node must be integers')
675
- if np.array(r1).dtype != float and r1 != None:
676
- raise TypeError('r1 must have float values')
677
- if np.array(r2).dtype != float and r2 != None:
678
- raise TypeError('r2 must have float values')
679
- if np.array(r3).dtype != float and r3 != None:
680
- raise TypeError('r3 must have float values')
681
- if np.array(r4).dtype != float and r4 != None:
682
- raise TypeError('r4 must have float values')
683
- if np.array(r5).dtype != float and r5 != None:
684
- raise TypeError('r5 must have float values')
685
- if np.array(r6).dtype != float and r6 != None:
686
- raise TypeError('r6 must have float values')
675
+ if not np.issubdtype(np.array(r1).dtype, np.number) and r1 != None:
676
+ raise TypeError('r1 must have numeric (float or complex) values')
677
+ if not np.issubdtype(np.array(r2).dtype, np.number) and r2 != None:
678
+ raise TypeError('r2 must have numeric (float or complex) values')
679
+ if not np.issubdtype(np.array(r3).dtype, np.number) and r3 != None:
680
+ raise TypeError('r3 must have numeric (float or complex) values')
681
+ if not np.issubdtype(np.array(r4).dtype, np.number) and r4 != None:
682
+ raise TypeError('r4 must have numeric (float or complex) values')
683
+ if not np.issubdtype(np.array(r5).dtype, np.number) and r5 != None:
684
+ raise TypeError('r5 must have numeric (float or complex) values')
685
+ if not np.issubdtype(np.array(r6).dtype, np.number) and r6 != None:
686
+ raise TypeError('r6 must have numeric (float or complex) values')
687
687
  if type(load_case) != int and load_case != None:
688
688
  raise TypeError('load_case must be integer')
689
689
  if type(mode_n) != int and mode_n != None:
@@ -696,12 +696,12 @@ def prepare_55(
696
696
  raise TypeError('modal_damp_vis must be float')
697
697
  if type(modal_damp_his) != float and modal_damp_his != None:
698
698
  raise TypeError('modal_damp_his must be float')
699
- if np.array(eig).dtype != float and eig != None:
700
- raise TypeError('eig must be float')
701
- if np.array(modal_a).dtype != float and modal_a != None:
702
- raise TypeError('modal_a must be float')
703
- if np.array(modal_b).dtype != float and modal_b != None:
704
- raise TypeError('modal_b must be float')
699
+ if not np.issubdtype(np.array(eig).dtype, np.number) and eig != None:
700
+ raise TypeError('eig must be numeric (float or complex)')
701
+ if not np.issubdtype(np.array(modal_a).dtype, np.number) and modal_a != None:
702
+ raise TypeError('modal_a must be numeric (float or complex)')
703
+ if not np.issubdtype(np.array(modal_b).dtype, np.number) and modal_b != None:
704
+ raise TypeError('modal_b must be numeric (float or complex)')
705
705
  if type(freq_step_n) != int and freq_step_n != None:
706
706
  raise TypeError('freq_step_n must be int')
707
707
  if np.array(node_nums).dtype != int and node_nums != None:
@@ -902,11 +902,6 @@ def _write58(fh, dset, mode='add', _filename=None, force_double=True):
902
902
 
903
903
  # handling abscissa spacing automatically
904
904
  # is_even = len( set( [ dset['x'][ii]-dset['x'][ii-1] for ii in range(1,len(dset['x'])) ] ) ) == 1
905
- # decode utf to ascii
906
- for k, v in dset.items():
907
- if type(v) == str:
908
- dset[k] = v.encode("utf-8").decode('ascii','ignore')
909
-
910
905
  dset['abscissa_min'] = dset['x'][0]
911
906
  dx = dset['x'][1] - dset['x'][0]
912
907
  fh.write('%6i\n%6i' % (-1, 58))
@@ -977,9 +972,9 @@ def _write58(fh, dset, mode='add', _filename=None, force_double=True):
977
972
  [fh.write(struct.pack('>d', datai)) for datai in data]
978
973
  fh.close()
979
974
  if mode.lower() == 'overwrite':
980
- fh = open(_filename, 'wt')
975
+ fh = open(_filename, 'wt', encoding='utf-8')
981
976
  elif mode.lower() == 'add':
982
- fh = open(_filename, 'at')
977
+ fh = open(_filename, 'at', encoding='utf-8')
983
978
  else:
984
979
  if is_double: # write double precision
985
980
  n4_blocks = len(data) // 4
@@ -7,7 +7,7 @@ This module defines an UFF class to manipulate with the
7
7
  UFF (Universal File Format) files, i.e., to read from and write
8
8
  to UFF files. Among the variety of UFF formats, only some of the
9
9
  formats (data-set types) frequently used in structural dynamics
10
- are supported: **15, 55, 58, 58b, 82, 151, 164, 2411, 2412, 2414, 2420, 2429, 2467**
10
+ are supported: **15, 55, 58, 58b, 82, 151, 164, 1858, 2400, 2411, 2412, 2414, 2420, 2429, 2467**
11
11
  Data-set **58b** is actually a hybrid format [1]_ where the signal is written in the
12
12
  binary form, while the header-part is slightly different from 58 but still in the
13
13
  ascii format.
@@ -54,6 +54,7 @@ from .datasets.dataset_82 import _write82, _extract82, get_structure_82
54
54
  from .datasets.dataset_151 import _write151, _extract151, get_structure_151
55
55
  from .datasets.dataset_164 import _write164, _extract164, get_structure_164
56
56
  from .datasets.dataset_1858 import _write1858, _extract1858, get_structure_1858
57
+ from .datasets.dataset_2400 import _write2400, _extract2400, get_structure_2400
57
58
  from .datasets.dataset_2411 import _write2411, _extract2411, get_structure_2411
58
59
  from .datasets.dataset_2412 import _write2412, _extract2412, get_structure_2412
59
60
  from .datasets.dataset_2414 import _write2414, _extract2414, get_structure_2414
@@ -61,7 +62,7 @@ from .datasets.dataset_2420 import _write2420, _extract2420, get_structure_2420
61
62
  from .datasets.dataset_2429 import _write2429, _extract2429, get_structure_2429
62
63
  from .datasets.dataset_2467 import _write2467, _extract2467, get_structure_2467
63
64
 
64
- _SUPPORTED_SETS = ['15', '55', '58', '58b', '82', '151', '164', '1858', '2411', '2412', '2414', '2420', '2429', '2467']
65
+ _SUPPORTED_SETS = ['15', '55', '58', '58b', '82', '151', '164', '1858', '2400', '2411', '2412', '2414', '2420', '2429', '2467']
65
66
 
66
67
 
67
68
  class UFF:
@@ -379,6 +380,8 @@ class UFF:
379
380
  dset = _extract164(block_data)
380
381
  elif self._set_types[int(n)] == 1858:
381
382
  dset = _extract1858(block_data)
383
+ elif self._set_types[int(n)] == 2400:
384
+ dset = _extract2400(block_data)
382
385
  elif self._set_types[int(n)] == 2411:
383
386
  dset = _extract2411(block_data) # TEMP ADD
384
387
  elif self._set_types[int(n)] == 2412:
@@ -416,13 +419,13 @@ class UFF:
416
419
  if mode.lower() == 'overwrite':
417
420
  # overwrite mode
418
421
  try:
419
- fh = open(self._filename, 'wt')
422
+ fh = open(self._filename, 'wt', encoding='utf-8')
420
423
  except:
421
424
  raise Exception('Cannot access the file: ' + self._filename + ' to write to.')
422
425
  elif mode.lower() == 'add':
423
426
  # add (append) mode
424
427
  try:
425
- fh = open(self._filename, 'at')
428
+ fh = open(self._filename, 'at', encoding='utf-8')
426
429
  except:
427
430
  raise Exception('Cannot access the file: ' + self._filename + ' to write to.')
428
431
  else:
@@ -452,6 +455,8 @@ class UFF:
452
455
  _write164(fh, dset)
453
456
  elif set_type == 1858:
454
457
  _write1858(fh, dset)
458
+ elif set_type == 2400:
459
+ _write2400(fh, dset)
455
460
  elif set_type == 2411:
456
461
  _write2411(fh, dset)
457
462
  elif set_type == 2412:
File without changes
File without changes
File without changes