17754fd70a40418c9c44062ca33b07aa

CAD Similarity Search Using HOOPS Embeddings

This notebook demonstrates how to query a pre-built FAISS index with a CAD file and retrieve the most geometrically similar parts from a large indexed dataset.

Prerequisites: A FAISS index built with `demo_HOOPS_Embeddings_indexing.ipynb <./demo_HOOPS_Embeddings_indexing.ipynb>`__.

Workflow

  1. Configure paths to the model checkpoint and FAISS index.

  2. Register the model and load the index into CADSearch.

  3. Embed a query CAD file and search for similar parts.

[1]:
import hoops_ai
import os
import sys

license_key = os.environ.get("HOOPS_AI_LICENSE")
if not license_key:
    sys.exit("HOOPS_AI_LICENSE environment variable is required.")

hoops_ai.set_license(license_key, validate=True)
------------------------------------------------------------
HOOPS AI
------------------------------------------------------------
  Platform      : Windows 11
  Architecture  : AMD64
  Python        : 3.12.10
------------------------------------------------------------
  Core          : hoops-ai             1.1.0  (build: ed23c844 2026-06-12T14:14:13Z)
  CAD Access    : hoops-exchange       26.2.0  (build: 1e11169 2026-06-12T10:38:16Z)
  Conversion    : hoops-converter      26.1.1  (build: 00dc9f6 2026-06-12T10:22:46Z)
  Insights      : hoops-web-viewer     26.1.1  (build: d30058f 2026-06-12T10:22:25Z)
------------------------------------------------------------
======================================================================
[OK] HOOPS AI License: Valid
======================================================================

1. Configure paths

Set the path to the pre-trained model checkpoint and the FAISS index. Both live under packages/ — one level above this notebook.

[2]:
from hoops_ai.ml.embeddings import HOOPSEmbeddings, Embedding, EmbeddingBatch
import pathlib

packages_dir = pathlib.Path.cwd().parent.joinpath("packages")

pretrained_model = packages_dir.joinpath("trained_ml_models", "ts3d_2M_hoops_embeddings_SIGNAL-preview.ckpt")

Pre-built TMCAD index

A pre-indexed FAISS store for the TMCAD dataset is available for download at https://transfer.techsoft3d.com/link/eiZk3koBNP4C0m6gQzRcXj ask the password for downloading to your Tech Soft 3D contact person, or you can build your own with `demo_HOOPS_Embeddings_indexing.ipynb <./demo_HOOPS_Embeddings_indexing.ipynb>`__.

Place the downloaded folder contents under packages/vectorstores/tmcad/.

[3]:
indexed_database = packages_dir.joinpath("vectorstores","tmcad","TMCAD_SIGNAL.faiss")

if not indexed_database.exists():
    sys.exit("TMCAD_SIGNAL.faiss file is required. See section Indexed database with TMCAD dataset")

2. Register the model

The pre-trained SIGNAL model is used here. To use a custom model trained on your own data, replace pretrained_model with the path to your checkpoint (see `demo_HOOPS_EMBEDDINGS_training.ipynb <./demo_HOOPS_EMBEDDINGS_training.ipynb>`__).

[4]:
# HOOPS AI release 1.1
HOOPSEmbeddings.register_model(
    model_name="HOOPS Embeddings SIGNAL preview",
    checkpoint_path=str(pretrained_model)
)

print(HOOPSEmbeddings.list_available_models())
['HOOPS Embeddings SIGNAL preview']
[5]:
embedder = HOOPSEmbeddings(model="HOOPS Embeddings SIGNAL preview")

print(f"Using model: {embedder.model_name} with dimension: {embedder.embedding_dim}")
Successfully loaded model from checkpoint: c:\Users\LuisSalazar.LY-LS-LEGION\Documents\repos\HOOPS-AI-tutorials\packages\trained_ml_models\ts3d_2M_hoops_embeddings_SIGNAL-preview.ckpt
Using model: HOOPS Embeddings SIGNAL preview with dimension: 2048
c:\Users\LuisSalazar.LY-LS-LEGION\Documents\hoops-ai-packages-test\.venv\Lib\site-packages\pytorch_lightning\utilities\parsing.py:136: pytorch_lightning save_hyperparameters: frame introspection failed. Nuitka-compiled frames have empty locals, which breaks PL's collect_init_args. Pass an explicit dict to save_hyperparameters() for correct hparams under Nuitka.

3. Load the FAISS index

Deserialize the index into a CADSearch instance. Once loaded, all similarity queries run entirely in memory — no re-encoding needed.

[6]:
from hoops_ai.ml import CADSearch

loaded_searcher = CADSearch(shape_model=embedder)

embeddingBatch = loaded_searcher.load_shape_index(path=str(indexed_database))

print(f"Source {embeddingBatch.model}")
print(f"Loaded {len(embeddingBatch.ids)} part embeddings (dim={embeddingBatch.values.shape[1]}).")

Source CUSTOM:HOOPS Embeddings SIGNAL preview
Loaded 39736 part embeddings (dim=2048).
[ ]:

6cdcafacf58544bebae8f037862432a4

[7]:
from hoops_ai.insights import DatasetViewer

ds_viewer = DatasetViewer([], [], [], reference_dir=packages_dir.joinpath("vectorstores","tmcad","images_tmcad"))

Production pattern and performance

What takes time — and what doesn’t

The timing output above reveals an important asymmetry:

  • B-rep encoding is the bottleneck. Converting a CAD file into the tensor representation the model expects (face types, edge connectivity, surface normals, …) involves parsing the boundary representation and running the HOOPS Exchange conversion pipeline. This is the only step that touches the CAD file.

  • Vector search is near-instant. Once both the query and the indexed parts are in embedding space, finding the top-K nearest neighbors in a 38 K-part FAISS index takes a few milliseconds regardless of index size (FAISS uses approximate nearest- neighbor algorithms that scale sub-linearly).

Further reading

[ ]: