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

1# -*- coding: utf-8 -*- 

2""" 

3Model Header 

4 

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. 

11 

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. 

16 

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. 

21 

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""" 

25 

26import datetime 

27from ..sdynpy_uff import UFFReadError 

28 

29 

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 

76 

77 @property 

78 def dataset_number(self): 

79 return 2400 

80 

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 

192 

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 

204 

205 def __repr__(self): 

206 return 'Sdynpy_UFF_Dataset_2400<{}>'.format(self.entity_name) 

207 

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]) 

231 

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)) 

244 

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) 

251 

252 

253def read(data): 

254 return Sdynpy_UFF_Dataset_2400.from_uff_data_array(data)