Skip to content

ENH: Out-of-core architecture rewrite and filter optimizations#1568

Draft
joeykleingers wants to merge 82 commits into
BlueQuartzSoftware:developfrom
joeykleingers:worktree-ooc-architecture-rewrite
Draft

ENH: Out-of-core architecture rewrite and filter optimizations#1568
joeykleingers wants to merge 82 commits into
BlueQuartzSoftware:developfrom
joeykleingers:worktree-ooc-architecture-rewrite

Conversation

@joeykleingers

@joeykleingers joeykleingers commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

Summary

This branch does two things at once:

  1. Reworks the core out-of-core (OOC) data-storage architecture in simplnx so that disk-backed storage is supplied by a runtime-registered IO manager through clean interfaces, with the core library holding no reference to any concrete OOC format or symbol. Core gains a bulk-I/O data-store API (copyIntoBuffer / copyFromBuffer), an injectable store-format resolver, IO-manager lifecycle hooks, a tri-state storage-mode preference, a memory-budget manager, and memory-safety guards. The OOC implementation itself (chunked HDF5 stores, the chunk cache, deflate decompression) lives in a separate private SimplnxOoc source set and is not part of this diff — it plugs into core at runtime through these interfaces.

  2. Adds chunk-aware (OOC-optimized) algorithm variants for ~50 filters across the SimplnxCore and OrientationAnalysis plugins, plus shared core utilities that benefit many more. Random-access algorithms that thrash the chunk cache on disk-backed arrays now either stream data with bulk I/O or dispatch to a sequential "scanline / CCL" variant, eliminating per-element virtual dispatch and HDF5 chunk churn. In-core behavior and performance are preserved via a runtime storage-type check, so optimized filters keep two code paths: one for in-memory data, one for disk-backed data.

Scope of this diff

develop…HEAD: 378 files, +42,853 / −13,112.

Area Files + / −
src/simplnx (core library) 74 +6,874 / −1,252
Plugins/SimplnxCore 179 +24,817 / −8,795
Plugins/OrientationAnalysis 103 +8,379 / −2,853
Root / build / top-level tests 22 +2,783 / −212

How to review

