Coverage for lasso/dyna/test_d3plot.py: 96%

198 statements  

« prev     ^ index     » next       coverage.py v7.2.4, created at 2023-04-28 18:42 +0100

1import os 

2import tempfile 

3from lasso.io.binary_buffer import BinaryBuffer 

4from lasso.femzip.femzip_api import FemzipAPI 

5from unittest import TestCase 

6 

7import struct 

8import numpy as np 

9 

10from lasso.dyna.d3plot import D3plot, FilterType, _negative_to_positive_state_indexes 

11from lasso.dyna.array_type import ArrayType 

12 

13 

14class D3plotTest(TestCase): 

15 def test_init(self): 

16 

17 # settings 

18 self.maxDiff = None 

19 

20 filepath = "test/simple_d3plot/d3plot" 

21 

22 geometry_array_shapes = { 

23 "node_coordinates": (4915, 3), 

24 "element_solid_part_indexes": (0,), 

25 "element_solid_node_indexes": (0, 8), 

26 "element_tshell_node_indexes": (0, 8), 

27 "element_tshell_part_indexes": (0,), 

28 "element_beam_part_indexes": (0,), 

29 "element_beam_node_indexes": (0, 5), 

30 "element_shell_node_indexes": (4696, 4), 

31 "element_shell_part_indexes": (4696,), 

32 "node_ids": (4915,), 

33 "element_solid_ids": (0,), 

34 "element_beam_ids": (0,), 

35 "element_shell_ids": (4696,), 

36 "element_tshell_ids": (0,), 

37 "part_titles_ids": (1,), 

38 "part_titles": (1,), 

39 } 

40 

41 state_array_shapes = { 

42 "timesteps": (1,), 

43 "global_kinetic_energy": (1,), 

44 "global_internal_energy": (1,), 

45 "global_total_energy": (1,), 

46 "global_velocity": (1, 3), 

47 "part_internal_energy": (1, 1), 

48 "part_kinetic_energy": (1, 1), 

49 "part_velocity": (1, 1, 3), 

50 "part_mass": (1, 1), 

51 "part_hourglass_energy": (1, 1), 

52 "node_displacement": (1, 4915, 3), 

53 "node_velocity": (1, 4915, 3), 

54 "node_acceleration": (1, 4915, 3), 

55 "element_shell_stress": (1, 4696, 3, 6), 

56 "element_shell_effective_plastic_strain": (1, 4696, 3), 

57 "element_shell_history_vars": (1, 4696, 3, 19), 

58 "element_shell_bending_moment": (1, 4696, 3), 

59 "element_shell_shear_force": (1, 4696, 2), 

60 "element_shell_normal_force": (1, 4696, 3), 

61 "element_shell_thickness": (1, 4696), 

62 "element_shell_unknown_variables": (1, 4696, 2), 

63 "element_shell_strain": (1, 4696, 2, 6), 

64 "element_shell_internal_energy": (1, 4696), 

65 "element_shell_is_alive": (1, 4696), 

66 } 

67 

68 all_array_shapes = {**geometry_array_shapes, **state_array_shapes} 

69 

70 # empty constructor 

71 D3plot() 

72 

73 # file thing 

74 d3plot = D3plot(filepath) 

75 d3plot_shapes = {array_name: array.shape for array_name, array in d3plot.arrays.items()} 

76 self.assertDictEqual(d3plot_shapes, all_array_shapes) 

77 

78 # limited buffer files 

79 d3plot = D3plot(filepath, buffered_reading=True) 

80 d3plot_shapes = {array_name: array.shape for array_name, array in d3plot.arrays.items()} 

81 self.assertDictEqual(d3plot_shapes, all_array_shapes) 

82 

83 # test loading single state arrays 

84 for array_name, array_shape in state_array_shapes.items(): 

85 d3plot = D3plot(filepath, state_array_filter=[array_name]) 

86 d3plot_shapes = {array_name: array.shape for array_name, array in d3plot.arrays.items()} 

