This document explains how to perform and parallelize boolean operations using OpenCascade, specifically focusing on generating conformal volumes by embedding a surface within a volume. The goal is to ensure the mesh is connected at the interface, which is particularly useful for Fluid-Structure Interaction (FSI) modeling.
Boolean operations in OpenCascade can be used to combine or manipulate shapes. This document covers:
- Importing STEP files.
- Performing a boolean fuse operation.
- Ensuring the mesh is connected using
BOPAlgo_MakeConnected
. - Parallelizing the operations to improve performance.
- Exporting the resulting shape.
- Python
- OpenCascade (OCC) library
Ensure you have OpenCascade installed in your Python environment. You can install it via pip if it's available or follow the specific installation instructions for your operating system.
pip install opencascade-python
Start by importing the necessary libraries from OpenCascade.
import os
import time
from OCC.Core.STEPControl import STEPControl_Reader
from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Fuse
from OCC.Core.BOPAlgo import BOPAlgo_MakeConnected
from OCC.Core.BRepTools import breptools
Define a function to import STEP files and return the shape.
def import_step_file(filename):
"""Import a STEP file and return the shape."""
reader = STEPControl_Reader()
status = reader.ReadFile(filename)
if status != 1:
raise ValueError(f"Error reading STEP file: {filename}")
reader.TransferRoot()
shape = reader.Shape()
return shape
Define a function to export shapes to BREP files.
def export_to_brep(shape, filename):
"""Export a TopoDS_Shape to a BREP file."""
breptools.Write(shape, filename)
The main function performs the boolean fuse operation, ensures the resulting shape is connected, and measures execution time.
def main(num_threads):
# Set the number of OpenMP threads
os.environ["OMP_NUM_THREADS"] = str(num_threads)
# Import the STEP files
surface_shape = import_step_file("last_dura.step")
volume_shape = import_step_file("last_diff.step")
# Perform the fuse operation
fuse_algo = BRepAlgoAPI_Fuse(volume_shape, surface_shape)
fuse_algo.Build()
# Use BOPAlgo_MakeConnected to ensure the mesh is connected
mk_connected = BOPAlgo_MakeConnected()
mk_connected.AddArgument(fuse_algo.Shape())
mk_connected.SetRunParallel(True)
# Measure the execution time
start_time = time.time()
mk_connected.Perform()
end_time = time.time()
connected_shape = mk_connected.Shape()
# Export the connected shape to a BREP file
brep_filename = f"connected_shape_{num_threads}.brep"
export_to_brep(connected_shape, brep_filename)
print(f"Connected shape exported to {brep_filename}")
print(f"Total execution time with {num_threads} threads: {end_time - start_time:.9f} seconds")
Save the script to a file (e.g., boolean_operation.py
) and execute it from the command line with the desired number of threads.
python boolean_operation.py <num_threads>
Replace <num_threads>
with the number of threads you want to use. For example:
python boolean_operation.py 4
Ensure that the STEP files "last_dura.step" and "last_diff.step" are in the same directory as the script or provide the full path to these files in the import_step_file
function calls. This will import the STEP files, perform the fuse operation, ensure the mesh is connected, and export the resulting shape to a BREP file, printing the execution time.
OpenCascade provides several boolean operations that can be used to manipulate shapes:
- Fuse (Union): Combines two shapes into one.
- Cut (Difference): Subtracts one shape from another.
- Common (Intersection): Creates a shape from the intersection of two shapes.
Example:
from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Cut, BRepAlgoAPI_Common
# Perform cut operation
cut_algo = BRepAlgoAPI_Cut(shape1, shape2)
cut_algo.Build()
cut_shape = cut_algo.Shape()
# Perform common operation
common_algo = BRepAlgoAPI_Common(shape1, shape2)
common_algo.Build()
common_shape = common_algo.Shape()
The BOPAlgo_MakeConnected
class ensures that the resulting shapes have a conformal mesh, which is essential for FSI modeling where the interface between domains must be neatly connected.
Here is the full script:
import os
import time
from OCC.Core.STEPControl import STEPControl_Reader
from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Fuse
from OCC.Core.BOPAlgo import BOPAlgo_MakeConnected
from OCC.Core.BRepTools import breptools
def import_step_file(filename):
"""Import a STEP file and return the shape."""
reader = STEPControl_Reader()
status = reader.ReadFile(filename)
if status != 1:
raise ValueError(f"Error reading STEP file: {filename}")
reader.TransferRoot()
shape = reader.Shape()
return shape
def export_to_brep(shape, filename):
"""Export a TopoDS_Shape to a BREP file."""
breptools.Write(shape, filename)
def main(num_threads):
# Set the number of OpenMP threads
os.environ["OMP_NUM_THREADS"] = str(num_threads)
# Import the STEP files
surface_shape = import_step_file("last_dura.step")
volume_shape = import_step_file("last_diff.step")
# Perform the fuse operation
fuse_algo = BRepAlgoAPI_Fuse(volume_shape, surface_shape)
fuse_algo.Build()
# Use BOPAlgo_MakeConnected to ensure the mesh is connected
mk_connected = BOPAlgo_MakeConnected()
mk_connected.AddArgument(fuse_algo.Shape())
mk_connected.SetRunParallel(True)
# Measure the execution time
start_time = time.time()
mk_connected.Perform()
end_time = time.time()
connected_shape = mk_connected.Shape()
# Export the connected shape to a BREP file
brep_filename = f"connected_shape_{num_threads}.brep"
export_to_brep(connected_shape, brep_filename)
print(f"Connected shape exported to {brep_filename}")
print(f"Total execution time with {num_threads} threads: {end_time - start_time:.9f} seconds")
if __name__ == "__main__":
import sys
if len(sys.argv) < 2:
print("Usage: python script_name.py <num_threads>")
sys.exit(1)
num_threads = int(sys.argv[1])
main(num_threads)
This document should help you understand and implement parallelized boolean fuse operations using OpenCascade, ensuring the resulting shapes have a conformal mesh suitable for FSI modeling.