The diff is large but highly patterned, and the two layers are independent:

  • Core architecture lives in src/simplnx/DataStructure/IO/Generic/*, Core/Preferences.*, Utilities/{MemoryBudgetManager,AlgorithmDispatch,SegmentFeatures,UnionFind,SliceBufferedTransfer}.*, and Filter/IFilter.cpp (Part 1).
  • Filter work is summarized in the inventory tables in Part 2. Every optimization is one of four patterns — reviewing one example of each pattern transfers to the rest. Each optimized algorithm's original file was renamed to the in-core variant and the OOC variant added beside it, so the diffs read as edits against the original code rather than wholesale new files.

Part 1 — Core out-of-core architecture (src/simplnx)

1.1 Bulk-I/O data-store API

  • copyIntoBuffer / copyFromBuffer on AbstractDataStore<T> (a flat range form and a tuple-addressed form) are the single mechanism for bulk reads/writes, implemented by DataStore<T> and EmptyDataStore<T>; the OOC implementation supplies its own override.
  • The storage-kind signal is IDataStore::StoreType { InMemory, OutOfCore, Empty }, queried via getStoreType(). The chunk-traversal API (loadChunk, getNumberOfChunks, getChunkLowerBounds, getChunkUpperBounds, getChunkShape) and the chunk-shape-based OOC detection are removed — bulk I/O plus getStoreType() replace them entirely.
  • Empty/placeholder string storage: EmptyStringStore, AbstractStringStore/StringStore placeholder support, and StringArray::isPlaceholder().

1.2 Runtime store-format resolution and IO-manager hooks

OOC capability is supplied entirely at runtime; core never names the concrete format.

  • IDataStoreFormatResolver: a const, thread-safe policy interface deciding which registered format a soon-to-be-created array uses ("" = in-memory). InMemoryFormatResolver is the default policy.
  • ArrayCreationUtilities::ResolveStorageFormat is the single decision point for every array-creation call site, with a fixed precedence: the unstructured/poly-geometry gate (ParentGeometrySupportsOoc) forces in-core, then an explicit per-filter format override, then the DataStructure's resolver. DataStructure carries a per-instance resolver plus a lazily-seeded process-wide default (neither serialized).
  • IDataIOManager lifecycle hooks (default no-ops): finalizesImport, onImportFinalize, onRecoveryWrite, onFinalizeStores, setBaseDirectory, shutdownManager. DataIOCollection fans these out to every registered manager, so an OOC manager participates in import finalization, recovery writes, store read-only transition, and shutdown without core knowing the specifics.
  • CoreDataIOManager: the always-present default manager that registers the in-memory data-store/list-store factories; an OOC manager registers on top at runtime.
  • Store creation goes through resolver-aware CreateDataStore / CreateListStore single entry points; CreateNeighborListAction / CreateNeighbors thread an explicit dataFormat override through to the store.

1.3 Storage-mode preference (+ legacy migration)

  • DataStorageMode { Adaptive, ForceInCore, ForceOutOfCore } (persisted as data_storage_mode) is the single source of truth for storage placement, replacing the large_data_format / force_ooc_data preferences. The enum is deliberately OOC-vocabulary-free — core states user intent; the registered manager maps it to a concrete format. dataStorageMode() migrates older preference files from the retained legacy keys; useOocData() is a convenience view (true unless ForceInCore).
  • Preferences seeds the OOC base directory and default format on startup via the IO-collection hooks, and gains a removeValue helper.

1.4 Memory budget + memory safety

  • MemoryBudgetManager: tracks the budget governing in-core vs OOC placement. defaultBudgetBytes() (50% of RAM, ≥1 GiB, clamped to the cap), maxBudgetBytes() (max(min(total−6 GiB, 0.95·total), 1 GiB)), and setBudgetBytes() which clamps to the cap and reports whether it clamped. Total-RAM detection is centralized in Memory::GetTotalMemory(). The default is clamped to the cap so it never exceeds it on <12 GiB machines (e.g. CI runners).
  • nxrunner --memory-budget <GB>: CLI flag wired through to the budget manager so the override takes effect in headless runs, with parsing hardened against NaN/inf/trailing garbage.
  • Memory-safety guards (additive to the existing -264 total-RAM hard block):
    • -271 — non-blocking preflight warning when an in-core array would exceed currently-available RAM. OOC arrays are excluded (EmptyDataStore::memoryUsage() reports 0 for OOC placeholders; the format is resolved in preflight via the shared ResolveStorageFormat helper).
    • -272 — a std::bad_alloc safety net at the single IFilter::execute → executeImpl boundary, turning an out-of-memory condition into a clean pipeline error instead of a crash.

1.5 HDF5 streaming write + compression

  • DatasetIO provides the streaming OOC write path — createEmptyDataset + writeSpanHyperslab for arrays too large to be resident — alongside the single-shot writeSpan; reads use readChunk / readChunkIntoSpan.
  • The streaming path honors requested compression: createEmptyDataset builds the chunked-deflate creation property list (BuildChunkedDeflateDcpl), so a large OOC array taking the two-step streaming write is compressed identically to the single-shot path. Contiguous storage is still used for compression level 0 and for arrays below the small-array threshold.

1.6 .dream3d loader API

  • Dream3dIO exposes a LoadDataStructure family: LoadDataStructure, LoadDataStructureMetadata (metadata-only for preflight), LoadDataStructureArrays (array subset), plus resolver-aware overloads that stamp a per-DataStructure resolver before import finalization (so a read-only visualization load can direct arrays to disk for fast first-show). Import is eager or deferred based on anyManagerFinalizesImport(); writes run under a recovery-write guard supplied by the registered manager.
  • ImportH5ObjectPathsAction uses this API: metadata-only on preflight, full load on execute, with a selective shortest-path-first merge of only the requested paths.

1.7 Core algorithm infrastructure

  • AlgorithmDispatch.hppDispatchAlgorithm<InCoreAlgo, OocAlgo>(arrays, args…), a free function template selecting between an in-core and an OOC algorithm class at runtime. Priority: ForceInCoreAlgorithm() > any array OOC > ForceOocAlgorithm() > in-core default. RAII test guards ForceOocAlgorithmGuard(bool) and ForceInCoreAlgorithmGuard let a single build exercise both paths.
  • SegmentFeatures OOC pathexecuteCCL(): Z-slice connected-component labeling with a 2-slice rolling buffer and UnionFind equivalence tracking (Face and FaceEdgeVertex connectivity, optional periodic BCs), replacing random-access BFS/DFS flood-fill on disk-backed data.
  • UnionFind — vector-based disjoint set with union-by-rank and path-halving.
  • SliceBufferedTransfer — type-dispatched Z-slice buffered tuple copy for morphological / neighbor-replacement transfer phases.
  • Extent — region/range math helper (with unit tests).
  • AlignSections OOC path — bulk slice read/write transfer for the align-sections family.

1.8 Core utility bulk-I/O conversions

These live in core utilities and benefit every caller; each is guarded by a runtime storage-type check that preserves the original in-core code path:

  • DataArrayUtilitiesImportFromBinaryFile, AppendData, CopyData, and the mirror swap_ranges ops route through chunked bulk I/O when OOC. (Powers ReadRawBinary and AppendImageGeometry's mirror.)
  • DataGroupUtilities::RemoveInactiveObjects — chunked featureIds renumbering via copyIntoBuffer/copyFromBuffer.
  • ClusteringUtilities::RandomizeFeatureIds — chunked bulk I/O (both overloads; benefits segmentation filters, SharedFeatureFace, MergeTwins).
  • GeometryHelpersFindElementsContainingVert / FindElementNeighbors use 65K-element chunked passes with a current-chunk cache-hit check before falling back to per-element reads.
  • ImageRotationUtilities — Z-slab source cache for nearest-neighbor and a ±2-slice trilinear margin, sliding-window slab updates (memmove + delta reads), and intra-slice parallelism. This is how ApplyTransformationToGeometry and RotateSampleRefFrame get their OOC speedups (no plugin algorithm file changes for ApplyTransformation).
  • TriangleUtilities — bulk-load triangles/labels for winding repair.
  • H5DataStore — streaming row-batch FillOocDataStore replacing full-dataset allocation on import.
  • RectGridGeom / ImageGeom findElementSizes — route through the resolver-aware CreateDataStore (voxel-sizes array can go OOC); the RectGrid inner loop refactored to per-axis precompute + Z-slice copyFromBuffer.

Part 2 — Filter optimizations

Optimization patterns

Every filter optimization is one of these four shapes:

  • (a) Dispatch splitDispatchAlgorithm<…Direct, …Scanline>: an in-core Direct class (unchanged or parallel) and an OOC Scanline class that streams Z-slices / chunks. The original Foo.cpp becomes a thin dispatcher.
  • (b) CCL splitDispatchAlgorithm<…BFS, …CCL> (or an in-file branch): random-access flood-fill in-core, sequential Z-slice connected-component labeling for OOC.
  • (c) Single-implementation bulk I/O — one algorithm that reads/writes in chunks and caches feature/ensemble-level arrays in local std::vectors, with a runtime storage-type check so in-core stays optimal.
  • (d) Slice-buffered / safety — rolling Z-slice buffers via SliceBufferedTransfer, or an OOC-correctness guard (e.g. disabling threading for OOC stores) / progress-and-cancel additions.

Algorithm structure: in-core + out-of-core variants

For dispatch-split filters the original algorithm file is renamed to the in-core variant and the OOC variant is added beside it; the original filename remains as a thin dispatcher:

Filter In-core variant OOC variant
FillBadData FillBadDataBFS FillBadDataCCL
IdentifySample IdentifySampleBFS IdentifySampleCCL
ComputeBoundaryCells …Direct …Scanline
ComputeFeatureNeighbors …Direct …Scanline
ComputeSurfaceFeatures …Direct …Scanline
ComputeSurfaceAreaToVolume …Direct …Scanline
ComputeFeatureSizes …Direct …Scanline
MultiThresholdObjects …Direct …Scanline
DBSCAN …Direct …Scanline
ComputeKMedoids …Direct …Scanline
QuickSurfaceMesh …Direct …Scanline
SurfaceNets …Direct …Scanline
BadDataNeighborOrientationCheck (OA) …Worklist …Scanline
ComputeGBCDPoleFigure (OA) …Direct …Scanline

New shared header IdentifySampleCommon.hpp (SimplnxCore) provides the VectorUnionFind and per-slice functor shared by the BFS/CCL variants; TupleTransfer.hpp gains quickSurfaceTransferBatch / surfaceNetsTransferBatch bulk APIs used by the mesh Scanline variants.

SimplnxCore inventory

Filter Pattern Technique
FillBadData (b) DispatchAlgorithm<FillBadDataBFS, FillBadDataCCL>; CCL streams Z-slices with core UnionFind
IdentifySample (b) DispatchAlgorithm<IdentifySampleBFS, IdentifySampleCCL>; scanline labeling via VectorUnionFind
ScalarSegmentFeatures (b) In-file OOC branch to SegmentFeatures::executeCCL() (Z-slice CCL)
ComputeBoundaryCells (a) Scanline Z-slice rolling-window neighbor reads
ComputeSurfaceFeatures (a) Scanline Z-slice rolling window
ComputeFeatureNeighbors (a) Scanline Z-slice rolling window
ComputeSurfaceAreaToVolume (a) Scanline Z-slice rolling window
ComputeFeatureSizes (a) Direct = tbb parallel Kahan accumulation; Scanline = chunked copyIntoBuffer (256K-tuple)
MultiThresholdObjects (a) Scanline eliminates the O(n) temp result vector
DBSCAN (a) Chunked grid build + on-demand per-cell coordinate reads in canMerge
ComputeKMedoids (a) Chunked findClusters; bounded per-cluster peak memory
QuickSurfaceMesh (a) Scanline drops the O(volume) nodeIds for rolling 2-plane node buffers; quickSurfaceTransferBatch
SurfaceNets (a) Scanline reimplements with a hash-map surface store; surfaceNetsTransferBatch
ComputeFeatureCentroids (c) Plain std::vector accumulators (no DataStore); 64K-tuple chunked featureIds
ComputeFeatureClustering (c) Feature-level array caching; RDF in local vectors
ComputeEuclideanDistMap (c) Bulk-read into local vectors, flood-fill in RAM, bulk-write
ComputeFeaturePhases (c) 65K-tuple chunked featureIds + cellPhases; feature-level vectors replace per-cell map
RequireMinimumSizeFeatures (c) Chunked feature removal + 3-slice rolling slab for assignBadVoxels voting; sparse changed-voxel tracking
CropImageGeometry (c) K=32 Z-slice batched slab I/O (O(n^⅔) working set)
ExtractInternalSurfacesFromTriangleGeometry (c) triMask bitset + sparse triPrefixSum popcount (~6.4× less memory); 65K-element streamed passes
ComputeTriangleAreas (c) Filter-level chunked triangle connectivity + span-bounded vertex loads; parallel compute on local buffers
RegularGridSampleSurfaceMesh (c/d) ZSliceWorker parallel Z-slice rasterize → mutex-guarded bulk copyFromBuffer
ErodeDilateBadData (d) SliceBufferedTransfer per-Z commit + Z-slice neighbor reads
ErodeDilateCoordinationNumber (d) SliceBufferedTransfer per-Z commit
ErodeDilateMask (c/d) Slice-based bulk mask erosion/dilation
ReplaceElementAttributesWithNeighborValues (d) SliceBufferedTransfer per-Z best-neighbor commit
AlignSectionsFeatureCentroid (d) In-file OOC branch findShiftsOoc() with per-Z-slice mask reads
WriteAvizoRectilinearCoordinate / WriteAvizoUniformCoordinate (c) Bulk copyIntoBuffer for coordinate/data output
ComputeArrayStatistics (d) OOC-safety: parallelization disabled when stores are OOC
ReadHDF5Dataset / ReadStlFile (d) Cancel checks + throttled progress

OrientationAnalysis inventory

Filter Pattern Technique
ComputeIPFColors (a) DispatchAlgorithm<…Direct, …Scanline>; Direct keeps parallel in-core, Scanline 65K-tuple chunks + cached crystal structures; color key forwarded to the OOC path
ComputeGBCDPoleFigure (a) Dispatched at the filter level; Scanline caches only the phase-of-interest GBCD slice
BadDataNeighborOrientationCheck (a) DispatchAlgorithm<…Worklist, …Scanline>; bool-mask reads routed through bulk I/O
EBSDSegmentFeatures (b) SegmentFeatures::executeCCL() slice-by-slice, replacing DFS flood-fill
CAxisSegmentFeatures (b) Same CCL architecture as EBSDSegmentFeatures
AlignSectionsMisorientation (c) findShiftsOoc(), 2-slice buffered quats/phases/mask + cached crystal structures
AlignSectionsMutualInformation (c) Per-slice bulk reads of phases/quats/mask + cached crystal structures
NeighborOrientationCorrelation (c/d) 3-slice rolling window via SliceBufferedTransfer; cached crystal structures
ComputeAvgOrientations (c) Chunked featureIds/phases/quats; cached crystal structures + avgQuats; bulk write
ComputeFeatureReferenceMisorientations (c) Chunked cell-level arrays; cached crystal structures, avgQuats, center quats
ComputeKernelAvgMisorientations (c) Per-Z-plane [plane−kZ, plane+kZ] slab reads; cached crystal structures
ComputeAvgCAxes (c) 4096-tuple chunked reads; feature-level avgCAxes + crystal structures cached
ComputeCAxisLocations (c) 64K-tuple chunked read/process/write; cached crystal structures
ComputeFeatureReferenceCAxisMisorientations (c) Z-slice buffered cell-level I/O; cached crystalStructures + avgCAxes
ComputeFeatureNeighborCAxisMisalignments (c) Bulk-read feature-level arrays; buffered output
ComputeTwinBoundaries (c) Bulk-read all face/feature/ensemble arrays into local vectors
MergeTwins (c) Chunked voxel parent-ID fill + assignment; feature-level parentIds cached
ConvertOrientations (c) Macro-generated convertors process each range in 4096-tuple chunks (bulk read→convert→bulk write)
RotateEulerRefFrame (c) 64K-tuple in-place read-modify-write chunks
ComputeGBCD (c) Feature-level caching; chunked 50K-triangle reads; GBCD accumulated locally then copyFromBuffer
ComputeGBCDMetricBased (c) Per-chunk sequential area accumulation (no O(n) triIncluded); feature-level caching; raw-pointer parallel selector
ComputeGBPDMetricBased (c) Caches feature eulers/phases + ensemble crystal structures; chunked triangle reads (distinct filter from GBCD MetricBased)
WriteGBCDGMTFile (c) Caches phase-of-interest GBCD slice; crystal structures cached
WriteGBCDTriangleData (c) 8K-triangle chunked reads; feature-level Euler cache; output buffered via fmt::memory_buffer
ReadAngData / ReadCtfData (c) Bulk copyFromBuffer for all cell arrays; chunked Euler interleave; in-place phase validation
ReadH5Ebsd (c) copyFromBuffer in CopyData template, phase copy, Euler interleave
ReadH5EspritData (c) Bulk copyFromBuffer from raw HDF5 reader buffers
WritePoleFigure (c) Per-phase chunked input reads with bounded buffers; bulk copyFromBuffer for intensity/image outputs

Cancel + progress

In-core and OOC variants gained m_ShouldCancel checks at the top of major loops and ThrottledMessenger-based progress reporting with per-phase messages and percent-complete.


Part 3 — Performance results

All benchmarks use arm64 Release builds. OOC measurements force the disk-backed path through DataStorageMode::ForceOutOfCore or ForceOocAlgorithmGuard.

CRITICAL filter optimizations (existing unit-test data, filter.execute() only)

Filter IC Before (s) IC After (s) IC Speedup OOC Before (s) OOC After (s) OOC Speedup
ComputeShapesTriangleGeom 0.012920 0.012610 1.02x 0.012910 0.012560 1.03x
RemoveFlaggedFeatures 0.000890 0.000990 0.90x 0.003230 0.003450 0.94x
ComputeKMeans 0.000980 0.000970 1.01x 0.020480 0.020290 1.01x
ComputeArrayStatistics 0.000790 0.000700 1.13x 0.004800 0.004670 1.03x
ComputeArrayHistogramByFeature 0.000710 0.000850 0.84x 0.003890 0.004020 0.97x
ResampleRectGridToImageGeom 0.000890 0.000780 1.14x 0.178960 0.009790 18.28x
ResampleImageGeom 0.002170 0.000940 2.31x 1.658850 0.012980 127.80x
UncertainRegularGridSampleSurfaceMesh 0.003190 0.001850 1.72x 0.487270 0.003690 132.05x
ArrayCalculator 0.000240 0.000240 1.00x 0.000250 0.000230 1.09x
FlyingEdges3D 0.000420 ~0.000100 ~4.20x 0.004830 0.000150 32.20x
ConvertOrientationsToVertexGeometry 0.016570 0.014700 1.13x 0.311490 0.020160 15.45x
ExtractVertexGeometry 0.001500 0.000690 2.17x 0.601910 0.001680 358.28x
ComputeVertexToTriangleDistances 0.000600 0.000750 0.80x 0.000620 0.002030 0.31x
WriteAbaqusHexahedron 0.018990 0.016520 1.15x 4.294920 0.201020 21.37x
WriteStlFile 0.000790 0.000840 0.94x 0.000720 0.001440 0.50x
VerifyTriangleWinding 0.003020 0.003250 0.93x 0.003010 0.003490 0.86x
CreateAMScanPaths 0.020630 0.002070 9.97x 0.020620 0.002180 9.46x

Small existing datasets do not expose every asymptotic win: mesh bucketing/pruning and bounded-memory streaming can add fixed overhead at this scale. All 17 filters passed their affected suites in both configurations; the table reports measured values rather than hiding those small-test regressions.

Large synthetic filter benchmarks (filter.execute() only)

Tier Filter IC Before (s) IC After (s) IC Speedup OOC Before (s) OOC After (s) OOC Speedup
HIGH ComputeArrayHistogram 0.088506 0.053227 1.66x 487.917981 0.814006 599x
HIGH ComputeFeatureBounds 0.053695 0.002626 20.45x 65.637232 0.186534 352x
HIGH ComputeFeatureRect 0.071993 0.017759 4.05x 715.698738 0.090509 7,907x
HIGH ExtractFeatureBoundaries2D 0.028188 0.011352 2.48x 63.905878 0.024392 2,620x
HIGH PartitionGeometry 0.005694 0.001530 3.72x 107.960858 0.054839 1,969x
HIGH ReadChannel5Data 0.408973 0.345354 1.18x >300 0.368083 >815x
HIGH CreateColorMap 0.029480 0.010684 2.76x >120 0.182033 >659x
HIGH ComputeBoundingBoxStats 0.019897 0.014888 1.34x >60 1.075362 >55.8x
HIGH CombineAttributeArrays 0.062550 0.056931 1.10x >60 0.391489 >153x
HIGH ComputeCoordinateThreshold 0.090332 0.000675 133.8x 7.620420 0.090790 83.9x
HIGH ComputeDifferencesMap 0.022731 0.002642 8.60x >60 0.184405 >325x
HIGH ComputeLargestCrossSections (XY) 0.029501 0.026580 1.11x 24.694420 0.032494 760x
HIGH ComputeLargestCrossSections (XZ) 0.024886 0.006156 4.04x 24.816181 0.107269 231x
HIGH ComputeLargestCrossSections (YZ) 0.029908 0.020359 1.47x 26.939749 0.302016 89.2x
HIGH ComputeVectorColors 0.116860 0.062063 1.88x >60 0.248597 >241x
HIGH ComputeFZQuaternions 0.051898 0.038698 1.34x >60 0.595947 >100x
HIGH ComputeMisorientations 0.080476 0.052000 1.55x >60 0.062403 >961x
HIGH ComputeFeaturePhasesBinary 0.027152 0.007749 3.50x >60 0.009101 >6,592x
HIGH ConditionalSetValue 0.009228 0.001509 6.12x >60 0.165667 >362x
HIGH ConvertColorToGrayScale 0.004248 0.001848 2.30x >60 0.101111 >593x
HIGH ConvertQuaternion 0.008270 0.001548 5.34x >60 0.127112 >472x
HIGH ChangeAngleRepresentation 0.002260 0.001425 1.59x >60 0.052921 >1,133x
HIGH ComputeCoordinatesImageGeom 0.006337 0.001267 5.00x >60 0.019143 >3,134x
HIGH AddBadData 0.092763 0.009174 10.11x 49.366814 0.183687 268.76x
HIGH WriteStatsGenOdfAngleFile 0.022509 0.004826 4.66x >60 0.227642 >263x
HIGH WriteVtkStructuredPoints 0.026717 0.015289 1.75x >60 0.016252 >3,691x
HIGH SplitDataArrayByComponent 0.031228 0.002297 13.60x >60 0.198318 >302x
HIGH SplitDataArrayByTuple 0.055733 0.001667 33.43x >60 0.102487 >585x
MEDIUM ComputeMomentInvariants2D 0.001834 0.001560 1.18x 13.974384 0.012929 1,080.86x
MEDIUM CreateFeatureArrayFromElementArray 0.204728 0.026567 7.71x >60 0.251625 >238.45x
MEDIUM ExtractComponentAsArray 0.055706 0.031082 1.79x >60 0.192867 >311.10x
MEDIUM ConvertData 0.005581 0.005187 1.08x >60 0.206812 >290.12x
MEDIUM GroupMicroTextureRegions 0.015163 0.003478 4.36x >60 0.101423 >591.58x
MEDIUM ComputeBoundaryElementFractions 0.013681 0.008264 1.66x 51.947201 0.159685 325.31x
MEDIUM ComputeQuaternionConjugate 0.008203 0.007182 1.14x >60 0.128279 >467.73x
MEDIUM ReadBinaryCTNorthstar 0.018764 0.007421 2.53x >60 0.036908 >1,625.66x
MEDIUM ReadCSVFile 1.126726 1.101959 1.02x >60 1.177329 >50.96x
MEDIUM ReadVtkStructuredPoints 0.300159 0.265677 1.13x >60 0.298817 >200.79x
MEDIUM WriteINLFile 7.112353 7.050428 1.01x >60 7.331228 >8.18x
MEDIUM WriteLosAlamosFFT 1.727152 1.578432 1.09x >60 2.181956 >27.50x

HIGH and MEDIUM benchmarks use 8,000,000 cells (200³) except the 2D-only tests (2048²), the generated Channel5 reader dataset (8,000 × 1,000), and CSV's 8,000,000 rows. Figures are medians of five execute-only runs for the MEDIUM batches and repeated runs for HIGH where practical; > values are conservative timeout bounds. Every listed filter passed its normal affected suite and hidden large benchmark in both configurations.

Additional 200³ execute-only OOC benchmarks

Group Filter Before (s) After (s) Speedup
Groups B–E ComputeBoundaryCells 6.69 0.25 27x
Groups B–E ComputeSurfaceFeatures 4.01 0.28 14x
Groups B–E ComputeFeatureNeighbors 8.93 0.81 11x
Groups B–E ComputeSurfaceAreaToVolume 8.59 0.24 36x
Groups B–E BadDataNeighborOrientationCheck 97.1 5.25 18x
Groups B–E ErodeDilateBadData 25.09 3.80 7x
Groups B–E ErodeDilateCoordinationNumber 12.43 2.30 5x
Groups B–E ErodeDilateMask 6.43 0.40 16x
Groups B–E ReplaceElementAttrsWithNeighborValues 6.05 4.00 1.5x
Groups B–E NeighborOrientationCorrelation 67.94 5.70 12x
Groups B–E ScalarSegmentFeatures 708.3 1.77 400x
Groups B–E EBSDSegmentFeatures 972.6 2.10 463x
Groups B–E CAxisSegmentFeatures 824.1 1.39 593x
Groups B–E FillBadData 8.6 2.26 4x
Groups B–E IdentifySample 825.0 0.27 3056x
Groups B–E AlignSectionsMisorientation 32.89 0.80 41x
Groups B–E AlignSectionsMutualInformation 15.61 0.81 19x
Groups B–E AlignSectionsFeatureCentroid 8.41 0.39 22x
Groups B–E AlignSectionsListFilter 7.50 0.39 19x
Pipeline-critical ComputeFeatureCentroids 39.700 0.025 1,589x
Pipeline-critical RequireMinimumSizeFeatures 20.200 0.210 96x
Pipeline-critical ComputeIPFColors 1.940 0.090 21.5x
Pipeline-critical ComputeFeatureSizes 0.813 0.028 29x
Pipeline-critical ComputeFeatureReferenceMisorientations (AvgOri) 0.106 0.001 106x
Pipeline-critical ComputeFeatureReferenceMisorientations (EuclDist) 0.136 0.001 136x

Full-test wall-clock OOC benchmarks

Group Test Before (s) After (s) Speedup
Mesh generation QuickSurfaceMesh: Base 11.30 0.19 59x
Mesh generation QuickSurfaceMesh: Winding 22.70 0.22 103x
Mesh generation QuickSurfaceMesh: Problem Voxels 11.18 0.19 59x
Mesh generation QuickSurfaceMesh: Winding+PV 21.96 0.22 100x
Mesh generation SurfaceNets: Default 176 2.40 73x
Mesh generation SurfaceNets: Smoothing 224 2.62 85x
Mesh generation SurfaceNets: Winding 515 2.86 180x
Mesh generation SurfaceNets: Winding Smoothing 416 3.22 129x
OrientationAnalysis ComputeFeatureReferenceCAxisMisorientations 196 5.4 36x
OrientationAnalysis ComputeEuclideanDistMap 116 1.1 105x
GBCD ComputeGBCDPoleFigure 833 (fail) 2.4 350x
GBCD ComputeGBCD 1500 (timeout) ~10 150x
GBCD WriteGBCDGMTFile 162 (fail) 6.0 27x
GBCD ComputeGBCDMetricBased 38.1 28.9 1.3x
GBCD WriteGBCDTriangleData 23.5 19.2 1.2x
HDF5 / pole figure WritePoleFigure (3 tests) 4500 (timeout) 11.7 385x
HDF5 / pole figure ReadH5EspritData (3 tests) 2060 (timeout) 6.8 303x
HDF5 / pole figure ReadHDF5Dataset 1500 (timeout) 6.7 224x
Additional ReadRawBinary (Case1) 1076 29 37x
Additional ComputeGBCDPoleFigure 853 0.9 948x
Additional DBSCAN 3D 653 12 54x
Additional AlignSectionsMisorientation Pipeline 635 5.9 107x
Additional ReadH5Ebsd 463 2.1 220x
Additional ReadCtfData 231 0.25 924x
Additional AppendImageGeometry 469 113 4.2x
Additional ComputeFeatureClustering 203 77 2.6x
Additional ComputeTwinBoundaries 179 44 4x
Additional MergeTwins 67 1.8 37x
Additional ComputeKMedoids 74 13 5.7x
Additional CropImageGeometry (X) 27 2.6 10x
Additional WriteAvizoRectilinear 22.8 2.3 10x
Additional WriteAvizoUniform 22.3 2.0 11x

Geometry / Mesh / Phase Filters

Filter Before After Note
ApplyTransformationToGeometry (trilinear, CT_align 1.97 B-voxel) 133s 20s ~6.6x; via ImageRotationUtilities slab cache
ComputeTriangleAreas (CT_align mesh) 26s <1s ~26x
ComputeFeaturePhases (748,800 cells, disk-backed) 11.7s 35ms feature-level vectors + chunked reads
ComputeGBPDMetricBased 20.5s 6.3s ~3.3x; feature/ensemble caching
ExtractInternalSurfacesFromTriangleGeometry ~6.4x less triangle-side memory (bitset + popcount)

Part 4 — Test infrastructure

  • Comparison functions rewritten for chunked bulk I/O (UnitTestCommon.hpp): CompareDataArrays, CompareDataArraysByComponent, CompareArrays, CompareFloatArraysWithNans stream both arrays in 40K-element chunks via copyIntoBuffer instead of per-element operator[] (per-element access on OOC arrays is pathologically slow).
  • New store-type helpers: ExpectedStoreType() (derives the expected StoreType from the active DataStorageMode + whether an OOC manager is registered) and RequireExpectedStoreType().
  • PreferencesSentinel takes a DataStorageMode and restores the original preferences on destruction.
  • TestFileSentinel reference-counts archive extraction via per-process holder files, so parallel test runs don't delete shared decompressed data prematurely.
  • LoadDataStructure test helper calls DREAM3D::LoadDataStructure(path) directly.
  • New SegmentFeaturesTestUtils.hpp (~638 lines): shared builders/verifiers for the SegmentFeatures family.
  • Dual-path testing: ForceOocAlgorithmGuard + GENERATE(from_range(k_ForceOocTestValues)) runs each case in both in-core and forced-OOC modes — adopted by 23 plugin test files (16 SimplnxCore, 7 OrientationAnalysis).
  • 8 new top-level tests in test/: DataStoreFormatResolverTest, DataStorageModeMigrationTest, Dream3dLoadingApiTest, EmptyStringStoreTest, ExtentTest, MemoryBudgetManagerTest, MemorySafetyTest, IParallelAlgorithmTest.
  • RotateSampleRefFrame / RotateEulerRefFrame test paths use slab/chunked bulk I/O.

Part 5 — Build system

  • OOC is a runtime capability — it is selected entirely by the registered IO manager; there is no compile-time OOC switch. cmake/SimplnxConfig.hpp.in is a generated PUBLIC, ODR-safe config header.
  • SIMPLNX_TEST_ALGORITHM_PATH cache option (default 0): 0=Both, 1=OOC-only, 2=InCore-only; plumbed into every plugin test as a compile definition (cmake/Plugin.cmake). An in-core build can validate both algorithm paths (forcing the Scanline path against in-core data still runs correctly and fast).
  • SIMPLNX_UNIT_TEST_TARGETS global propertycreate_simplnx_plugin_unit_test records each test target so consumer (add_subdirectory) builds can attach extra sources/settings.
  • zlib as a direct vcpkg dependency — the OOC layer compiled into consumers uses it directly for parallel deflate-chunk decompression off the global HDF5 mutex (and UnitTestCommon uses it for the in-house tar.gz extractor).
  • /bigobj for the MSVC build of Dream3dIO.cpp (exceeds the COMDAT limit / C1128 in Debug).
  • New core headers/sources registered in CMake (Extent, EmptyStringStore, IDataStoreFormatResolver, InMemoryFormatResolver, MemoryBudgetManager, AlgorithmDispatch, SliceBufferedTransfer, UnionFind, IdentifySampleCommon).

Part 6 — Documentation

  • 48 filter docs updated under src/Plugins/*/docs/ (27 SimplnxCore, 21 OrientationAnalysis; ~+1,177 lines), each adding an ## Algorithm section with ### Performance and paired In-Core / Out-of-Core subsections that explain the dual implementation, memory footprint, and chunk/slab streaming strategy. No docs deleted.

Part 7 — Test data archives

Three download_test_data() entries added:

  • fill_bad_data_exemplars.tar.gz (SimplnxCore)
  • identify_sample_exemplars.tar.gz (SimplnxCore)
  • segment_features_exemplars.tar.gz (referenced by both SimplnxCore and OrientationAnalysis)

No existing archive entries were removed.


Related PR

  • BlueQuartzSoftware/DREAM3DNX#1121 — DREAM3D-NX OOC visualization architecture; consumes the runtime resolver/loader APIs added here and depends on this PR merging first.

Test Plan

  • In-core build (SIMPLNX_TEST_ALGORITHM_PATH=2) passes
  • Out-of-core build (SIMPLNX_TEST_ALGORITHM_PATH=1) passes
  • Both algorithm paths (SIMPLNX_TEST_ALGORITHM_PATH=0) pass
  • All optimized filters produce identical results on both algorithm paths
  • In-core performance verified: no regression on the core-utility changes (CopyData, AppendData, mirror swaps)

@joeykleingers joeykleingers force-pushed the worktree-ooc-architecture-rewrite branch from b4ef97f to 99b49ed Compare March 24, 2026 18:13
@joeykleingers joeykleingers force-pushed the worktree-ooc-architecture-rewrite branch 2 times, most recently from b4ef97f to bb09048 Compare March 24, 2026 18:51
@joeykleingers joeykleingers force-pushed the worktree-ooc-architecture-rewrite branch 4 times, most recently from 102c436 to b4c1358 Compare April 2, 2026 00:55
@joeykleingers joeykleingers changed the title WIP: OOC architecture rewrite — new bulk I/O API, SimplnxOoc plugin, and filter optimizations ENH: OOC architecture rewrite — new bulk I/O API and infrastructure Apr 2, 2026
@joeykleingers joeykleingers force-pushed the worktree-ooc-architecture-rewrite branch 6 times, most recently from 2bd614a to 110c054 Compare April 8, 2026 17:41
@joeykleingers joeykleingers changed the title ENH: OOC architecture rewrite — new bulk I/O API and infrastructure WIP: ENH: OOC architecture rewrite — new bulk I/O API and infrastructure Apr 8, 2026
@joeykleingers joeykleingers force-pushed the worktree-ooc-architecture-rewrite branch 4 times, most recently from 35aecd0 to 3a88bbf Compare April 16, 2026 13:03
@joeykleingers joeykleingers force-pushed the worktree-ooc-architecture-rewrite branch from bdfed87 to 6fbfc8d Compare April 27, 2026 18:18
…uresDirect for OOC dispatch

Prepares the RemoveFlaggedFeatures algorithm for OOC dispatch by renaming the
existing in-core implementation to RemoveFlaggedFeaturesDirect. No logic
changes; the InputValues struct and enum are unchanged. A thin
RemoveFlaggedFeatures dispatcher plus an OOC-optimized
RemoveFlaggedFeaturesScanline variant will be added in a follow-up commit.
…anline dispatch

Adds a thin RemoveFlaggedFeatures dispatcher plus a RemoveFlaggedFeaturesScanline
algorithm that eliminates all per-voxel operator[]/copyTuple access on the
(potentially out-of-core) FeatureIds array and its companion cell arrays:

- The neighbor-vote pass (IdentifyNeighbors equivalent) reads FeatureIds through
  a 3-slice rolling window (copyIntoBuffer), matching ComputeBoundaryCellsScanline's
  approach, instead of random single-element reads whose +/-Z offset is a full
  Z-slice away.
- The data-transfer pass (FindVoxelArrays equivalent) reuses the shared
  SliceBufferedTransfer utility to copy winning-neighbor data into every removed
  voxel for FeatureIds and all companion arrays, one Z-slice at a time, instead of
  per-voxel copyTuple calls.
- FlagFeatures is rewritten as a chunked bulk copyIntoBuffer/copyFromBuffer scan
  instead of per-voxel operator[] read/write.