87 self.assertDictEqual(d3plot_shapes, {**geometry_array_shapes, array_name: array_shape}) 

88 

89 # test loading individual states 

90 d3plot = D3plot(filepath, state_filter={0}) 

91 d3plot2 = D3plot(filepath) 

92 hdr_diff, array_diff = d3plot.compare(d3plot2) 

93 self.assertEqual(d3plot.n_timesteps, 1) 

94 self.assertDictEqual(hdr_diff, {}) 

95 self.assertDictEqual(array_diff, {}) 

96 

97 def test_header(self): 

98 

99 test_header_data = { 

100 "title": " ", 

101 "runtime": 1472027823, 

102 "filetype": 1, 

103 "source_version": -971095103, 

104 "release_version": "R712", 

105 "version": 960.0, 

106 "ndim": 4, 

107 "numnp": 4915, 

108 "it": 0, 

109 "iu": 1, 

110 "iv": 1, 

111 "ia": 1, 

112 "nel2": 0, 

113 "nel4": 4696, 

114 "nel8": 0, 

115 "nelt": 0, 

116 "nel20": 0, 

117 "nel27": 0, 

118 "nel48": 0, 

119 "nv1d": 6, 

120 "nv2d": 102, 

121 "nv3d": 32, 

122 "nv3dt": 90, 

123 "nummat4": 1, 

124 "nummat8": 0, 

125 "nummat2": 0, 

126 "nummatt": 0, 

127 "icode": 6, 

128 "nglbv": 13, 

129 "numst": 0, 

130 "numds": 0, 

131 "neiph": 25, 

132 "neips": 19, 

133 "maxint": -10003, 

134 "nmsph": 0, 

135 "ngpsph": 0, 

136 "narbs": 9624, 

137 "ioshl1": 1000, 

138 "ioshl2": 1000, 

139 "ioshl3": 1000, 

140 "ioshl4": 1000, 

141 "ialemat": 0, 

142 "ncfdv1": 0, 

143 "ncfdv2": 0, 

144 "nadapt": 0, 

145 "nmmat": 1, 

146 "numfluid": 0, 

147 "inn": 1, 

148 "npefg": 0, 

149 "idtdt": 0, 

150 "extra": 0, 

151 "nt3d": 0, 

152 "neipb": 0, 

153 } 

154 

155 d3plot = D3plot("test/simple_d3plot/d3plot") 

156 header = d3plot.header 

157 

158 for name, value in test_header_data.items(): 

159 self.assertEqual(header.raw_header[name], value, "Invalid var %s" % name) 

160 

161 def test_beam_integration_points(self): 

162 

163 self.maxDiff = None 

164 

165 filepath = "test/d3plot_beamip/d3plot" 

166 maxmin_test_values = { 

167 # "element_beam_shear_stress": (-0.007316963, 0.), 

168 "element_beam_shear_stress": (0.0, 0.0056635854), 

169 "element_beam_axial_stress": (-0.007316963, 0.0), 

170 "element_beam_plastic_strain": (0.0, 0.0056297667), 

171 "element_beam_axial_strain": (-0.0073745, 0.0), 

172 } 

173 

174 d3plot = D3plot(filepath) 

175 

176 for array_name, minmax in maxmin_test_values.items(): 

177 array = d3plot.arrays[array_name] 

178 self.assertAlmostEqual( 

179 array.min(), 

180 minmax[0], 

181 msg="{0}: {1} != {2}".format(array_name, array.min(), minmax[0]), 

182 ) 

183 self.assertAlmostEqual( 

184 array.max(), 

185 minmax[1], 

186 msg="{0}: {1} != {2}".format(array_name, array.max(), minmax[1]), 

187 ) 

188 

189 def test_correct_sort_of_more_than_100_state_files(self): 

190 

191 filepath = "test/order_d3plot/d3plot" 

192 

193 d3plot = D3plot(filepath) 

194 

195 timesteps = d3plot.arrays[ArrayType.global_timesteps] 

