4. Detect and List Empty Components

Why empty components accumulate

In a HyperMesh model that has passed through several rounds of geometry cleanup, remeshing, and part consolidation, components frequently survive their contents. A component is a container: it holds elements, geometry (surfaces, solids, lines), and references to properties and materials. When you delete elements or geometry during cleanup, the component itself is not removed. The result is a model browser cluttered with empty containers that inflate entity counts, confuse downstream reporting, and can silently break property or material assignment audits.

The task here is narrow and deliberate: detect components that contain no elements and no geometry, and emit a structured list for human review. This chapter does not delete anything. Deletion with safety checks is a separate concern; the value of this routine is that it produces a trustworthy, reviewable inventory first.

What "empty" means in HyperMesh terms

A component is empty when both of the following hold:

  • It has zero elements. In the HyperMesh Python API, element counts are obtained per component via hm_getentityvalue on the elems collector, or by querying the element list associated with the component.
  • It has zero geometry. Geometry entities (surfaces, solids, lines, points) are attached to components through their collector membership, so the check must cover all geometry types, not just surfaces.

A component that holds only geometry but no elements is not empty by this definition — it may be a legitimate geometry-only container awaiting meshing. Likewise, a component with elements but no geometry is normal. Only the intersection of both conditions qualifies. This distinction matters because a naive element-count-only check will flag geometry-only components and produce false positives that erode trust in the report.

Do not treat "no elements" as equivalent to "empty." Geometry-only components are common in mid-cleanup models and must be preserved. The routine below checks both element and geometry counts before flagging a component.

Query strategy and the API surface

The routine relies on a small set of stable HyperMesh Python calls. Component IDs are collected with hm_getentitylist or by iterating the component collector. For each component, counts are retrieved with hm_getentityvalue using the component ID and the appropriate entity type. Geometry counts require querying each geometry type separately because HyperMesh does not expose a single "all geometry" count per component.

The output is a structured list — one record per empty component — carrying the component ID, name, element count, geometry count, and a review status field. Writing this to a CSV or printing a formatted table gives reviewers something they can sort, annotate, and sign off on before any deletion step runs.

Component collector hm_getentitylist For each component ID hm_getentityvalue Element count elems per comp n_elems Geometry count surf + solid + line n_geom n_elems==0 AND n_geom==0 EMPTY → review list id, name, counts, status RETAIN geometry-only or populated true false

Implementation

The script below is self-contained. It assumes a model is loaded in the current HyperMesh session and that the hm and hmlib modules are importable, which is the standard environment when running a Python script from the HyperMesh command window or via hmbatch. It writes a CSV report and prints a summary line.

import csv
import hm
import hmlib

# Geometry entity types that can be attached to a component.
GEOM_TYPES = ("surfs", "solids", "lines", "points")

def get_component_ids():
    """Return all component IDs in the current model."""
    return hm.getentitylist(hm.Component, 0)

def count_entities(comp_id, entity_type):
    """Return the number of entities of entity_type attached to comp_id."""
    try:
        return hm.getentityvalue(comp_id, entity_type, 0, 0)
    except Exception:
        # If a geometry type is absent from the model, treat as zero.
        return 0

def classify_component(comp_id):
    """Return a dict describing the component's emptiness."""
    n_elems = count_entities(comp_id, "elems")
    n_geom = sum(count_entities(comp_id, g) for g in GEOM_TYPES)
    name = hm.getentityvalue(comp_id, "name", 0, 0)
    return {
        "comp_id": comp_id,
        "name": name,
        "n_elems": n_elems,
        "n_geom": n_geom,
        "is_empty": (n_elems == 0 and n_geom == 0),
        "review_status": "pending",
    }

def detect_empty_components():
    """Return a list of records for all empty components."""
    records = []
    for cid in get_component_ids():
        rec = classify_component(cid)
        if rec["is_empty"]:
            records.append(rec)
    return records

def write_report(records, path="empty_components_review.csv"):
    fields = ["comp_id", "name", "n_elems", "n_geom", "is_empty", "review_status"]
    with open(path, "w", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=fields)
        writer.writeheader()
        writer.writerows(records)
    return path

if __name__ == "__main__":
    empty = detect_empty_components()
    out = write_report(empty)
    print("Empty components found: %d" % len(empty))
    print("Review file written to: %s" % out)
    for r in empty:
        print("  id=%s name=%s elems=%d geom=%d" %
              (r["comp_id"], r["name"], r["n_elems"], r["n_geom"]))

Two implementation details deserve attention. First, count_entities wraps the query in a try/except because querying a geometry type that does not exist in the model can raise rather than return zero, depending on the HyperMesh version. Treating a failed geometry query as zero is safe here because the element count is checked independently. Second, the review_status field is initialized to "pending" so that the CSV is immediately usable as a sign-off sheet: a reviewer changes it to "approved" or "rejected" before the deletion step consumes it.

Running and verifying

Load a model that you know contains at least one empty component — for example, create a component, delete its elements, and leave the container in place. Run the script from the HyperMesh command window with execfile("detect_empty.py") or via hmbatch -python detect_empty.py. Expected observable behavior:

  • The console prints Empty components found: N where N matches the number of containers you deliberately emptied.
  • The CSV contains one row per empty component with n_elems=0 and n_geom=0.
  • A geometry-only component you created as a control does not appear in the CSV, confirming the dual check works.
If the count is unexpectedly high, check whether the model uses component hierarchies or assemblies where parent components legitimately hold no direct elements. In that case, add a filter that skips components with children before flagging them as empty.

Common failure symptoms

SymptomLikely causeFix
All components flagged as emptyhm_getentityvalue argument order wrong for the installed versionConfirm the signature against the API help for your HyperMesh release; the entity type string must match exactly ("elems", not "elements")
Geometry-only components flaggedOnly element count checkedEnsure the GEOM_TYPES sum is included in is_empty
Script raises on first geometry queryGeometry type absent from modelThe try/except in count_entities handles this; verify it was not removed
CSV empty but model visibly has empty componentsComponents are children of an assembly and hold no direct entitiesDecide policy: flag parents with no children, or skip parents entirely

Review checklist before handoff

The deliverable of this chapter is the CSV, not a deletion. Before passing it to the deletion step, confirm: every row has n_elems=0 and n_geom=0; the control geometry-only component is absent; the review_status column is populated for each row; and the component names in the CSV match what the model browser shows, so reviewers can locate each entry without ambiguity. Only after these checks should the list be treated as an approved deletion candidate set.