The per-voxel neighbor-vote mapping remains a single O(n_cells) std::vector<int64>
(documented in RemoveFlaggedFeaturesScanline.hpp): the vote pass must run to
completion across the whole volume, strictly read-only, before any voxel is
written, to preserve the Direct algorithm's exact convergence and tie-breaking
behavior. This buffer is plain heap memory, not an OOC store, so it does not
itself cause chunk thrashing.

RemoveFlaggedFeaturesTest.cpp now runs its three execution-based TEST_CASEs
through both the in-core and forced-OOC algorithm paths via
ForceOocAlgorithmGuard + GENERATE(from_range(k_ForceOocTestValues)).
Track the observed FeatureIds range while streaming image and rectilinear-grid chunks, avoiding a separate full-array OOC scan while preserving validation errors.

Signed-off-by: Joey Kleingers <joey.kleingers@bluequartz.net>
This change introduces storage-aware execution for data-intensive filters, preserving direct contiguous access for in-memory arrays while using bounded bulk transfers for disk-backed stores. It also converts histogram modal analysis and additional filter algorithms to chunked I/O and adds targeted correctness and large OOC benchmark coverage. 58 files changed, +8,494 / -2,103 lines.

================================================================================
1. Storage-aware direct and scanline algorithms
================================================================================
Files:
- SimplnxCore/CMakeLists.txt
- ComputeBoundingBoxStats{,Direct,Scanline}.*
- ComputeCoordinateThreshold{,Direct,Scanline}.*
- ComputeFeatureBounds{,Direct,Scanline}.*
- ComputeLargestCrossSections{,Direct,Scanline}.*
- CreateColorMap{,Direct,Scanline}.*
- PartitionGeometry{,Direct,Scanline}.*

