2. Enumerate and Classify Model Entities by Type
Why enumerate before you clean
Cleanup work in HyperMesh is destructive by nature: deleting a component removes its elements, deleting a property orphans the components that referenced it, and deleting a material can silently break a property's card image. Before any deletion script runs, you need a census of the model — how many entities of each type exist, what they are named, and which ones are candidates for removal. This case builds a single Python script that walks the current HyperMesh session, enumerates every entity type through the HyperMesh Python API, and emits a classification summary you can use as the input to a cleanup plan.
The script is deliberately read-only. It queries, counts, and reports; it never modifies the model. That makes it safe to run on a production assembly at any time, and it gives you a repeatable baseline you can diff against after a cleanup pass to confirm what actually changed.
Entity types and the API surface
HyperMesh organizes model data into a small number of top-level collectors and a large number of element and node records. The Python API exposes each type through a dedicated module, and the query pattern is consistent: you ask a module for its collection, then iterate. The table below lists the types this script covers, the module that owns them, and the collector query used to fetch them.
| Entity type | API module | Query used | Cleanup relevance |
|---|---|---|---|
| Components | hm.Components |
hm.Components.getall() |
Empty or duplicate part containers |
| Properties | hm.Properties |
hm.Properties.getall() |
Unreferenced property cards |
| Materials | hm.Materials |
hm.Materials.getall() |
Materials with no property reference |
| Elements | hm.Elements |
hm.Elements.getall() |
Count per component, orphan elements |
| Nodes | hm.Nodes |
hm.Nodes.getall() |
Free nodes not attached to elements |
| Loads | hm.Loads |
hm.Loads.getall() |
Stale load collectors from prior runs |
| Load steps | hm.LoadSteps |
hm.LoadSteps.getall() |
Empty or duplicated steps |
| Sets | hm.Sets |
hm.Sets.getall() |
Orphaned entity sets |
Two practical notes on the API. First, getall() returns a collection object, not a Python list; call len() on it for a count and iterate it directly for names. Second, entity names are not guaranteed unique and may be empty strings, so the summary must key on entity ID where a stable identifier is needed and treat the name as descriptive metadata only.
The enumeration script
The script below is self-contained: it imports the HyperMesh API, defines a registry of entity types, walks each one, and prints a classification summary. It runs inside the HyperMesh Python console or as a script executed from the HyperMesh command line, and it depends on nothing outside the standard HyperMesh installation.
import hm
# Registry: (label, module, collector query)
ENTITY_TYPES = [
("components", hm.Components, hm.Components.getall),
("properties", hm.Properties, hm.Properties.getall),
("materials", hm.Materials, hm.Materials.getall),
("elements", hm.Elements, hm.Elements.getall),
("nodes", hm.Nodes, hm.Nodes.getall),
("loads", hm.Loads, hm.Loads.getall),
("loadsteps", hm.LoadSteps, hm.LoadSteps.getall),
("sets", hm.Sets, hm.Sets.getall),
]
def classify_entities():
"""Enumerate every entity type and return a classification summary."""
summary = {}
for label, module, query in ENTITY_TYPES:
try:
collection = query()
except Exception as exc:
summary[label] = {"count": 0, "error": str(exc), "names": []}
continue
names = []
for entity in collection:
try:
names.append(entity.name or "")
except Exception:
names.append("")
summary[label] = {
"count": len(collection),
"error": None,
"names": names,
}
return summary
def print_summary(summary):
print("=" * 56)
print("HyperMesh entity classification summary")
print("=" * 56)
total = 0
for label, info in summary.items():
total += info["count"]
status = "OK" if info["error"] is None else "ERROR: " + info["error"]
print("{:<12} {:>8} {}".format(label, info["count"], status))
print("-" * 56)
print("{:<12} {:>8}".format("TOTAL", total))
print("=" * 56)
if __name__ == "__main__":
result = classify_entities()
print_summary(result)
Run it from the HyperMesh Python console with exec(open("classify_entities.py").read()), or load the file through the script runner. The output is a fixed-width table with one row per entity type, a count column, and a status column that reports any query failure without aborting the whole run. The try/except around each query is intentional: a model with no load steps, for example, may raise rather than return an empty collection depending on the API version, and you want the remaining types to still be counted.
Reading the summary as a cleanup plan
The counts alone are not a cleanup decision, but they tell you where to look. A model with 240 components and 12 properties is almost certainly carrying duplicate or empty part containers. A model with 0 loads but 6 load steps has stale steps to remove. A model where element count is far below node count suggests free nodes left behind by a failed import. The SVG below shows how the raw counts map onto the three cleanup signals the script is designed to surface.
The three signals are not exhaustive, but they cover the most common cleanup entry points and they are all derivable from the counts the script already produces. The point of the classification summary is to turn a vague instruction like "clean up the model" into a ranked list of specific queries to run next.
Verification and failure modes
To confirm the script is reading the live model rather than a cached state, create a throwaway component in the HyperMesh GUI, re-run the script, and check that the component count increments by exactly one. Delete it and confirm the count returns. If the count does not change, the script is holding a stale collection reference — re-query inside the loop rather than caching the collection at module load.
Two failure modes are worth anticipating. If a query raises because the corresponding collector type is absent from the model, the try/except records the error and continues; check the status column rather than assuming a zero count means "none present." If entity names contain non-ASCII characters, the console may raise an encoding error on print; write the summary to a UTF-8 file instead of stdout when working with imported models from non-English CAD sources.
Reusable output for the cleanup plan
The script returns a dictionary keyed by entity type, each entry holding a count, an error field, and a list of names. That structure is the contract the rest of the cleanup toolchain can rely on: later scripts can import classify_entities(), compare counts against thresholds, and decide which entity types to hand to a deletion routine. Keeping the enumeration read-only and the output structured means the census can be re-run at any point in the cleanup pipeline without side effects, which is exactly what you want from the first stage of an automation workflow.