midas-pipeline 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. midas_pipeline-0.1.0/PKG-INFO +94 -0
  2. midas_pipeline-0.1.0/README.md +50 -0
  3. midas_pipeline-0.1.0/midas_pipeline/__init__.py +82 -0
  4. midas_pipeline-0.1.0/midas_pipeline/__main__.py +11 -0
  5. midas_pipeline-0.1.0/midas_pipeline/_logging.py +47 -0
  6. midas_pipeline-0.1.0/midas_pipeline/cli.py +543 -0
  7. midas_pipeline-0.1.0/midas_pipeline/config.py +498 -0
  8. midas_pipeline-0.1.0/midas_pipeline/dispatch.py +72 -0
  9. midas_pipeline-0.1.0/midas_pipeline/em_refine.py +512 -0
  10. midas_pipeline-0.1.0/midas_pipeline/ff_shim.py +53 -0
  11. midas_pipeline-0.1.0/midas_pipeline/find_grains/__init__.py +510 -0
  12. midas_pipeline-0.1.0/midas_pipeline/find_grains/_cluster.py +443 -0
  13. midas_pipeline-0.1.0/midas_pipeline/find_grains/_consolidation_io.py +249 -0
  14. midas_pipeline-0.1.0/midas_pipeline/find_grains/_geom.py +103 -0
  15. midas_pipeline-0.1.0/midas_pipeline/find_grains/_patches.py +128 -0
  16. midas_pipeline-0.1.0/midas_pipeline/find_grains/_sinogen.py +318 -0
  17. midas_pipeline-0.1.0/midas_pipeline/find_grains/_sinogen_indexing.py +391 -0
  18. midas_pipeline-0.1.0/midas_pipeline/find_grains/_spot_association.py +170 -0
  19. midas_pipeline-0.1.0/midas_pipeline/find_grains/_voxel_keys.py +143 -0
  20. midas_pipeline-0.1.0/midas_pipeline/fuse.py +252 -0
  21. midas_pipeline-0.1.0/midas_pipeline/pipeline.py +254 -0
  22. midas_pipeline-0.1.0/midas_pipeline/potts.py +198 -0
  23. midas_pipeline-0.1.0/midas_pipeline/provenance.py +185 -0
  24. midas_pipeline-0.1.0/midas_pipeline/py.typed +0 -0
  25. midas_pipeline-0.1.0/midas_pipeline/recon/__init__.py +40 -0
  26. midas_pipeline-0.1.0/midas_pipeline/recon/fbp.py +188 -0
  27. midas_pipeline-0.1.0/midas_pipeline/recon/mlem.py +521 -0
  28. midas_pipeline-0.1.0/midas_pipeline/recon/voxelmap.py +136 -0
  29. midas_pipeline-0.1.0/midas_pipeline/results.py +237 -0
  30. midas_pipeline-0.1.0/midas_pipeline/seeding/__init__.py +57 -0
  31. midas_pipeline-0.1.0/midas_pipeline/seeding/align.py +180 -0
  32. midas_pipeline-0.1.0/midas_pipeline/seeding/ff_index.py +181 -0
  33. midas_pipeline-0.1.0/midas_pipeline/seeding/handoff.py +183 -0
  34. midas_pipeline-0.1.0/midas_pipeline/seeding/merge_all.py +115 -0
  35. midas_pipeline-0.1.0/midas_pipeline/stages/__init__.py +76 -0
  36. midas_pipeline-0.1.0/midas_pipeline/stages/_base.py +95 -0
  37. midas_pipeline-0.1.0/midas_pipeline/stages/_stub.py +41 -0
  38. midas_pipeline-0.1.0/midas_pipeline/stages/binning.py +210 -0
  39. midas_pipeline-0.1.0/midas_pipeline/stages/calc_radius.py +10 -0
  40. midas_pipeline-0.1.0/midas_pipeline/stages/consolidation.py +77 -0
  41. midas_pipeline-0.1.0/midas_pipeline/stages/consolidation_pf.py +354 -0
  42. midas_pipeline-0.1.0/midas_pipeline/stages/cross_det_merge.py +10 -0
  43. midas_pipeline-0.1.0/midas_pipeline/stages/em_refine.py +54 -0
  44. midas_pipeline-0.1.0/midas_pipeline/stages/find_grains_stage.py +88 -0
  45. midas_pipeline-0.1.0/midas_pipeline/stages/fuse.py +78 -0
  46. midas_pipeline-0.1.0/midas_pipeline/stages/global_powder.py +10 -0
  47. midas_pipeline-0.1.0/midas_pipeline/stages/hkl.py +10 -0
  48. midas_pipeline-0.1.0/midas_pipeline/stages/indexing.py +169 -0
  49. midas_pipeline-0.1.0/midas_pipeline/stages/merge_overlaps.py +10 -0
  50. midas_pipeline-0.1.0/midas_pipeline/stages/merge_scans.py +597 -0
  51. midas_pipeline-0.1.0/midas_pipeline/stages/peakfit.py +10 -0
  52. midas_pipeline-0.1.0/midas_pipeline/stages/potts.py +75 -0
  53. midas_pipeline-0.1.0/midas_pipeline/stages/process_grains.py +10 -0
  54. midas_pipeline-0.1.0/midas_pipeline/stages/reconstruct.py +191 -0
  55. midas_pipeline-0.1.0/midas_pipeline/stages/refinement.py +209 -0
  56. midas_pipeline-0.1.0/midas_pipeline/stages/seeding.py +154 -0
  57. midas_pipeline-0.1.0/midas_pipeline/stages/sinogen.py +68 -0
  58. midas_pipeline-0.1.0/midas_pipeline/stages/transforms.py +10 -0
  59. midas_pipeline-0.1.0/midas_pipeline/stages/zip_convert.py +10 -0
  60. midas_pipeline-0.1.0/midas_pipeline.egg-info/PKG-INFO +94 -0
  61. midas_pipeline-0.1.0/midas_pipeline.egg-info/SOURCES.txt +65 -0
  62. midas_pipeline-0.1.0/midas_pipeline.egg-info/dependency_links.txt +1 -0
  63. midas_pipeline-0.1.0/midas_pipeline.egg-info/entry_points.txt +2 -0
  64. midas_pipeline-0.1.0/midas_pipeline.egg-info/requires.txt +29 -0
  65. midas_pipeline-0.1.0/midas_pipeline.egg-info/top_level.txt +1 -0
  66. midas_pipeline-0.1.0/pyproject.toml +78 -0
  67. midas_pipeline-0.1.0/setup.cfg +4 -0