Route each algorithm through storage-aware dispatch based on its participating arrays. Direct implementations retain or accelerate parallel contiguous-store processing for in-memory data, while scanline implementations use fixed-size row, plane, or chunk buffers for sequential out-of-core access.

Keep scratch storage independent of cell count for coordinate masks, feature bounds, cross sections, color generation, and geometry partitioning. Compute exact bounding-box frequency statistics with bounded reads and temporary external merge sorting instead of cell-sized in-memory collections.

================================================================================
2. Bounded histogram and modal processing
================================================================================
Files:
- ComputeArrayHistogram.cpp
- ComputeArrayHistogram.hpp

Stream masked and unmasked inputs through explicit range and binning passes using fixed-size buffers. Preserve direct modal calculation for in-memory stores and use temporary sorted runs plus bounded merge passes for out-of-core mode detection, including all-distinct inputs.

Write bin ranges and counts in bulk, retain overflow reporting, and add throttled progress and cancellation checks throughout the multi-pass work.

================================================================================
3. Chunked bulk-I/O conversions
================================================================================
Files:
- ReadChannel5Data.*
- CombineAttributeArrays.*
- ComputeDifferencesMap.*
- ComputeFeatureRect.cpp
- ExtractFeatureBoundaries2D.cpp

Replace per-element datastore traffic with bounded contiguous transfers. Chunk Channel 5 field and compatibility-array writes, combine and normalize attribute arrays through reusable buffers, stream difference-map and feature-rectangle inputs, and detect 2D feature boundaries with rolling row buffers.