196 self.assertListEqual(timesteps.astype(int).tolist(), [1, 2, 10, 11, 12, 22, 100]) 

197 

198 def test_femzip_basic(self): 

199 

200 self.maxDiff = None 

201 

202 filepath1 = "test/femzip/d3plot.fz" 

203 filepath2 = "test/femzip/d3plot" 

204 

205 d3plot_kwargs_list = [{}, {"buffered_reading": True}, {"state_filter": [0]}] 

206 

207 D3plot.use_advanced_femzip_api = False 

208 

209 for d3plot_kwargs in d3plot_kwargs_list: 

210 

211 d3plot1 = D3plot(filepath1, **d3plot_kwargs) 

212 d3plot2 = D3plot(filepath2, **d3plot_kwargs) 

213 

214 hdr_diff, array_diff = d3plot1.compare(d3plot2, array_eps=1e-2) 

215 

216 self.assertDictEqual(hdr_diff, {}) 

217 self.assertDictEqual(array_diff, {}) 

218 

219 def test_femzip_extended(self): 

220 

221 self.maxDiff = None 

222 

223 filepath1 = "test/femzip/d3plot.fz" 

224 filepath2 = "test/femzip/d3plot" 

225 

226 d3plot_kwargs_list = [{}, {"buffered_reading": True}, {"state_filter": [0]}] 

227 

228 api = FemzipAPI() 

229 if not api.has_femunziplib_license(): 

230 return 

231 

232 D3plot.use_advanced_femzip_api = True 

233 

234 for d3plot_kwargs in d3plot_kwargs_list: 

235 

236 d3plot1 = D3plot(filepath1, **d3plot_kwargs) 

237 d3plot2 = D3plot(filepath2, **d3plot_kwargs) 

238 

239 hdr_diff, array_diff = d3plot1.compare(d3plot2, array_eps=1e-2) 

240 

241 self.assertDictEqual(hdr_diff, {}) 

242 self.assertDictEqual(array_diff, {}) 

243 

244 def test_part_filter(self): 

245 

246 self.maxDiff = None 

247 

248 filepath = "test/simple_d3plot/d3plot" 

249 part_ids = [1] 

250 

251 d3plot = D3plot(filepath) 

252 shell_filter = d3plot.get_part_filter(FilterType.SHELL, part_ids) 

253 self.assertEqual(shell_filter.sum(), 4696) 

254 

255 part_filter = d3plot.get_part_filter(FilterType.PART, part_ids) 

256 self.assertEqual(part_filter.sum(), 1) 

257 

258 node_filter = d3plot.get_part_filter(FilterType.NODE, part_ids) 

259 self.assertEqual(len(node_filter), 4915) 

260 

261 def test_read_solid_integration_points(self): 

262 

263 filepath = "test/d3plot_solid_int/d3plot" 

264 

265 # data from META 

266 stress_valid = np.array( 

267 [ 

268 2.132084e02, 

269 1.792203e02, 

270 1.397527e02, 

271 2.307352e02, 

272 2.132105e02, 

273 1.792210e02, 

274 1.397558e02, 

275 2.307304e02, 

276 ] 

277 ) 

278 pstrain_valid = np.array( 

279 [ 

280 2.227418e-02, 

281 2.576126e-03, 

282 1.909884e-02, 

283 3.695280e-02, 

284 2.227416e-02, 

285 2.576110e-03, 

286 1.909888e-02, 

287 3.695256e-02, 

288 ] 

289 ) 

290 last_timestep = -1 

291 first_element = 0 

292 stress_xx = 0 

293 

294 d3plot = D3plot(filepath) 

295 

296 stress = d3plot.arrays[ArrayType.element_solid_stress] 

297 np.array_equal(stress[last_timestep, first_element, :, stress_xx], stress_valid) 

298 

299 pstrain = d3plot.arrays[ArrayType.element_solid_effective_plastic_strain] 

300 np.array_equal(pstrain[last_timestep, first_element, :], pstrain_valid) 

