This document provides a comprehensive overview of the Finite Element Analysis (FEA) module structure and functionality within the VOLCO repository. It serves as a reference for large language models to understand the FEA module without requiring all files to be uploaded as context.
The FEA module extends VOLCO's capabilities by providing structural analysis functionality for voxel models generated by VOLCO simulations. It enables users to:
- Convert voxel matrices to finite element meshes
- Apply boundary conditions to the mesh
- Solve linear static structural problems
- Visualize results including displacements and stresses using Plotly
- Save and load analysis results in various formats
The module is designed to work seamlessly with VOLCO's voxel-based output, allowing for direct structural analysis of 3D printed parts simulated by VOLCO.
app/postprocessing/fea/
├── __init__.py # Module entry point
├── core.py # Main analysis functionality
├── mesh.py # Mesh generation from voxel matrices
├── boundary.py # Boundary condition application
├── solver.py # Linear static FEA solver
├── viz.py # Visualization of results
└── io.py # Input/output functionality for saving/loading results
- Exposes the main functions:
analyze_voxel_matrixandload_fea_results - Provides a clean interface for users to access the module's functionality
analyze_voxel_matrix(): Main entry point for FEA analysisload_fea_results(): Function to load previously saved results- Orchestrates the entire analysis process from mesh generation to results visualization
generate_mesh(): Converts voxel matrix to hexahedral elementscheck_continuity(): Ensures the voxel model represents a single continuous bodyextract_surface_elements(): Identifies elements on the model surfaceget_top_surface_nodes(),get_bottom_surface_nodes(): Helper functions for boundary condition application
Surface: Enumeration for standard surface identifiers (PLUS_X, MINUS_X, PLUS_Y, MINUS_Y, PLUS_Z, MINUS_Z)apply_boundary_conditions(): Applies boundary conditions using the enhanced systemidentify_surface_nodes(): Identifies nodes on a specified surfaceselect_nodes_by_predicate(),select_nodes_in_box(),select_nodes_on_plane(): Functional utilities for expert users
solve_static_problem(): Main solver function for linear static analysisassemble_system(): Assembles global stiffness matrix and force vectorcalculate_element_stiffness(): Computes element stiffness matricesshape_functions(): Calculates shape functions for hexahedral elementsapply_boundary_conditions(): Modifies system equations to account for boundary conditionssolve_system(): Solves the system of equationscalculate_stresses_and_strains(): Post-processes results to obtain stresses and strains
visualize_fea(): Unified visualization function using Plotly with optimized mesh renderingexport_visualization(): Saves visualizations to HTML filesvisualize_voxel_matrix(): Visualizes the original voxel matrix
save_results(): Saves analysis results to file in various formatsload_results(): Loads analysis results from file- Support for multiple file formats: pickle, JSON, and HDF5 (if available)
analyze_voxel_matrix()→ Entry point for analysischeck_continuity()→ Ensures model is a single bodygenerate_mesh()→ Converts voxels to hexahedral elements- Creates nodes at voxel corners
- Defines element connectivity
- Maps physical coordinates based on voxel size
apply_boundary_conditions()→ Applies boundary conditions using the enhanced system- Simple Mode: Uses Surface enumerations (PLUS_X, MINUS_X, etc.) with "fix" keyword or vector constraints
- Expert Mode: Uses custom functions for advanced boundary conditions
identify_surface_nodes()→ Identifies nodes on specified surfaces- Creates dictionary mapping node indices to prescribed displacements
solve_static_problem()→ Main solver functionassemble_system()→ Creates global stiffness matrix and force vectorapply_boundary_conditions()→ Modifies system for boundary conditionssolve_system()→ Solves the linear system of equationscalculate_stresses_and_strains()→ Post-processes results
visualize_fea()→ Creates Plotly visualization with optimized mesh rendering- Uses the "volco mesh visualization method" that only renders visible faces
- Supports showing both original and deformed meshes simultaneously
- Deforms mesh based on calculated displacements
- Colors elements based on stress or displacement values
- Creates interactive 3D visualization with colorbar
save_results()→ Saves results to file- Supports pickle, JSON, and HDF5 formats
- Includes metadata about the analysis
load_results()→ Loads results from file- Automatically detects file format
- Reconstructs numpy arrays from serialized data
young_modulus: Young's modulus in MPa (default: 2000.0 for typical PLA)poisson_ratio: Poisson's ratio (default: 0.3 for typical PLA)
constraints: Dictionary mapping surface identifiers or custom functions to constraints- Simple Mode:
{Surface.MINUS_Z: "fix", Surface.PLUS_Z: [None, None, -0.1, None, None, None]} - Expert Mode:
{"custom": custom_function}
- Simple Mode:
visualization: Whether to generate visualization (default: True)result_type: Type of result to visualize ('displacement', 'von_mises')scale_factor: Factor to scale displacements for visualization (default: 1.0)show_undeformed: Whether to show the original undeformed mesh (default: False)original_opacity: Opacity of the original mesh when shown (default: 0.3)
save_results: Whether to save results to a file (default: False)save_path: Path to save results (default: 'Results_volco/fea/results')save_format: Format to save results ('pickle', 'json', or 'hdf5') (default: 'pickle')include_visualization: Whether to include visualization in saved file (default: False)
from volco import run_simulation
from volco_fea import analyze_voxel_matrix, Surface, visualize_fea, export_visualizationThis simplified import pattern allows users to import all FEA functionality from a single location, making the code cleaner and more intuitive.
from volco import run_simulation
from volco_fea import analyze_voxel_matrix, Surface
# Run VOLCO simulation
output = run_simulation(
gcode_path='examples/gcode_example.gcode',
printer_config_path='examples/printer_settings.json',
sim_config_path='examples/simulation_settings.json'
)
# Get cropped voxel matrix and voxel size
voxel_matrix = output.cropped_voxel_space
voxel_size = output._simulation.voxel_size
# Define boundary conditions using Simple Mode
from app.postprocessing.fea.boundary import Surface
# Calculate displacement as 1% of model height
model_height = voxel_matrix.shape[2] * voxel_size
displacement_magnitude = model_height * 0.01
boundary_conditions = {
'constraints': {
Surface.MINUS_Z: "fix", # Fix bottom surface
Surface.PLUS_Z: [None, None, -displacement_magnitude, None, None, None] # Apply compression on top
}
}
# Run FEA analysis
results = analyze_voxel_matrix(
voxel_matrix=voxel_matrix,
voxel_size=voxel_size,
boundary_conditions=boundary_conditions,
visualization=True,
result_type='von_mises',
scale_factor=10.0 # Exaggerate deformation for visualization
)
# Access results
print(f"Maximum displacement: {results['max_displacement']} mm")
print(f"Maximum von Mises stress: {results['max_von_mises']} MPa")
# Save visualization
export_visualization(results['visualization'], "Results_volco/fea/von_mises.html")# Save results
# Define boundary conditions
boundary_conditions = {
'constraints': {
Surface.MINUS_Z: "fix", # Fix bottom surface
Surface.PLUS_Z: [None, None, -displacement_magnitude, None, None, None] # Apply compression on top
}
}
results = analyze_voxel_matrix(
voxel_matrix=voxel_matrix,
voxel_size=voxel_size,
boundary_conditions=boundary_conditions,
save_results=True,
save_path='Results_volco/fea/my_analysis',
save_format='pickle'
)
# Load results
from volco_fea import load_fea_results, visualize_fea, export_visualization
loaded_results = load_fea_results('Results_volco/fea/my_analysis.pkl')
# Create visualization from loaded results
viz = visualize_fea(
nodes=loaded_results['nodes'],
elements=loaded_results['elements'],
displacements=loaded_results['displacements'],
von_mises=loaded_results['von_mises'],
result_type='von_mises',
scale_factor=1.0,
show_undeformed=True # Show both original and deformed meshes
)
# Export the visualization to an HTML file
export_visualization(viz, "Results_volco/fea/loaded_von_mises_with_undeformed.html")# Define custom material properties for ABS
material_properties = {
'young_modulus': 2300.0, # MPa (typical for ABS)
'poisson_ratio': 0.35 # Typical for ABS
}
# Define boundary conditions
boundary_conditions = {
'constraints': {
Surface.MINUS_Z: "fix", # Fix bottom surface
Surface.PLUS_Z: [None, None, -displacement_magnitude, None, None, None] # Apply compression on top
}
}
results = analyze_voxel_matrix(
voxel_matrix=voxel_matrix,
voxel_size=voxel_size,
material_properties=material_properties,
boundary_conditions=boundary_conditions
)from volco_fea import Surface
# Define boundary conditions using Simple Mode
boundary_conditions = {
'constraints': {
Surface.MINUS_Z: "fix", # Fix bottom surface
Surface.PLUS_Z: [None, None, -0.1, None, None, None] # Apply 0.1mm compression on top
}
}
results = analyze_voxel_matrix(
voxel_matrix=voxel_matrix,
voxel_size=voxel_size,
boundary_conditions=boundary_conditions
)# Define custom boundary conditions using expert mode
def custom_constraint_function(nodes, elements):
# Get model dimensions directly
z_coords = nodes[:, 2]
min_z = np.min(z_coords)
max_z = np.max(z_coords)
# Calculate model height
model_height = max_z - min_z
# Calculate displacement as 1% of model height
displacement_magnitude = model_height * 0.01
return {
# Fix nodes on the bottom surface
i: [0, 0, 0, 0, 0, 0] for i in range(len(nodes))
if abs(nodes[i, 2] - min_z) < 1e-6
} | {
# Apply displacement to nodes on the top surface
i: [None, None, -displacement_magnitude, None, None, None] for i in range(len(nodes))
if abs(nodes[i, 2] - max_z) < 1e-6
}
boundary_conditions = {
'constraints': {
"custom": custom_constraint_function
}
}
results = analyze_voxel_matrix(
voxel_matrix=voxel_matrix,
voxel_size=voxel_size,
boundary_conditions=boundary_conditions
)- Voxel to Hexahedral Conversion: Each material voxel is converted to a hexahedral element with 8 nodes
- Node Sharing: Nodes are shared between adjacent elements to ensure mesh continuity
- Continuity Checking: Connected component labeling is used to ensure the model is a single continuous body
- Direct Stiffness Method: Assembly of element stiffness matrices into global stiffness matrix
- Gaussian Quadrature: Numerical integration for element stiffness calculation
- Shape Functions: Trilinear shape functions for hexahedral elements
- Sparse Matrix Solver: Efficient solution of large sparse linear systems
- Strain-Displacement Relation: B-matrix maps nodal displacements to strains
- Stress-Strain Relation: D-matrix (material matrix) maps strains to stresses
- von Mises Stress: Calculation of equivalent stress for failure prediction
volco_fea.py→app/postprocessing/fea/core.py,app/postprocessing/fea/viz.py,app/postprocessing/fea/boundary.py,app/postprocessing/fea/io.py(simplified import interface)app/postprocessing/fea/__init__.py→app/postprocessing/fea/core.pyapp/postprocessing/fea/core.py→app/postprocessing/fea/mesh.py,app/postprocessing/fea/solver.py,app/postprocessing/fea/boundary.py,app/postprocessing/fea/viz.py,app/postprocessing/fea/io.pyapp/postprocessing/fea/mesh.py→scipy.ndimage(for connected component labeling)app/postprocessing/fea/solver.py→scipy.sparse,scipy.sparse.linalg(for sparse matrix operations)app/postprocessing/fea/viz.py→plotlyapp/postprocessing/fea/io.py→pickle,json,h5py(optional)
- Modify
solver.pyto include new material behavior - Update the material matrix calculation in
calculate_element_stiffness() - Add new material parameters to the
material_propertiesdictionary
- Add new surface identifiers to the
Surfaceenumeration inboundary.py - Extend the
apply_boundary_conditions()function to handle new constraint types - Add new functional utilities for expert users
- Update
calculate_stresses_and_strains()insolver.pyto compute additional results - Modify the
resultsdictionary inanalyze_voxel_matrix()to include the new results - Update visualization functions to support the new result type
- Add new visualization features to the unified
visualize_fea()function inviz.py - Add any necessary parameters to the visualization methods
- Mesh Size: The number of elements grows cubically with model resolution, affecting memory usage and computation time
- Sparse Matrix Operations: Efficient sparse matrix storage and solvers are used to handle large models
- Visualization Memory Usage: Rendering large models can be memory-intensive, especially with Plotly
- Optimized Mesh Rendering: The "volco mesh visualization method" significantly improves performance by only rendering visible faces
- File Format Selection: HDF5 is more efficient for large datasets compared to pickle or JSON
- Continuity Checking: Connected component labeling can be memory-intensive for large voxel matrices
- Parallelization: The current implementation is single-threaded; parallelization could improve performance for large models