Propagate bulk-transfer failures and add progress and cancellation checks at chunk boundaries without materializing full cell arrays.

================================================================================
4. Correctness and OOC benchmark coverage
================================================================================
Files:
- OrientationAnalysis/test/ReadChannel5DataTest.cpp
- SimplnxCore/test/*Test.cpp for the affected filters

Add hidden large-data OOC benchmarks that construct disk-backed inputs with bulk writes and validate analytical output values, ranges, colors, geometry, and feature IDs. Extend focused coverage for normalization, masked reads across chunk boundaries, all-distinct modal values, coordinate-threshold chunk boundaries, and both storage-dispatched paths.

================================================================================
Verification
================================================================================
- git diff --cached --check
- Build and tests not run; this is a history-only squash.
@joeykleingers joeykleingers force-pushed the worktree-ooc-architecture-rewrite branch from c6bb7fe to ee6b370 Compare July 13, 2026 18:29
joeykleingers and others added 5 commits July 13, 2026 15:49
Optimize six OrientationAnalysis and SimplnxCore filters for their
backing datastore. Use bounded bulk I/O for out-of-core arrays and
contiguous-memory execution where a direct path is beneficial. Add
large-volume coverage for both forced algorithm paths.
18 files changed, +2458 / -365 lines.

================================================================================
1. Bounded out-of-core algorithms
================================================================================
Files:
* OrientationAnalysis: ComputeFZQuaternions, ComputeMisorientations
* SimplnxCore: ComputeFeaturePhasesBinary, ComputeVectorColors,
  ConditionalSetValue, ConvertColorToGrayScale

Process cell-level arrays through reusable fixed-size buffers and bulk
datastore transfers instead of per-tuple out-of-core access. Preserve
filter semantics for masks, phase lookups, feature assignment, value
replacement, and grayscale conversion while propagating transfer
errors. Add chunk-level cancellation and progress reporting, and cache
small lookup data or feature-indexed output state where appropriate.

================================================================================
2. Contiguous in-memory paths
================================================================================
Files:
* ComputeFZQuaternions
* ConditionalSetValue
* ConvertColorToGrayScale

Dispatch compatible in-memory stores to direct implementations that use
contiguous pointers and parallel ranges. Retain abstract-store fallbacks
so forced direct execution remains testable on non-contiguous stores,
and precompute reusable phase operations outside tuple loops.

================================================================================
3. Large-volume dispatch coverage
================================================================================
Files:
* ComputeFZQuaternionsTest.cpp
* ComputeMisorientationsTest.cpp
* ComputeFeaturePhasesBinaryTest.cpp
* ComputeVectorColorsTest.cpp
* ConditionalSetValueTest.cpp
* ConvertColorToGrayScaleTest.cpp

Add hidden 200x200x200 OOC benchmarks that exercise both forced
algorithm selections. Construct inputs and validate complete outputs
through bounded slice buffers while checking tuple shapes, component
counts, masks, and expected datastore types.

================================================================================
Verification
================================================================================
* git diff --cached --check
* Build and tests not run; this is a history-only squash.

Signed-off-by: Joey Kleingers <joey.kleingers@bluequartz.net>
…e type

Adds a virtual getPlannedStoreType() to IDataStore that returns the store type
an array will have once it is materialized. The default returns getStoreType();
EmptyDataStore overrides it to report InMemory or OutOfCore based on the
intended data format recorded during preflight. This lets callers reflect the
eventual backing of a preflight-only placeholder array without dispatching on
the placeholder's element type.

Signed-off-by: Jessica Marquis <jessica.marquis@bluequartz.net>
Optimize eight OrientationAnalysis and SimplnxCore filters for their
backing datastore. Dispatch contiguous stores to direct implementations
and stream disk-backed stores through bounded bulk transfers. Add
large-volume coverage for both forced algorithm paths.
25 files changed, +3479 / -341 lines.

================================================================================
1. Storage-aware algorithm execution
================================================================================
Files:
* OrientationAnalysis: ConvertQuaternion, WriteStatsGenOdfAngleFile
* SimplnxCore: AddBadData, ChangeAngleRepresentation,
  ComputeCoordinatesImageGeom, SplitDataArrayByComponent,
  SplitDataArrayByTuple, WriteVtkStructuredPoints

Use direct contiguous pointers and parallel ranges for compatible
in-memory stores. Route out-of-core and forced scanline execution through
fixed-size buffers, bulk datastore reads and writes, chunk-level
cancellation, progress reporting, and transfer-error propagation.
Retain bounded fallbacks when a forced direct path receives a
non-contiguous store.

================================================================================
2. Filter behavior and writer compatibility
================================================================================
Files:
* AddBadData.cpp
* SplitDataArrayByComponent.cpp
* SplitDataArrayByTuple.cpp
* WriteStatsGenOdfAngleFile.cpp
* WriteVtkStructuredPoints.cpp

Preserve seeded boundary and Poisson draw order while updating only
selected tuples. Copy component and N-D tuple splits in row-major chunks
without materializing full outputs. Stream phase-angle and VTK ASCII or
binary payloads with bounded memory, endian conversion, explicit file
errors, and compatibility helper APIs.

================================================================================
3. Large-volume dispatch coverage
================================================================================
Files:
* OrientationAnalysis ConvertQuaternion and StatsGen ODF tests
* SimplnxCore algorithm tests and test registration

Add 200x200x200 OOC benchmarks for all eight filters and exercise both
forced algorithm selections. Populate and validate data through bounded
slice buffers, check complete array results and file payloads, and
register the new VTK structured-points test.

================================================================================
Verification
================================================================================
* git diff --cached --check
* Build and tests not run; this is a history-only squash.

Signed-off-by: Joey Kleingers <joey.kleingers@bluequartz.net>
Replace element-wise datastore access in six filters with bounded bulk transfers
and dispatch-backed direct paths where applicable. Cache feature-level data for
microtexture grouping, add cancellation and progress reporting, and retain
direct parallel execution for in-core stores. Add large OOC benchmarks that
validate both forced algorithm paths. 18 files changed, +1769 / -279 lines.

================================================================================
1. Bounded SimplnxCore filter transfers
================================================================================
Files: ComputeBoundaryElementFractions, CreateFeatureArrayFromElementArray,
ExtractComponentAsArray, ComputeMomentInvariants2D, and ConvertData algorithms.

Stream cell and value arrays through fixed-size copyIntoBuffer and
copyFromBuffer transfers instead of per-element datastore access. Dispatch
ConvertData, ExtractComponentAsArray, and ComputeMomentInvariants2D between
direct in-memory implementations and scanline OOC implementations while
preserving type conversion, extraction, reduction, and moment calculations.
Propagate bulk-I/O errors and report cancellable progress at chunk boundaries.

================================================================================
2. Cached microtexture grouping data
================================================================================
Files: GroupMicroTextureRegions.cpp and GroupMicroTextureRegions.hpp.

Cache feature phases, parent IDs, crystal structures, quaternions, and volumes
before grouping so random feature access remains in memory. Perform final cell
parent remapping with bounded bulk transfers, keep randomized parent IDs in the
cache until writeback, and check cancellation during grouping and remapping.

================================================================================
3. Forced-path OOC benchmark coverage
================================================================================
Files: ComputeBoundaryElementFractionsTest.cpp,
ComputeMomentInvariants2DTest.cpp, ConvertDataTest.cpp,
CreateFeatureArrayFromElementArrayTest.cpp,
ExtractComponentAsArrayTest.cpp, and GroupMicroTextureRegionsTest.cpp.

Add large deterministic fixtures under the hidden OOC benchmark tag. Exercise
both direct and forced-OOC algorithm dispatch, require the expected datastore
type, and validate complete analytical outputs for fractions, moments,
conversions, feature values, component transfers, and parent-ID remapping.

Verification: Tests were not run as part of this history-only squash.
Convert large array imports, exports, and quaternion conjugation to bounded
bulk I/O while retaining direct in-core paths for hot loops. Harden
cancellation, error propagation, large-file offsets, VTK token parsing, CSV
buffer flushing, and deferred legacy string-array creation. Add deterministic
large OOC benchmarks covering direct and forced dispatch paths. 24 files
changed, +2272 / -447 lines.

================================================================================
1. Storage-aware computation and export
================================================================================
Files: ComputeQuaternionConjugate algorithms and CMake registration,
WriteINLFile.cpp/.hpp, and WriteLosAlamosFFT.cpp/.hpp.

Split quaternion conjugation into a parallel direct implementation and a
fixed-capacity scanline implementation selected by datastore-aware dispatch.
Stream INL and Los Alamos FFT inputs in bounded tuple chunks for disk-backed
arrays while preserving contiguous direct access for RAM-backed arrays. Buffer
formatted output where appropriate, retain coordinate and material metadata
semantics, report progress, honor cancellation, and return file-write failures.

================================================================================
2. Bounded import and parsing paths
================================================================================
Files: ReadBinaryCTNorthstar.cpp, ReadCSVFile.cpp,
ReadVtkStructuredPoints.cpp/.hpp, FileUtilities.cpp/.hpp, and Dream3dIO.cpp.

Bulk-initialize and populate Northstar density rows with checked large-file
seeks. Buffer numeric CSV columns for contiguous datastore writes while
preserving direct in-core and string assignment paths, flushing partial data on
completion, cancellation, and parse errors. Replace VTK element-wise parsing
with bounded ASCII and binary readers that preserve section boundaries, validate
truncation and token limits, byte-swap binary chunks, and support vector arrays.
Use empty legacy string stores during deferred metadata import.

================================================================================
3. Forced-path OOC benchmark coverage
================================================================================
Files: ComputeQuaternionConjugateTest.cpp, WriteINLFileTest.cpp,
ReadBinaryCTNorthstarTest.cpp, ReadCSVFileTest.cpp,
ReadVtkStructuredPointsTest.cpp, and WriteLosAlamosFFTTest.cpp.

Add large deterministic fixtures under the hidden OOC benchmark tag. Exercise
both direct and forced-OOC algorithm paths, require expected datastore types,
and validate complete quaternion, density, CSV, VTK, INL, and FFT outputs while
checking input preservation and temporary-file cleanup.

Verification: Builds and tests were not run as part of this history-only squash.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants