Utils¶
Utility functions for extracting data from HDF5 simulation files.
utils
¶
DDACS utilities for extracting simulation data.
The DDACS dataset contains deep drawing simulations with: - Material parameters: FC (friction), MAT (material), STHK (sheet thickness), BF (blank holder force) - Geometry types: R (rectangular), V (concave), X (convex) with radius parameter - Components: blank (workpiece), die, binder, punch (forming tools) - Operations: OP10 (forming), OP20 (springback analysis)
compute_von_mises(stress)
¶
Compute Von Mises equivalent stress from stress tensor in Voigt notation.
The Von Mises stress is a scalar value used to predict yielding of materials under complex loading conditions based on the distortion energy theory.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stress
|
ndarray
|
Stress tensor array in Voigt notation with shape (..., 6). Components are ordered as [σxx, σyy, σzz, σxy, σyz, σxz]. |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
np.ndarray: Von Mises stress values with shape (...). |
Examples:
>>> # Single stress state
>>> stress = np.array([100, 50, 0, 25, 0, 0]) # MPa
>>> vm = compute_von_mises(stress)
>>> print(f"Von Mises stress: {vm:.1f} MPa")
>>> # Batch of stress states
>>> stresses = np.random.randn(100, 6) * 100
>>> vm_batch = compute_von_mises(stresses)
>>> print(f"Max Von Mises: {vm_batch.max():.1f} MPa")
Note
Formula: σ_vm = √(0.5 * [(σxx-σyy)² + (σyy-σzz)² + (σzz-σxx)² + 6(σxy² + σyz² + σxz²)])
Source code in ddacs/utils.py
display_structure(h5_path, max_depth=None)
¶
Display the complete hierarchical structure of an HDF5 file in tree format.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
h5_path
|
str | Path
|
Path to the H5 file to analyze. |
required |
max_depth
|
int
|
Maximum depth to display (default: None for unlimited depth). Useful for limiting output when files have deep nesting. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
None |
None
|
Prints the structure directly to stdout. |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If the H5 file does not exist. |
Examples:
>>> display_structure('simulation_001.h5')
HDF5 Structure: simulation_001.h5
============================================================
OP10/ (Group)
blank/ (Group)
node_coordinates (Dataset: shape=(1024, 3), dtype=float64)
...
Note
Displays groups, datasets, and their attributes in a hierarchical tree format. Shows dataset shapes, data types, and any HDF5 attributes.
Source code in ddacs/utils.py
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 | |
extract_element_strain(h5_path, timestep=0, operation=10, integration_point=0)
¶
Extract effective plastic strain for shell elements.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
h5_path
|
str | Path
|
Path to the H5 simulation file. |
required |
timestep
|
int
|
Timestep index (default: 0). Use -1 for final state. |
0
|
operation
|
int
|
Operation index (default: 10). Use 10 for forming, 20 for cutting. |
10
|
integration_point
|
int
|
Through-thickness integration point (default: 0 for top). |
0
|
Returns:
| Type | Description |
|---|---|
ndarray
|
np.ndarray: Effective plastic strain array with shape (n_triangles,). Values are duplicated to match triangle mesh conversion. |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If the H5 file does not exist. |
KeyError
|
If strain data is not found in the file. |
Examples:
>>> strain = extract_element_strain('simulation_001.h5', timestep=-1)
>>> print(f"Max plastic strain: {strain.max():.3f}")
>>> # Find elements with high plastic deformation
>>> high_strain_mask = strain > 0.1
>>> print(f"Elements with >10% strain: {high_strain_mask.sum()}")
Note
Effective plastic strain is a scalar measure of accumulated plastic deformation. Values > 0 indicate permanent deformation has occurred.
Source code in ddacs/utils.py
extract_element_stress(h5_path, timestep=0, operation=10, integration_point=0)
¶
Extract Von Mises stress for shell elements.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
h5_path
|
str | Path
|
Path to the H5 simulation file. |
required |
timestep
|
int
|
Timestep index (default: 0). Use -1 for final state. |
0
|
operation
|
int
|
Operation index (default: 10). Use 10 for forming, 20 for cutting. |
10
|
integration_point
|
int
|
Through-thickness integration point (default: 0 for top). Shell elements typically have multiple integration points through the thickness (0=top, 1=middle, 2=bottom). |
0
|
Returns:
| Type | Description |
|---|---|
ndarray
|
np.ndarray: Von Mises stress array with shape (n_triangles,). Values are duplicated to match triangle mesh conversion. |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If the H5 file does not exist. |
KeyError
|
If stress data is not found in the file. |
Examples:
>>> stress = extract_element_stress('simulation_001.h5', timestep=-1)
>>> print(f"Max stress: {stress.max():.1f} MPa")
>>> # Compare top vs bottom surface stress
>>> stress_top = extract_element_stress('sim.h5', integration_point=0)
>>> stress_bot = extract_element_stress('sim.h5', integration_point=2)
>>> print(f"Stress difference: {(stress_top - stress_bot).mean():.1f} MPa")
Note
Stress is computed from the full stress tensor using Von Mises criterion. The result is scaled to match the triangle mesh from extract_mesh().
Source code in ddacs/utils.py
extract_element_thickness(h5_path, timestep=0, operation=10)
¶
Extract element thickness data from H5 simulation file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
h5_path
|
str | Path
|
Path to the H5 simulation file. |
required |
timestep
|
int
|
Timestep index (default: 0). Use 0 for initial state, -1 for final state. |
0
|
operation
|
int
|
Operation index (default: 10). Use 10 for deep drawing process and 20 for cutting process. |
10
|
Returns:
| Type | Description |
|---|---|
ndarray
|
np.ndarray: Element thickness array with shape (n_elements,). Each value represents the thickness of one element. |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If the H5 file does not exist. |
KeyError
|
If the specified component, operation or thickness data is not found. |
Examples:
>>> thickness = extract_element_thickness('simulation_001.h5', timestep=0)
>>> print(f"Initial thickness range: {thickness.min():.3f} - {thickness.max():.3f}")
>>> # Compare initial vs final thickness
>>> t0 = extract_element_thickness('simulation_001.h5', timestep=0)
>>> t_final = extract_element_thickness('simulation_001.h5', timestep=-1)
>>> thinning = (t0 - t_final) / t0 * 100
>>> print(f"Maximum thinning: {thinning.max():.1f}%")
Note
Thickness data shows how the material thickness changes during forming. This is particularly useful for analyzing thinning in deep drawing processes. Can be used with matplotlib's color mapping on mesh visualizations.
Source code in ddacs/utils.py
extract_mesh(h5_path, component, timestep=0, operation=10)
¶
Extract mesh data for matplotlib visualization.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
h5_path
|
str | Path
|
Path to the H5 simulation file. |
required |
component
|
str
|
Component name ('binder', 'blank', 'die', 'punch'). |
required |
timestep
|
int
|
Timestep index (default: 0). Use 0 for initial state, -1 for final state. |
0
|
operation
|
int
|
Operation index (default: 10). Use 10 for deep drawing process and 20 for cutting process. |
10
|
Returns:
| Type | Description |
|---|---|
tuple[ndarray, ndarray]
|
Tuple[np.ndarray, np.ndarray]: A tuple containing: - vertices: Node coordinates array with shape (n_nodes, 3) - triangles: Triangle connectivity array with shape (n_faces, 3) Each row contains indices of triangle vertices |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If the H5 file does not exist. |
KeyError
|
If the specified component or operation is not found in the file. |
Examples:
>>> vertices, triangles = extract_mesh('simulation_001.h5', 'blank')
>>> print(f"Mesh has {len(vertices)} vertices and {len(triangles)} triangles")
>>> # Extract final deformed mesh
>>> vertices, triangles = extract_mesh('simulation_001.h5', 'blank', timestep=-1)
Note
Quad elements are automatically converted to triangles by splitting each quad into two triangles.
Source code in ddacs/utils.py
extract_point_cloud(h5_path, component, timestep=0, operation=10)
¶
Extract point cloud coordinates from H5 simulation file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
h5_path
|
str | Path
|
Path to the H5 simulation file. |
required |
component
|
str
|
Component name ('binder', 'blank', 'die', 'punch'). |
required |
timestep
|
int
|
Timestep index (default: 0). Use 0 for initial state, -1 for final state. Tools may have different timestep structures than the workpiece. |
0
|
operation
|
int
|
Operation index (default: 10). Use 10 for deep drawing process and 20 for cutting process. |
10
|
Returns:
| Type | Description |
|---|---|
ndarray
|
np.ndarray: Node coordinates array with shape (n_nodes, 3). Returns the actual node positions at the specified timestep. |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If the H5 file does not exist. |
KeyError
|
If the specified component or operation is not found in the file. |
Examples:
>>> coords = extract_point_cloud('simulation_001.h5', 'blank', timestep=0)
>>> print(f"Initial blank shape: {coords.shape}")
>>> final_coords = extract_point_cloud('simulation_001.h5', 'blank', timestep=-1)
>>> print(f"Final deformed shape: {final_coords.shape}")
>>> cutting_coords = extract_point_cloud('simulation_001.h5', 'blank', timestep=0, operation=20)
>>> print(f"Cutting shape: {cutting_coords.shape}")
Note
The function reads from node_displacement which contains actual node coordinates at each timestep. Timestep structure differs by component: - blank: 4 timesteps (0: initial, 1-2: forming, 3: springback after tool removal) - tools (die, punch, binder): 3 timesteps (0: initial, 1-2: forming positions) Tools are removed at the final blank timestep, so timestep=3 or timestep=-1 only exists for the blank component. The cutting operation (operation=20) only contains the blank component.
Source code in ddacs/utils.py
extract_point_springback(h5_path, operation=10)
¶
Extract springback data for the blank component.
Springback is calculated as the difference between the last timestep and the second-to-last timestep, representing the material's elastic recovery after tool removal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
h5_path
|
str | Path
|
Path to the H5 simulation file. |
required |
operation
|
int
|
Operation index (default: 10). Use 10 for deep drawing process and 20 for cutting process. |
10
|
Returns:
| Type | Description |
|---|---|
tuple[ndarray, ndarray]
|
Tuple[np.ndarray, np.ndarray]: A tuple containing: - final_coords: Node coordinates after springback with shape (n_nodes, 3) - displacement_vectors: Springback displacement vectors with shape (n_nodes, 3) Each row contains [x, y, z] displacement due to springback |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If the H5 file does not exist. |
KeyError
|
If the specified operation or blank component is not found. |
Examples:
>>> final_coords, displacement = extract_point_springback('simulation_001.h5')
>>> magnitude = np.linalg.norm(displacement, axis=1)
>>>
>>> # Visualize final shape colored by springback magnitude
>>> plt.scatter(final_coords[:, 0], final_coords[:, 1], c=magnitude)
>>> plt.colorbar(label='Springback magnitude [mm]')
>>>
>>> # Show springback vectors
>>> plt.quiver(final_coords[:, 0], final_coords[:, 1],
... displacement[:, 0], displacement[:, 1])
Note
- For OP10 (forming): Compares timestep -1 (final springback) vs timestep -2 (max forming)
- For OP20 (cutting): Compares timestep -1 (final) vs timestep 0 (initial cutting state)
- Only works for the blank component as tools are removed before springback occurs
Source code in ddacs/utils.py
non_degenerate_mask(triangles)
¶
Return boolean mask identifying non-degenerate triangles.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
triangles
|
ndarray
|
Array of triangle vertex indices where each row represents one triangle with three vertex indices. |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
np.ndarray: Boolean mask where True indicates a valid (non-degenerate) triangle |
ndarray
|
and False indicates a degenerate triangle with duplicate vertices. |
Examples:
>>> triangles = np.array([[0, 1, 2], # Valid triangle
... [3, 3, 4], # Degenerate (vertices 3,3)
... [5, 6, 7], # Valid triangle
... [8, 9, 8]]) # Degenerate (vertices 8,8)
>>> mask = non_degenerate_mask(triangles)
>>> mask
array([ True, False, True, False])
>>> valid_triangles = triangles[mask]
>>> valid_triangles
array([[0, 1, 2],
[5, 6, 7]])
Note: The function only checks for vertex uniqueness, not geometric validity (e.g., collinear vertices that form zero-area triangles).