301 

302 def test_negative_to_positive_state_indexes(self) -> None: 

303 

304 indexes = set() 

305 new_indexes = _negative_to_positive_state_indexes(indexes, len(indexes)) 

306 self.assertSetEqual(indexes, new_indexes) 

307 

308 indexes = {0, 1, 2} 

309 with self.assertRaises(ValueError): 

310 new_indexes = _negative_to_positive_state_indexes(indexes, 2) 

311 

312 indexes = {0, -1} 

313 new_indexes = _negative_to_positive_state_indexes(indexes, 8) 

314 self.assertSetEqual(new_indexes, {0, 7}) 

315 

316 def test_is_end_of_file_marker(self) -> None: 

317 

318 # -999999. in float32 

319 bb = BinaryBuffer() 

320 bb.memoryview = memoryview(struct.pack("<f", -999999.0)) 

321 

322 result = D3plot._is_end_of_file_marker(bb, 0, np.float32) 

323 self.assertEqual(result, True) 

324 

325 # -999999. in float64 

326 bb = BinaryBuffer() 

327 bb.memoryview = memoryview(struct.pack("<d", -999999.0)) 

328 

329 result = D3plot._is_end_of_file_marker(bb, 0, np.float64) 

330 self.assertEqual(result, True) 

331 

332 # some other number 

333 bb = BinaryBuffer() 

334 bb.memoryview = memoryview(struct.pack("<d", -41.0)) 

335 

336 result = D3plot._is_end_of_file_marker(bb, 0, np.float64) 

337 self.assertEqual(result, False) 

338 

339 # invalid dtype 

340 with self.assertRaises(ValueError): 

341 result = D3plot._is_end_of_file_marker(bb, 0, np.int32) 

342 

343 def test_write(self): 

344 

345 self.maxDiff = None 

346 

347 filepaths = [ 

348 "test/simple_d3plot/d3plot", 

349 "test/d3plot_beamip/d3plot", 

350 "test/d3plot_node_temperature/d3plot", 

351 "test/d3plot_solid_int/d3plot", 

352 ] 

353 

354 d3plot_kwargs_list = [ 

355 {}, 

356 {"buffered_reading": True}, 

357 ] 

358 

359 with tempfile.TemporaryDirectory() as dirpath: 

360 

361 for d3plot_kwargs in d3plot_kwargs_list: 

362 for d3plot_filepath, _ in zip(filepaths, d3plot_kwargs_list): 

363 

364 print(d3plot_filepath) 

365 

366 # read d3plot 

367 d3plot1 = D3plot(d3plot_filepath, **d3plot_kwargs) 

368 

369 # rewrite d3plot 

370 out_filepath = os.path.join(dirpath, "yay.d3plot") 

371 d3plot1.write_d3plot(out_filepath) 

372 

373 # read it in again and compare 

374 d3plot2 = D3plot(out_filepath, **d3plot_kwargs) 

375 hdr_diff, array_diff = d3plot1.compare(d3plot2) 

376 

377 err_msg = f"{d3plot_filepath}: {d3plot_kwargs}" 

378 self.assertDictEqual(hdr_diff, {}, err_msg) 

379 self.assertDictEqual(array_diff, {}, err_msg) 

380 

381 def test_write_new(self): 

382 

383 self.maxDiff = None 

384 

385 d3plot1 = D3plot() 

386 d3plot1.arrays[ArrayType.node_coordinates] = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0]]) 

387 d3plot1.arrays[ArrayType.element_shell_node_indexes] = np.array([[0, 2, 1, 1]]) 

388 d3plot1.arrays[ArrayType.element_shell_part_indexes] = np.array([0]) 

389 d3plot1.arrays[ArrayType.node_displacement] = np.array([[[0, 0, 0], [1, 0, 0], [0, 1, 0]]]) 

390 

391 with tempfile.TemporaryDirectory() as dirpath: 

392 filepath = os.path.join(dirpath, "yay.d3plot") 

393 

