Code-first CAD (Code-CAD) memperlakukan geometri parametrik sebagai artefak perangkat lunak yang didefinisikan lewat kode sumber. Menguji model parametrik membutuhkan pendekatan berbeda dari pengujian unit konvensional: representasi geometri (B-Rep dan tessellated mesh) rentan mengalami regresi dimensional mikro dan artefak topologi akibat pembaruan dependensi geometric kernel (seperti OpenCASCADE) atau perubahan logika skrip.
Panduan ini merancang pipeline Continuous Integration (CI) pada runner standar GitHub Actions (headless CPU) untuk mendeteksi regresi geometri secara deterministik tanpa dependensi GPU fisik.
Arsitektur Headless Runner tanpa Dedicated GPU
Mayoritas runner CI publik tidak menyediakan GPU dedicated. Framework visualisasi dan ekspor mesh yang membutuhkan konteks OpenGL harus diarahkan ke software rasterizer melalui Mesa.
Gunakan implementasi llvmpipe melalui xvfb (X Virtual Framebuffer) untuk rendering off-screen:
sudo apt-get update && sudo apt-get install -y xvfb libgl1-mesa-glx libgl1-mesa-dri mesa-utils
export LIBGL_ALWAYS_SOFTWARE=1
export GALLIUM_DRIVER=llvmpipeKonfigurasi ini memastikan pustaka visualisasi CAD (seperti VTK, PyVista, atau Python-OpenCASCADE) menginisialisasi konteks OpenGL secara headless tanpa menghentikan proses eksekusi pipeline dengan galat display unavailable.
Tiga Strategi Regression Testing Geometri
Pengujian regresi model parametrik bertingkat dari komputasi teringan (skalar fisik) hingga terberat (perceptual diffing).
1. Perbandingan Toleransi Floating-Point Skalar Fisik
Verifikasi properti massa dan batas spasial merupakan filter regresi pertama. Jangan gunakan asersi presisi mutlak (assert a == b) karena kernel komputasi numerik menghasilkan variasi floating-point mikro antar platform.
import pytest
import numpy as np
def test_bracket_mass_properties(generated_solid):
# Nilai baseline tersimpan dari golden sample
EXPECTED_VOLUME = 15420.50
EXPECTED_BBOX = [0.0, 0.0, 0.0, 50.0, 30.0, 15.0]
# Hitung properti dari B-Rep solid
actual_volume = generated_solid.volume()
actual_bbox = generated_solid.bounding_box().to_list()
# Evaluasi dengan relative dan absolute tolerance
assert actual_volume == pytest.approx(EXPECTED_VOLUME, rel=1e-4, abs=1e-2)
np.testing.assert_allclose(actual_bbox, EXPECTED_BBOX, rtol=1e-4, atol=1e-3)2. Mesh Topology Hash (Quantized Invariant)
Membandingkan file STL secara biner (misal MD5 checksum mentah) menghasilkan false positive tinggi karena urutan penulisan vertex dan index face tidak selalu stabil di berbagai build kernel. Solusinya adalah melakukan kuantisasi koordinat dan pengurutan kanonikal sebelum hashing.
import hashlib
import numpy as np
def compute_mesh_topology_hash(vertices: np.ndarray, faces: np.ndarray, precision: int = 4) -> str:
# ponytail: sorting sederhana; upgrade ke graph isomorphism jika orientasi facet berubah
# 1. Kuantisasi koordinat untuk membuang jitter floating-point mikro
quantized_verts = np.round(vertices, decimals=precision)
# 2. Re-index dan sort verteks secara leksikografis
sorted_indices = np.lexsort((quantized_verts[:, 2], quantized_verts[:, 1], quantized_verts[:, 0]))
canonical_verts = quantized_verts[sorted_indices]
# 3. Hash representasi byte yang sudah dinormalisasi
hasher = hashlib.sha256()
hasher.update(canonical_verts.tobytes())
hasher.update(np.sort(faces, axis=1).tobytes())
return hasher.hexdigest()3. Visual Snapshot Diffing
Digunakan untuk memvalidasi fitur kosmetik, chamfer, atau fillet yang tidak selalu terdeteksi signifikan lewat pergeseran volume skalar. Simpan gambar referensi (golden snapshot), render model dari posisi kamera orthografis statis, lalu bandingkan rasio SSIM (Structural Similarity Index):
from PIL import Image
import numpy as np
def assert_visual_match(snapshot_path: str, golden_path: str, max_diff_ratio: float = 0.005):
img_a = np.array(Image.open(snapshot_path).convert("L"))
img_b = np.array(Image.open(golden_path).convert("L"))
assert img_a.shape == img_b.shape, "Dimensi viewport snapshot tidak cocok."
# Hitung selisih mutlak piksel ternormalisasi
diff = np.abs(img_a.astype(int) - img_b.astype(int))
diff_ratio = np.count_nonzero(diff > 10) / img_a.size
assert diff_ratio <= max_diff_ratio, f"Visual regression terdeteksi: diff {diff_ratio:.4f} > {max_diff_ratio}"Mengeliminasi Flaky Test Lintas Arsitektur CPU
Runner GitHub Actions dapat dialokasikan pada prosesor AMD EPYC atau Intel Xeon dengan set instruksi berbeda (AVX2, AVX-512, FMA). Perbedaan evaluasi instruksi Fused Multiply-Add dapat mengubah urutan pembulatan desimal terakhir.
- Tentukan Linear & Angular Deflection: Saat mengekspor B-Rep ke STL/Mesh, tetapkan parameter diskritisasi secara eksplisit (misal
linear_deflection = 0.01,angular_deflection = 0.1). Menggunakan toleransi adaptif dinamis default kernel memicu flakiness pada mesh output. - Hindari Fast-Math: Jika mengompilasi modul ekstensi C++/Rust lokal untuk CAD, jangan gunakan flag
-ffast-math. Flag ini melanggar asosiatifitas floating-point IEEE-754 demi performa, yang merusak determinisme geometri parametrik. - Isolasi Bounding Box vs Convex Hull: Gunakan Bounding Box sumbu-sejajar (AABB) dengan toleransi margin aman (epsilon), bukan Oriented Bounding Box (OBB) berbasis analisis PCA yang sensitif terhadap distribusi vertex mesh.
Konfigurasi Workflow GitHub Actions
Implementasi workflow di bawah menggabungkan eksekusi headless, dependency caching, dan eksekusi test suite parametrik.
name: Code-CAD CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
geometry-regression:
runs-on: ubuntu-latest
steps:
- name: Checkout Source
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: "pip"
- name: Install System Dependencies for Headless CAD
run: |
sudo apt-get update
sudo apt-get install -y xvfb libgl1-mesa-glx libgl1-mesa-dri
- name: Install Dependencies
run: |
pip install -r requirements-ci.txt
- name: Cache Golden CAD Artifacts
uses: actions/cache@v4
with:
path: tests/golden_cache
key: cad-golden-models-${{ hashFiles('cad_specs/**') }}
restore-keys: |
cad-golden-models-
- name: Execute Parametric Regression Tests
env:
LIBGL_ALWAYS_SOFTWARE: "1"
GALLIUM_DRIVER: "llvmpipe"
run: |
xvfb-run --auto-servernum --server-args="-screen 0 1920x1080x24" \
pytest tests/test_parametric_models.py --verbose
- name: Upload Failure Artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: failed-diff-renders
path: tests/output_diffs/Pertimbangan Praktis Pipeline
Implementasikan pengujian geometri bertingkat: jalankan pengecekan skalar (bounding box & volume) pada setiap commit pull request karena selesai dalam sub-detik. Visual diffing dan ekspor komparasi STEP/IGES sebaiknya dieksekusi hanya jika uji skalar lulus, mengurangi overhead runtime runner CI secara signifikan.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!