@@ -0,0 +1,94 @@
1
+ Metadata-Version: 2.4
2
+ Name: midas-pipeline
3
+ Version: 0.1.0
4
+ Summary: Unified MIDAS HEDM orchestrator. FF is the single-scan degeneracy of PF; one orchestrator, --scan-mode {ff,pf}.
5
+ Author-email: Hemant Sharma <hsharma@anl.gov>
6
+ License-Expression: BSD-3-Clause
7
+ Project-URL: Homepage, https://github.com/marinerhemant/MIDAS
8
+ Project-URL: Documentation, https://github.com/marinerhemant/MIDAS
9
+ Project-URL: Issues, https://github.com/marinerhemant/MIDAS/issues
10
+ Keywords: MIDAS,HEDM,FF-HEDM,PF-HEDM,scanning,diffraction,pipeline,PyTorch,multi-detector,crystallography,polycrystal,tomography
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Topic :: Scientific/Engineering :: Physics
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ Requires-Dist: numpy>=1.22
19
+ Requires-Dist: torch>=2.0
20
+ Requires-Dist: zarr<3,>=2.14
21
+ Requires-Dist: h5py>=3.7
22
+ Requires-Dist: tifffile
23
+ Requires-Dist: pandas>=1.5
24
+ Requires-Dist: midas-hkls>=0.2.0
25
+ Requires-Dist: midas-peakfit>=0.2.0
26
+ Requires-Dist: midas-transforms>=0.1.1
27
+ Requires-Dist: midas-index>=0.3.0
28
+ Requires-Dist: midas-fit-grain>=0.1.0a0
29
+ Requires-Dist: midas-process-grains>=0.1.0
30
+ Requires-Dist: midas-diffract>=0.1.0
31
+ Requires-Dist: midas-parsl-configs>=0.1.0
32
+ Requires-Dist: midas-stress>=0.6.0
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest>=7.0; extra == "dev"
35
+ Requires-Dist: pytest-cov; extra == "dev"
36
+ Requires-Dist: matplotlib; extra == "dev"
37
+ Requires-Dist: ipykernel; extra == "dev"
38
+ Provides-Extra: notebook
39
+ Requires-Dist: matplotlib; extra == "notebook"
40
+ Requires-Dist: ipykernel; extra == "notebook"
41
+ Requires-Dist: jupyter; extra == "notebook"
42
+ Provides-Extra: fast
43
+ Requires-Dist: numba>=0.56; extra == "fast"
44
+
45
+ # midas-pipeline
46
+
47
+ End-to-end MIDAS HEDM orchestrator. **FF is the single-scan degeneracy of PF.** One package, one CLI, two scan modes.
48
+
49
+ ## Status
50
+
51
+ **Alpha (0.1.0a0) — end-to-end PF and FF paths live.** The scanning indexer matches the C `IndexerScanningOMP` reference on its 1-voxel C-parity gate (seed identity, solution counts, voxel-center positions exact; orientation matrices within mrad-scale, the refiner closes the gap downstream). Cross-implementation perf optimization (~130s/voxel single-threaded today) is open work — see [project_midas_index_scanning_perf](https://github.com/marinerhemant/MIDAS/blob/master/packages/midas_pipeline/dev/perf-notes.md) tracking.
52
+
53
+ Stages call in-process Python kernels via `midas-index` / `midas-fit-grain` / `midas-transforms` / `midas-stress`. FF mode shells out to `python -m midas_index` and `python -m midas_fit_grain` (same kernels, subprocess for the FF parity-preserving pattern). No CUDA C; GPU is torch-only.
54
+
55
+ ## Install
56
+
57
+ ```bash
58
+ pip install -e packages/midas_pipeline
59
+ ```
60
+
61
+ ## CLI
62
+
63
+ ```bash
64
+ midas-pipeline run --scan-mode {ff,pf,auto} --params Parameters.txt --result rundir/
65
+ midas-pipeline status rundir/
66
+ midas-pipeline resume rundir/ --from <stage>
67
+ midas-pipeline reprocess rundir/
68
+ midas-pipeline inspect rundir/LayerNr_1/
69
+ midas-pipeline simulate --out simdir/ --params Parameters.txt
70
+ midas-pipeline seed --params ... --output UniqueOrientations.csv
71
+ ```
72
+
73
+ When `--scan-mode` is omitted (default `auto`), the CLI sniffs the parameter file: `nScans > 1` or presence of `BeamSize` / scanning keys → `pf`, otherwise `ff`. For PF mode, `--n-scans`, `--scan-step`, `--beam-size`, and `--scan-pos-tol` default to values in the params file (CLI flags override).
74
+
75
+ ## Coexistence with `midas-ff-pipeline`
76
+
77
+ The legacy `midas-ff-pipeline` console-script is preserved as an independent FF orchestrator (its own kernels, its own CLI). It is **not** deprecated by `midas-pipeline run --scan-mode ff` — both paths invoke the same `midas-index` / `midas-fit-grain` kernels under the hood, and both stay green on the FF parity gate. Pick whichever is more convenient for your workflow.
78
+
79
+ ## Architecture
80
+
81
+ See [`../../.claude/plans/for-pf-we-don-t-lovely-locket.md`](../../.claude/plans/for-pf-we-don-t-lovely-locket.md) for the long-form plan. Quick summary:
82
+
83
+ - **One orchestrator** with a mode-dependent `STAGE_ORDER`.
84
+ - **Shared kernel packages** (`midas-index`, `midas-fit-grain`, `midas-transforms`, etc.) extended in place; FF behavior preserved by parity gates.
85
+ - **PF-only modules** live inside `midas_pipeline` (`find_grains/`, `sinogen`, `recon/`, `fuse`, `potts`, `em_refine`, `seeding/`).
86
+ - **Differentiability + multi-device** mandatory on every new compute path (CPU / CUDA / MPS via torch).
87
+
88
+ ## Constraints
89
+
90
+ - No CUDA C; GPU support is torch-only.
91
+ - No deletions of legacy code in this effort.
92
+ - `midas-process-grains` is FF-only; PF consolidation is fresh pure-Python.
93
+ - `utils/calcMiso.py` is not imported by this package; all orientation math comes from `midas-stress`.
94
+ - `TOMO/midas_tomo_python.py` is imported in place, not relocated.
@@ -0,0 +1,50 @@
1
+ # midas-pipeline
2
+
3
+ End-to-end MIDAS HEDM orchestrator. **FF is the single-scan degeneracy of PF.** One package, one CLI, two scan modes.
4
+
5
+ ## Status
6
+
7
+ **Alpha (0.1.0a0) — end-to-end PF and FF paths live.** The scanning indexer matches the C `IndexerScanningOMP` reference on its 1-voxel C-parity gate (seed identity, solution counts, voxel-center positions exact; orientation matrices within mrad-scale, the refiner closes the gap downstream). Cross-implementation perf optimization (~130s/voxel single-threaded today) is open work — see [project_midas_index_scanning_perf](https://github.com/marinerhemant/MIDAS/blob/master/packages/midas_pipeline/dev/perf-notes.md) tracking.
8
+
9
+ Stages call in-process Python kernels via `midas-index` / `midas-fit-grain` / `midas-transforms` / `midas-stress`. FF mode shells out to `python -m midas_index` and `python -m midas_fit_grain` (same kernels, subprocess for the FF parity-preserving pattern). No CUDA C; GPU is torch-only.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ pip install -e packages/midas_pipeline
15
+ ```
16
+
17
+ ## CLI
18
+
19
+ ```bash
20
+ midas-pipeline run --scan-mode {ff,pf,auto} --params Parameters.txt --result rundir/
21
+ midas-pipeline status rundir/
22
+ midas-pipeline resume rundir/ --from <stage>
23
+ midas-pipeline reprocess rundir/
24
+ midas-pipeline inspect rundir/LayerNr_1/
25
+ midas-pipeline simulate --out simdir/ --params Parameters.txt
26
+ midas-pipeline seed --params ... --output UniqueOrientations.csv
27
+ ```
28
+
29
+ When `--scan-mode` is omitted (default `auto`), the CLI sniffs the parameter file: `nScans > 1` or presence of `BeamSize` / scanning keys → `pf`, otherwise `ff`. For PF mode, `--n-scans`, `--scan-step`, `--beam-size`, and `--scan-pos-tol` default to values in the params file (CLI flags override).
30
+
31
+ ## Coexistence with `midas-ff-pipeline`
32
+
33
+ The legacy `midas-ff-pipeline` console-script is preserved as an independent FF orchestrator (its own kernels, its own CLI). It is **not** deprecated by `midas-pipeline run --scan-mode ff` — both paths invoke the same `midas-index` / `midas-fit-grain` kernels under the hood, and both stay green on the FF parity gate. Pick whichever is more convenient for your workflow.
34
+
35
+ ## Architecture
36
+
37
+ See [`../../.claude/plans/for-pf-we-don-t-lovely-locket.md`](../../.claude/plans/for-pf-we-don-t-lovely-locket.md) for the long-form plan. Quick summary:
38
+
39
+ - **One orchestrator** with a mode-dependent `STAGE_ORDER`.
40
+ - **Shared kernel packages** (`midas-index`, `midas-fit-grain`, `midas-transforms`, etc.) extended in place; FF behavior preserved by parity gates.
41
+ - **PF-only modules** live inside `midas_pipeline` (`find_grains/`, `sinogen`, `recon/`, `fuse`, `potts`, `em_refine`, `seeding/`).
42
+ - **Differentiability + multi-device** mandatory on every new compute path (CPU / CUDA / MPS via torch).
43
+
44
+ ## Constraints
45
+
46
+ - No CUDA C; GPU support is torch-only.
47
+ - No deletions of legacy code in this effort.
48
+ - `midas-process-grains` is FF-only; PF consolidation is fresh pure-Python.
49
+ - `utils/calcMiso.py` is not imported by this package; all orientation math comes from `midas-stress`.
50
+ - `TOMO/midas_tomo_python.py` is imported in place, not relocated.
@@ -0,0 +1,82 @@
1
+ """midas-pipeline: Unified MIDAS HEDM orchestrator (FF + PF, single source).
2
+
3
+ FF is the single-scan degeneracy of PF: ``ScanGeometry.ff()`` produces
4
+ ``scan_mode='ff'`` with ``n_scans=1``; everything else is a regular PF
5
+ run with ``n_scans > 1``. One orchestrator, one CLI, two scan modes.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ __version__ = "0.1.0"
11
+
12
+ from .config import (
13
+ AlignMethod,
14
+ Device,
15
+ Dtype,
16
+ EMConfig,
17
+ FusionConfig,
18
+ LayerSelection,
19
+ MachineConfig,
20
+ PipelineConfig,
21
+ ProcessGrainsMode,
22
+ ReconConfig,
23
+ ReconMethod,
24
+ RefineLoss,
25
+ RefineMode,
26
+ RefinePositionMode,
27
+ RefineSolver,
28
+ RefinementConfig,
29
+ ResumeMode,
30
+ ScanGeometry,
31
+ ScanMode,
32
+ SeedingConfig,
33
+ SeedingMode,
34
+ SinoSource,
35
+ SinoType,
36
+ sniff_scan_mode_from_paramfile,
37
+ )
38
+ from .pipeline import Pipeline, all_stage_names, stage_order_for
39
+ from .results import (
40
+ LayerResult,
41
+ StageResult,
42
+ BinningResult,
43
+ CalcRadiusResult,
44
+ ConsolidationResult,
45
+ CrossDetMergeResult,
46
+ EMRefineResult,
47
+ FindGrainsResult,
48
+ FuseResult,
49
+ HKLResult,
50
+ IndexResult,
51
+ MergeOverlapsResult,
52
+ MergeScansResult,
53
+ PeakFitResult,
54
+ PottsResult,
55
+ ProcessGrainsResult,
56
+ ReconResult,
57
+ RefineResult,
58
+ SinogenResult,
59
+ TransformsResult,
60
+ )
61
+
62
+ __all__ = [
63
+ "__version__",
64
+ # config
65
+ "AlignMethod", "Device", "Dtype",
66
+ "EMConfig", "FusionConfig", "LayerSelection", "MachineConfig",
67
+ "PipelineConfig", "ProcessGrainsMode", "ReconConfig", "ReconMethod",
68
+ "RefineLoss", "RefineMode", "RefinePositionMode", "RefineSolver",
69
+ "RefinementConfig", "ResumeMode", "ScanGeometry", "ScanMode",
70
+ "SeedingConfig", "SeedingMode", "SinoSource", "SinoType",
71
+ "sniff_scan_mode_from_paramfile",
72
+ # pipeline
73
+ "Pipeline", "all_stage_names", "stage_order_for",
74
+ # results
75
+ "LayerResult", "StageResult",
76
+ "BinningResult", "CalcRadiusResult", "ConsolidationResult",
77
+ "CrossDetMergeResult", "EMRefineResult", "FindGrainsResult",
78
+ "FuseResult", "HKLResult", "IndexResult", "MergeOverlapsResult",
79
+ "MergeScansResult", "PeakFitResult", "PottsResult",
80
+ "ProcessGrainsResult", "ReconResult", "RefineResult",
81
+ "SinogenResult", "TransformsResult",
82
+ ]
@@ -0,0 +1,11 @@
1
+ """``python -m midas_pipeline`` entry point."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+
7
+ from .cli import main
8
+
9
+
10
+ if __name__ == "__main__":
11
+ sys.exit(main())
@@ -0,0 +1,47 @@
1
+ """Pipeline-wide logger + stage timer.
2
+
3
+ Single logger named ``midas_pipeline`` to keep child stage logs
4
+ co-located with the orchestrator's own.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import logging
10
+ import time
11
+ from contextlib import contextmanager
12
+ from typing import Iterator
13
+
14
+ LOG = logging.getLogger("midas_pipeline")
15
+
16
+
17
+ def configure_logging(level: int = logging.INFO) -> None:
18
+ """Idempotent root-logger setup. Safe to call from CLI or notebook."""
19
+ root = logging.getLogger("midas_pipeline")
20
+ if root.handlers:
21
+ root.setLevel(level)
22
+ return
23
+ handler = logging.StreamHandler()
24
+ handler.setFormatter(logging.Formatter(
25
+ "%(asctime)s [%(levelname)s] %(name)s: %(message)s",
26
+ datefmt="%H:%M:%S",
27
+ ))
28
+ root.addHandler(handler)
29
+ root.setLevel(level)
30
+ root.propagate = False
31
+
32
+
33
+ @contextmanager
34
+ def stage_timer(stage_name: str) -> Iterator[dict]:
35
+ """Time a stage and yield a dict that gets populated with start/end/duration."""
36
+ info: dict[str, float] = {"started_at": time.time()}
37
+ LOG.info("→ %s", stage_name)
38
+ try:
39
+ yield info
40
+ except Exception:
41
+ info["finished_at"] = time.time()
42
+ info["duration_s"] = info["finished_at"] - info["started_at"]
43
+ LOG.exception("✗ %s failed after %.2fs", stage_name, info["duration_s"])
44
+ raise
45
+ info["finished_at"] = time.time()
46
+ info["duration_s"] = info["finished_at"] - info["started_at"]
47
+ LOG.info("✓ %s — %.2fs", stage_name, info["duration_s"])