Coverage for src / sdynpy / fileio / sdynpy_uff_datasets / sdynpy_uff_dataset_2400.py: 10%
115 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"""
3Model Header
5This dataset defines the header for a model in a universal file
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"""
26import datetime
27from ..sdynpy_uff import UFFReadError
30class Sdynpy_UFF_Dataset_2400:
31 def __init__(self,
32 model_uid=100,
33 entity_type=7,
34 entity_subtype=1,
35 version_number=-1,
36 entity_name='sdynpy_geometry',
37 part_number='',
38 status_mask=[False] * 32,
39 datetime_short_time_format=None,
40 idm_item_version_id=1,
41 idm_item_id=1,
42 primary_parent_uid=9,
43 geometry_switch=False,
44 p_analysis_switch=False,
45 all_selections_switch=False,
46 auto_create_dynamic_groups_switch=False,
47 acdg_1d_element_switch=False,
48 acdg_2d_element_switch=False,
49 acdg_3d_element_switch=False,
50 acdg_other_element_switch=False,
51 acdg_related_nodes_switch=False,
52 acdg_related_geometry_switch=False,
53 acdg_related_boundary_condition_switch=False):
54 self.model_uid = model_uid
55 self.entity_type = entity_type
56 self.entity_subtype = entity_subtype
57 self.version_number = version_number
58 self.entity_name = entity_name
59 self.part_number = part_number
60 self.status_mask = status_mask
61 self.datetime_short_time_format = datetime_short_time_format
62 self.idm_item_version_id = idm_item_version_id
63 self.idm_item_id = idm_item_id
64 self.primary_parent_uid = primary_parent_uid
65 self.geometry_switch = geometry_switch
66 self.p_analysis_switch = p_analysis_switch
67 self.all_selections_switch = all_selections_switch
68 self.auto_create_dynamic_groups_switch = auto_create_dynamic_groups_switch
69 self.acdg_1d_element_switch = acdg_1d_element_switch
70 self.acdg_2d_element_switch = acdg_2d_element_switch
71 self.acdg_3d_element_switch = acdg_3d_element_switch
72 self.acdg_other_element_switch = acdg_other_element_switch
73 self.acdg_related_nodes_switch = acdg_related_nodes_switch
74 self.acdg_related_geometry_switch = acdg_related_geometry_switch
75 self.acdg_related_boundary_condition_switch = acdg_related_boundary_condition_switch
77 @property
78 def dataset_number(self):
79 return 2400
81 @classmethod
82 def from_uff_data_array(cls, data):
83 # Transform from binary to ascii
84 data = [line.decode() for line in data]
85 # Record 1: FORMAT(I12,2I6,I12)
86 # Field 1 -- Model UID
87 # Field 2 -- Entity type
88 # Field 3 -- Entity subtype
89 # Field 4 -- Version number
90 try:
91 model_uid = int(data[0][0:12])
92 except ValueError:
93 model_uid = data[0][0:12].strip()
94 try:
95 entity_type = int(data[0][12:18])
96 except ValueError:
97 entity_type = data[0][12:18].strip()
98 try:
99 entity_subtype = int(data[0][18:24])
100 except ValueError:
101 entity_subtype = data[0][18:24].strip()
102 try:
103 version_number = int(data[0][24:36])
104 except ValueError:
105 version_number = data[0][24:36].strip()
106 #
107 # Record 2: FORMAT(40A2)
108 # Field 1 -- Entity name
109 entity_name = data[1][0:40].strip()
110 #
111 # Record 3: FORMAT(40A2)
112 # Field 1 -- Part number
113 part_number = data[2][0:40].strip()
114 #
115 # Record 4: FORMAT(32I2)
116 # Field 1-32 -- Status mask
117 try:
118 status_mask = int(data[3][0:32])
119 except ValueError:
120 status_mask = data[3][0:32].strip()
121 #
122 # Record 5: FORMAT(10A2,3I12)
123 # Field 1-2 -- Date/time short time format
124 # Field 3 -- IDM item version ID
125 # Field 4 -- IDM item ID
126 # Field 5 -- Primary parent UID
127 try:
128 datetime_short_time_format = datetime.datetime.strptime(
129 ''.join(data[4][0:20].split()), '%d-%b-%y%H:%M:%S')
130 except ValueError:
131 datetime_short_time_format = data[4][0:20].strip()
132 try:
133 idm_item_version_id = int(data[4][20:32])
134 except ValueError:
135 idm_item_version_id = data[4][20:32].strip()
136 try:
137 idm_item_id = int(data[4][32:44])
138 except ValueError:
139 idm_item_id = data[4][32:44].strip()
140 try:
141 primary_parent_uid = int(data[4][44:56])
142 except ValueError:
143 primary_parent_uid = data[4][44:56].strip()
144 #
145 # Record 6: FORMAT(I12)
146 # Field 1 -- Optimization switch bitmask
147 # Bit 1 = Geometry switch
148 # Bit 2 = P analysis switch
149 # Bit 3 = All sections switch
150 # Bit 4 = Auto create dynamic groups switch
151 # Bit 5 = Auto create dynamic group -
152 # 1D element switch
153 # Bit 6 = Auto create dynamic group -
154 # 2D element switch
155 # Bit 7 = Auto create dynamic group -
156 # 3D element switch
157 # Bit 8 = Auto create dynamic group -
158 # Other element switch
159 # Bit 9 = Auto create dynamic group -
160 # Related nodes switch
161 # Bit 10= Auto create dynamic group -
162 # Related geometry switch
163 # Bit 11= Auto create dynamic group -
164 # Related boundary condition switch
165 try:
166 integer = int(data[5][0:12])
167 # TODO: I'm not sure if bit 1 is the most significant bit or least significant bit.
168 # I will assume most significant
169 geometry_switch = bool(integer & 2**10)
170 p_analysis_switch = bool(integer & 2**9)
171 all_selections_switch = bool(integer & 2**8)
172 auto_create_dynamic_groups_switch = bool(integer & 2**7)
173 acdg_1d_element_switch = bool(integer & 2**6)
174 acdg_2d_element_switch = bool(integer & 2**5)
175 acdg_3d_element_switch = bool(integer & 2**4)
176 acdg_other_element_switch = bool(integer & 2**3)
177 acdg_related_nodes_switch = bool(integer & 2**2)
178 acdg_related_geometry_switch = bool(integer & 2**1)
179 acdg_related_boundary_condition_switch = bool(integer & 2**0)
180 except ValueError:
181 geometry_switch = False
182 p_analysis_switch = False
183 all_selections_switch = False
184 auto_create_dynamic_groups_switch = False
185 acdg_1d_element_switch = False
186 acdg_2d_element_switch = False
187 acdg_3d_element_switch = False
188 acdg_other_element_switch = False
189 acdg_related_nodes_switch = False
190 acdg_related_geometry_switch = False
191 acdg_related_boundary_condition_switch = False
193 ds_2400 = cls(model_uid, entity_type, entity_subtype, version_number,
194 entity_name, part_number, status_mask,
195 datetime_short_time_format, idm_item_version_id,
196 idm_item_id, primary_parent_uid, geometry_switch,
197 p_analysis_switch, all_selections_switch,
198 auto_create_dynamic_groups_switch,
199 acdg_1d_element_switch, acdg_2d_element_switch,
200 acdg_3d_element_switch, acdg_other_element_switch,
201 acdg_related_nodes_switch, acdg_related_geometry_switch,
202 acdg_related_boundary_condition_switch)
203 return ds_2400
205 def __repr__(self):
206 return 'Sdynpy_UFF_Dataset_2400<{}>'.format(self.entity_name)
208 def write_string(self):
209 try:
210 datetime_short_time_format = ('{:<10}'.format(self.datetime_short_time_format.strftime('%d-%b-%y')) +
211 '{:<10}'.format(self.datetime_short_time_format.strftime('%H:%M:%S')))
212 except AttributeError:
213 datetime_short_time_format = self.datetime_short_time_format
214 if isinstance(self.status_mask, str):
215 status_mask = self.status_mask
216 else:
217 status_mask = ''.join(['{:>2}'.format(int(bool_val)) for bool_val in self.status_mask])
218 # TODO: I'm not sure if this is the correct bit order
219 optimization_switch_bitmask = sum([2**(10 - i) for i, bool_val in
220 enumerate([self.geometry_switch,
221 self.p_analysis_switch,
222 self.all_selections_switch,
223 self.auto_create_dynamic_groups_switch,
224 self.acdg_1d_element_switch,
225 self.acdg_2d_element_switch,
226 self.acdg_3d_element_switch,
227 self.acdg_other_element_switch,
228 self.acdg_related_nodes_switch,
229 self.acdg_related_geometry_switch,
230 self.acdg_related_boundary_condition_switch]) if bool_val])
232 return ('{:>12}{:>6}{:>6}{:>12}\n'.format(self.model_uid,
233 self.entity_type,
234 self.entity_subtype,
235 self.version_number) +
236 '{:<40}\n'.format(self.entity_name) +
237 '{:<40}\n'.format(self.part_number) +
238 '{:<64}\n'.format(status_mask) +
239 '{:<20}{:<12}{:<12}{:<12}\n'.format(datetime_short_time_format,
240 self.idm_item_version_id,
241 self.idm_item_id,
242 self.primary_parent_uid) +
243 '{:>12}\n'.format(optimization_switch_bitmask))
245 def __str__(self):
246 lines = self.write_string().split('\n')
247 if len(lines) > 8:
248 return 'Dataset 2400: Model Header\n ' + '\n '.join(lines[0:5] + ['.', '.', '.'])
249 else:
250 return 'Dataset 2400: Model Header\n ' + '\n '.join(lines)
253def read(data):
254 return Sdynpy_UFF_Dataset_2400.from_uff_data_array(data)