|
| 1 | +# Dual Contouring Overview |
| 2 | + |
| 3 | +## Module Layout |
| 4 | +- `multi_scalar_dual_contouring.py`: Entry point for multi-stack extraction; handles masking, edge finding, interpolation, and triangulation per stack and returns `DualContouringMesh` objects. |
| 5 | +- `_interpolate_on_edges.py`: Helper to locate edge intersections for a single stack, temporarily swap in a custom grid, interpolate exported fields on edge points, and package a `DualContouringData` payload. |
| 6 | +- `_experimental_water_tight_DC_1.py`: Prototype routine that merges per-stack datasets and runs dual contouring once to investigate watertight outputs. |
| 7 | +- `_mask_buffer.py`: Stateful placeholder intended for mask reuse, currently only provides a `clean` method. |
| 8 | +- `__init__.py`: Empty; the package exposes no curated re-exports today. |
| 9 | + |
| 10 | +## Data Flow Summary |
| 11 | +1. `dual_contouring_multi_scalar` clones interpolation options, enabling gradient export required by triangulation. |
| 12 | +2. Triangulation codes are generated (`get_triangulation_codes`) and masked per stack using `mask_generation` and `get_masked_codes`. |
| 13 | +3. For each scalar field stack: |
| 14 | + - Validate stack relations with `_validate_stack_relations`. |
| 15 | + - Derive edge intersections and validity flags via `find_intersection_on_edge`. |
| 16 | + - Buffer intersection coordinates for later interpolation. |
| 17 | +4. `_interp_on_edges` concatenates all intersections, swaps a temporary grid into the interpolation input, and calls `interpolate_all_fields_no_octree` to recover exported fields on edge points before restoring the original grid. |
| 18 | +5. `DualContouringData` objects are built per stack, bundling edge/center coordinates, gradients, and metadata, then passed to `compute_dual_contouring` alongside masked triangulation codes to generate meshes. |
| 19 | +6. Optional post-processing (`apply_faults_vertex_overlap`) is compiled but disabled; an experimental watertight path bypasses the standard pipeline when `options.debug_water_tight` is set. |
| 20 | + |
| 21 | +## Noted Issues / Risks |
| 22 | +- `_experimental_water_tight` invokes `all_meshes.append(*meshes)`, which fails if more than one mesh is returned, and it hardcodes the merge to two stacks while discarding scalar values and forcing `n_surfaces_to_export = 1`. |
| 23 | +- `_validate_stack_relations` checks whether the previous stack relation equals both `Onlap` and `Erosion`, a condition that can never succeed, so the intended guard is dead code. |
| 24 | +- `MaskBuffer` is cleared at the start of extraction but never populated or referenced again, introducing unnecessary shared state. |
| 25 | +- Temporary grid swaps lack `try/finally` protection; exceptions during interpolation could leave `InterpolationInput` pointing at the wrong grid. |
| 26 | +- `_interp_on_edges` re-interpolates all stacks on every invocation, even when only a subset needs updates, which can increase runtime cost. |
| 27 | +- `apply_faults_vertex_overlap` is effectively unreachable due to the hard-coded `and False`, preventing debug runs from exercising fault-resolution logic. |
| 28 | + |
| 29 | +## Improvement Opportunities |
| 30 | +- Fix the watertight helper by switching to `extend`, generalizing the merge over all stacks, and preserving per-surface metadata, or gate it clearly as experimental. |
| 31 | +- Replace `_validate_stack_relations` with accurate relation checks or remove it in favor of clearer upstream validation. |
| 32 | +- Either implement mask caching within `MaskBuffer` or drop the class to avoid confusing statefulness. |
| 33 | +- Wrap temporary grid assignments in context management to guarantee restoration when errors occur. |
| 34 | +- Add selective interpolation paths (per-stack or cached results) to avoid redundant work in `_interp_on_edges` and `_interpolate_on_edges_for_dual_contouring`. |
| 35 | +- Re-enable or refactor `apply_faults_vertex_overlap` so fault overlap correction can be toggled through configuration rather than being permanently disabled. |
| 36 | + |
| 37 | +## Optimization Opportunities |
| 38 | +- **Avoid repeated deep copies**: `dual_contouring_multi_scalar` performs a `copy.deepcopy` of `options` on every call (`gempy_engine/API/dual_contouring/multi_scalar_dual_contouring.py:50`). Profiling whether a shallow copy or explicit mutation of the gradient flag would suffice could trim overhead, especially when options include large backend tensors. |
| 39 | +- **Cache triangulation artefacts**: `mask_generation` and `get_triangulation_codes` recompute masks and codes for every invocation (`gempy_engine/API/dual_contouring/multi_scalar_dual_contouring.py:60`). Persisting these per-octree level—or at least per session—could avoid redundant work when extracting multiple realisations with identical grids. |
| 40 | +- **Incremental edge interpolation**: `_interp_on_edges` concatenates all intersection coordinates and re-runs `interpolate_all_fields_no_octree` even if only one stack changed (`gempy_engine/API/dual_contouring/multi_scalar_dual_contouring.py:188`). Introducing per-stack caching or dirty-bit tracking would let unchanged stacks reuse their previous edge fields. |
| 41 | +- **Minimise array copies under masking**: Slicing `octree_grid.values[mask]` allocates new arrays for each stack (`gempy_engine/API/dual_contouring/multi_scalar_dual_contouring.py:113`). Refactoring `DualContouringData` to accept views or index arrays would reduce memory churn when masks are large. |
| 42 | +- **Parallelise independent stacks**: Edge detection and triangulation are independent per stack (`gempy_engine/API/dual_contouring/multi_scalar_dual_contouring.py:75`). Leveraging multiprocessing, threading, or backend vectorisation could shorten wall-clock times on multi-core systems. |
| 43 | +- **Use backend tensor ops in experiments**: `_merge_dc_data` relies on NumPy stacking (`gempy_engine/API/dual_contouring/_experimental_water_tight_DC_1.py:23`). Switching to `BackendTensor` abstractions would avoid CPU round-trips when the active backend is GPU-accelerated. |
0 commit comments