Architecture¶
pycemrg-meshing wraps two C++ binaries — meshtools3d and laplace_solver —
behind a small, contract-driven Python surface. Its job is to author parameter
files, fetch the correct binary for the host platform, run it with an explicit
environment, and return verified output paths.
The two layers¶
The package is split into two directories by responsibility:
| Directory | Responsibility | Contents |
|---|---|---|
tools/ |
Stateless transformation. Pure schema and platform-key logic, no ambient I/O. | parameters.py, binaries.py |
logic/ |
Orchestration. Touches the filesystem, spawns processes, injects environment variables, builds paths from conventions. | runners.py, job.py, results.py |
Naming
In this repository, logic/ is the orchestration layer and tools/ is the
stateless layer. Keep new code on the correct side of this split: stateless
schema belongs in tools/parameters.py; anything that writes files or runs
processes belongs in logic/.
The run flow¶
A meshtools3d run is an explicit, three-step sequence — authoring the parameter file is separate from running the binary:
- Author parameters. Build a
MeshingParametersschema,setany overrides, and write the.parfile (job.write_parfile(...)). Keys are validated against the schema union, so typos raise rather than silently no-op. - Build the job. A
MeshingJobbundles the segmentation, output, and parfile paths;MeshingJob.from_parfile()reconstructs it from an existing.par. - Run.
MeshtoolsRunner.run(job, *, overrides, cwd)discovers the binary, injects the bundled library path, runs it, and returns a frozenMeshingResult.LaplaceRunner.run(job, *, options, cwd)is the analogous path forlaplace_solver.
run() requires the parfile to already exist — authoring is a separate, explicit
step, never a side effect of running.
Core stances¶
- Explicit data contracts. Layers communicate through dataclasses and flag
carriers —
MeshingJob,MeshingOverrides,LaplaceSolveOptions— rather than magic strings.MeshingOverridesrenders meshtools3d's native override flags;LaplaceSolveOptionscarries laplace's behaviour toggles only. .paris never mutated by a run. Per-run overrides are passed as the binary's own-seg_dir/-out_dir/ etc. flags; the file on disk is left untouched.- Fail-fast verification. The job's
expected_outputs, re-based onto the effective output directory, is handed to the underlyingCommandRunner, which raisesFileNotFoundErrorafter the run if any expected file is missing. - Explicit environment injection. Runners start from
os.environ.copy()and addDYLD_LIBRARY_PATH(macOS) /LD_LIBRARY_PATH(Linux) pointing at the bundledlib/beside the binary — never relying on ambient environment. - Deliberate working directory. Because the binary resolves relative paths
against its cwd, the runner picks cwd carefully (explicit
--cwdwins, else an absolute effective input dir, else the parfile's parent), and reportsoutdiragainst that same cwd to stay truthful.
Binary distribution¶
Binaries are fetched on demand via pycemrg's ModelManager, driven by
data/models.yaml. Each platform has two entries (meshtools3d +
laplace_solver) sharing one tarball URL, cached by URL + checksum so the
archive downloads once. Supported platforms are linux-x86_64 and
macos-arm64; anything else raises UnsupportedPlatformError.
See the developer guides for running on macOS and adding a new binary release.