394 # single file 

395 d3plot1.write_d3plot(filepath) 

396 d3plot2 = D3plot(filepath) 

397 hdr_diff, array_diff = d3plot1.compare(d3plot2) 

398 array_diff = { 

399 name: reason 

400 for name, reason in array_diff.items() 

401 if "missing in original" not in reason 

402 } 

403 self.assertDictEqual(hdr_diff, {}) 

404 self.assertDictEqual(array_diff, {}) 

405 

406 # multiple files 

407 d3plot1.write_d3plot(filepath, single_file=False) 

408 d3plot2 = D3plot(filepath) 

409 hdr_diff, array_diff = d3plot1.compare(d3plot2) 

410 array_diff = { 

411 name: reason 

412 for name, reason in array_diff.items() 

413 if "missing in original" not in reason 

414 } 

415 self.assertDictEqual(hdr_diff, {}) 

416 self.assertDictEqual(array_diff, {}) 

417 self.assertTrue(os.path.isfile(filepath)) 

418 self.assertTrue(os.path.isfile(filepath + "01")) 

419 

420 def test_append_4_shell_hists_then_read_bug(self): 

421 

422 self.maxDiff = None 

423 

424 # we need some d3plot 

425 d3plot = D3plot() 

426 d3plot.arrays[ArrayType.node_coordinates] = np.array( 

427 [[0, 0, 0], [1, 0, 0], [0, 1, 0]], dtype=np.float32 

428 ) 

429 d3plot.arrays[ArrayType.element_shell_node_indexes] = np.array([[0, 2, 1, 1]]) 

430 d3plot.arrays[ArrayType.element_shell_part_indexes] = np.array([0]) 

431 d3plot.arrays[ArrayType.node_displacement] = np.array( 

432 [[[0, 0, 0], [1, 0, 0], [0, 1, 0]]], dtype=np.float32 

433 ) 

434 

435 # there was a bug occurring if more than 3 history vars 

436 # were added, these were written and read back in again 

437 n_history_vars = 4 

438 

439 with tempfile.TemporaryDirectory() as dirpath: 

440 filepath1 = os.path.join(dirpath, "original") 

441 d3plot.write_d3plot(filepath1) 

442 

443 # open it again to have a safe copy 

444 d3plot1 = D3plot(filepath1) 

445 n_timesteps, n_shells, n_layers = 1, d3plot1.header.n_shells, 3 

446 

447 d3plot1.arrays[ArrayType.element_shell_history_vars] = np.random.random( 

448 (n_timesteps, n_shells, n_layers, n_history_vars) 

449 ) 

450 

451 filepath2 = os.path.join(dirpath, "modified") 

452 d3plot1.write_d3plot(filepath2) 

453 

454 d3plot_modif = D3plot(filepath2) 

455 self.assertTrue(ArrayType.element_shell_internal_energy not in d3plot_modif.arrays) 

456 

457 def test_reading_selected_states(self): 

458 

459 # read all states 

460 filepath = "test/d3plot_solid_int/d3plot" 

461 

462 d3plot = D3plot(filepath) 

463 d3plot2 = D3plot(filepath, state_filter=np.arange(0, 22)) 

464 

465 hdr_diff, array_diff = d3plot.compare(d3plot2) 

466 

467 self.assertDictEqual(hdr_diff, {}) 

468 self.assertDictEqual(array_diff, {}) 

469 

470 # select first and last state 

471 d3plot = D3plot(filepath, state_filter={0, -1}) 

472 

473 node_id = 119 

474 disp_node_real = np.array( 

475 [[50.0, 70.0, 5.0], [47.50418, 70.0, -10.000001]], dtype=np.float32 

476 ) 

477 

478 node_index = d3plot.arrays[ArrayType.node_ids].tolist().index(node_id) 

479 node_disp = d3plot.arrays[ArrayType.node_displacement][:, node_index] 

480 

481 np.testing.assert_allclose(node_disp, disp_node_real, rtol=1e-4)