115 lines
3.5 KiB
Python
115 lines
3.5 KiB
Python
"""Export SBCmesh.mat (MATLAB getMesh.m output) to OpticsFEM SBCmesh.dat format."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
from pathlib import Path
|
|
|
|
import scipy.io as sio
|
|
|
|
|
|
def _as_rows(arr, ncol: int) -> list[list[int]]:
|
|
if arr.ndim == 1:
|
|
return [list(arr)]
|
|
if arr.shape[0] == ncol and arr.shape[1] != ncol:
|
|
arr = arr.T
|
|
return [list(row) for row in arr]
|
|
|
|
|
|
def export_sbcmesh_mat_to_dat(mat_path: Path, dat_path: Path) -> None:
|
|
data = sio.loadmat(str(mat_path), squeeze_me=True, struct_as_record=False)
|
|
mesh = data["mesh"]
|
|
|
|
lines: list[str] = []
|
|
lines.append("NbrVertex")
|
|
lines.append(str(int(mesh.NbrVertex)))
|
|
lines.append("Vertex")
|
|
for row in _as_rows(mesh.Vertex, 3):
|
|
lines.append(f"{row[0]:.16g} {row[1]:.16g} {row[2]:.16g}")
|
|
|
|
lines.append("NbrTet")
|
|
lines.append(str(int(mesh.NbrTet)))
|
|
lines.append("Tet")
|
|
for row in _as_rows(mesh.Tet, 4):
|
|
lines.append(f"{int(row[0])} {int(row[1])} {int(row[2])} {int(row[3])}")
|
|
|
|
lines.append("DomainOfTet")
|
|
dom_tet = mesh.DomainOfTet.flatten()
|
|
for v in dom_tet:
|
|
lines.append(str(int(v)))
|
|
|
|
lines.append("NbrEdge")
|
|
lines.append(str(int(mesh.NbrEdge)))
|
|
lines.append("Edge")
|
|
for row in _as_rows(mesh.Edge, 2):
|
|
lines.append(f"{int(row[0])} {int(row[1])}")
|
|
|
|
lines.append("EdgeOfTet")
|
|
eot_rows = _as_rows(mesh.EdgeOfTet, 6)
|
|
zero_based = any(int(v) == 0 for row in eot_rows for v in row)
|
|
for row in eot_rows:
|
|
vals = [int(x) + (1 if zero_based else 0) for x in row]
|
|
lines.append(" ".join(str(x) for x in vals))
|
|
|
|
lines.append("NbrTri")
|
|
lines.append(str(int(mesh.NbrTri)))
|
|
lines.append("Tri")
|
|
for row in _as_rows(mesh.Tri, 3):
|
|
lines.append(f"{int(row[0])} {int(row[1])} {int(row[2])}")
|
|
|
|
lines.append("DomainOfTri")
|
|
dom_tri = mesh.DomainOfTri.flatten()
|
|
for v in dom_tri:
|
|
lines.append(str(int(v)))
|
|
|
|
lines.append("ConnOfTri")
|
|
for row in _as_rows(mesh.ConnOfTri, 2):
|
|
lines.append(f"{int(row[0])} {int(row[1])}")
|
|
|
|
norm_rows = [1, 2, 3, 4, 5, 14]
|
|
norm_face = mesh.NormOfFace
|
|
lines.append("NormOfFace")
|
|
lines.append(str(len(norm_rows)))
|
|
for d in norm_rows:
|
|
n = norm_face[d - 1] if norm_face.shape[0] >= d else norm_face[d]
|
|
if hasattr(n, "__len__") and len(n) >= 3:
|
|
nx, ny, nz = float(n[0]), float(n[1]), float(n[2])
|
|
else:
|
|
defaults = {
|
|
1: (-1, 0, 0),
|
|
2: (0, -1, 0),
|
|
3: (0, 0, -1),
|
|
4: (0, 0, 1),
|
|
5: (0, 1, 0),
|
|
14: (1, 0, 0),
|
|
}
|
|
nx, ny, nz = defaults[d]
|
|
lines.append(f"{d} {nx:.16g} {ny:.16g} {nz:.16g}")
|
|
|
|
dat_path.parent.mkdir(parents=True, exist_ok=True)
|
|
dat_path.write_text("\n".join(lines) + "\n", encoding="ascii")
|
|
print(f"Wrote {dat_path} ({len(lines)} lines)")
|
|
print(
|
|
f" NbrVertex={mesh.NbrVertex}, NbrTet={mesh.NbrTet}, "
|
|
f"NbrEdge={mesh.NbrEdge}, NbrTri={mesh.NbrTri}"
|
|
)
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser(description="Export SBCmesh.mat to SBCmesh.dat")
|
|
parser.add_argument("mat_file", type=Path, help="Input SBCmesh.mat path")
|
|
parser.add_argument(
|
|
"-o",
|
|
"--output",
|
|
type=Path,
|
|
default=None,
|
|
help="Output SBCmesh.dat path (default: same dir as mat)",
|
|
)
|
|
args = parser.parse_args()
|
|
out = args.output or args.mat_file.with_name("SBCmesh.dat")
|
|
export_sbcmesh_mat_to_dat(args.mat_file, out)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|