141 lines
4.4 KiB
Python
141 lines
4.4 KiB
Python
"""ANSYS Mechanical 2024 R2 declarative geometry-inspection adapter."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
from importlib.metadata import version
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
|
|
|
from ansys_geometry import ( # noqa: E402
|
|
ANSYS_REVISION,
|
|
EXECUTION_GATE,
|
|
artifact_manifest,
|
|
atomic_json,
|
|
export_geometry_image,
|
|
file_sha256,
|
|
geometry_inventory,
|
|
import_geometry,
|
|
input_file,
|
|
probe,
|
|
terminal,
|
|
validate_artifact,
|
|
)
|
|
|
|
ADAPTER_VERSION = "0.3.0"
|
|
_ARTIFACTS = {
|
|
"geometry-manifest.json": ("geometry_manifest", "application/json"),
|
|
"geometry-preview.png": ("geometry_preview", "image/png"),
|
|
"provenance.json": ("provenance", "application/json"),
|
|
}
|
|
|
|
|
|
def _validate_semantics(request: dict[str, Any]) -> None:
|
|
inspect = request["operation"]["inspect"]
|
|
input_keys = {item["key"] for item in request["inputs"]}
|
|
if inspect["geometry"]["input"] not in input_keys:
|
|
raise ValueError("GEOMETRY_INPUT_NOT_BOUND")
|
|
if request["outputs"]:
|
|
raise ValueError("INSPECT_OUTPUTS_MUST_BE_EMPTY")
|
|
|
|
|
|
def _load_request(job_dir: Path) -> dict[str, Any]:
|
|
record = json.loads(
|
|
(job_dir / "request" / "request.json").read_text(encoding="utf-8")
|
|
)
|
|
request = record.get("request")
|
|
if not isinstance(request, dict):
|
|
raise TypeError("JOB_REQUEST_MISSING")
|
|
_validate_semantics(request)
|
|
return record
|
|
|
|
|
|
def run(job_dir: Path) -> list[dict[str, Any]]:
|
|
job_dir = job_dir.resolve(strict=True)
|
|
record = _load_request(job_dir)
|
|
request = record["request"]
|
|
inspect = request["operation"]["inspect"]
|
|
geometry = input_file(job_dir, inspect["geometry"]["input"])
|
|
output = job_dir / "output"
|
|
output.mkdir(exist_ok=True)
|
|
|
|
from ansys.mechanical.core import App
|
|
|
|
software_version: int | None = None
|
|
manifest_path = output / "geometry-manifest.json"
|
|
preview_path = output / "geometry-preview.png"
|
|
with App(version=ANSYS_REVISION, private_appdata=True) as app:
|
|
software_version = app.version
|
|
api: dict[str, Any] = {}
|
|
app.update_globals(api)
|
|
import_geometry(app, api, geometry)
|
|
inventory, _ = geometry_inventory(app)
|
|
inventory.update(
|
|
{
|
|
"title": inspect["title"],
|
|
"software": "ANSYS Mechanical",
|
|
"software_version": software_version,
|
|
}
|
|
)
|
|
atomic_json(manifest_path, inventory)
|
|
export_geometry_image(app, api, preview_path)
|
|
|
|
provenance_path = output / "provenance.json"
|
|
atomic_json(
|
|
provenance_path,
|
|
{
|
|
"adapter_version": ADAPTER_VERSION,
|
|
"pymechanical_version": version("ansys-mechanical-core"),
|
|
"ansys_revision": ANSYS_REVISION,
|
|
"request_digest": record["request_digest"],
|
|
"input": {
|
|
"key": inspect["geometry"]["input"],
|
|
"filename": geometry.name,
|
|
"sha256": file_sha256(geometry),
|
|
},
|
|
},
|
|
)
|
|
paths = [manifest_path, preview_path, provenance_path]
|
|
for path in paths:
|
|
validate_artifact(path)
|
|
return [artifact_manifest(path, _ARTIFACTS) for path in paths]
|
|
|
|
|
|
def main() -> int:
|
|
if sys.argv[1:] == ["--probe"]:
|
|
return probe(ADAPTER_VERSION)
|
|
if len(sys.argv) != 2:
|
|
print("[ERR] Usage: worker.py <job-directory>", file=sys.stderr)
|
|
return 2
|
|
job_dir = Path(sys.argv[1])
|
|
record: dict[str, Any] = {}
|
|
try:
|
|
record = _load_request(job_dir)
|
|
if os.environ.get(EXECUTION_GATE) != "1":
|
|
raise RuntimeError("ANSYS_242_REAL_LICENSE_ACCEPTANCE_REQUIRED")
|
|
artifacts = run(job_dir)
|
|
atomic_json(job_dir / "artifacts.json", artifacts)
|
|
atomic_json(job_dir / "terminal.json", terminal(record, "succeeded", artifacts, {}))
|
|
print("[OK] ANSYS Mechanical geometry inspection completed.")
|
|
return 0
|
|
except Exception as exc: # noqa: BLE001 - terminal.json must capture vendor failures
|
|
atomic_json(
|
|
job_dir / "terminal.json",
|
|
terminal(
|
|
record,
|
|
"failed",
|
|
[],
|
|
{"code": type(exc).__name__, "detail": str(exc)[:500]},
|
|
),
|
|
)
|
|
print(f"[ERR] {type(exc).__name__}: {exc}", file=sys.stderr)
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|