Move the processing code under pipeline/
Preparing to merge this repository into a combined astrophotography repo. session-scripts/ becomes pipeline/ because the scripts import layout.py from their own directory and must stay together, and because 'pipeline' says what it is rather than how it came about. observing/ stays at the top level: observing plans are not processing code.
This commit is contained in:
parent
653ca103cd
commit
c6299f41ab
53 changed files with 0 additions and 0 deletions
124
pipeline/restructure.py
Normal file
124
pipeline/restructure.py
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
"""Reorganise the session directory so a file's kind is obvious from where it sits.
|
||||
|
||||
Placement is decided by filename rules rather than by hand, so the same layout
|
||||
can be reproduced for any other session. Dry run by default; --apply to move.
|
||||
|
||||
raw/ exactly what iTelescope delivered: the zips and jpegs
|
||||
calibrated/ the uncompressed calibrated subs
|
||||
stacks/masters/ per-filter registered, plate-solved masters
|
||||
stacks/original/ the alignment-only baseline stacks
|
||||
final/ the four deliverable renderings + the comparison
|
||||
renderings/ other finished images (LRGB, HDR, annotated, starless)
|
||||
science/figures/ analysis plots
|
||||
science/catalogues/ measured tables (CSV)
|
||||
science/data/ models, masks and derived quantities
|
||||
science/notes/ the analysis write-ups
|
||||
intermediates/ caches and scratch that a re-run can regenerate
|
||||
"""
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
ROOT = r"C:\Users\lhorrocks-barlow\Downloads\NGC5128\20260721"
|
||||
STACKED = os.path.join(ROOT, "stacked")
|
||||
APPLY = "--apply" in sys.argv
|
||||
|
||||
DIRS = ["raw", "calibrated", "stacks/masters", "stacks/original", "final",
|
||||
"renderings", "science/figures", "science/catalogues", "science/data",
|
||||
"science/notes", "intermediates"]
|
||||
|
||||
|
||||
def destination(name, from_stacked):
|
||||
"""Where a file belongs, decided by its name alone."""
|
||||
low = name.lower()
|
||||
if not from_stacked:
|
||||
if low.endswith(".zip"):
|
||||
return "raw"
|
||||
if low.startswith("jpeg-") and low.endswith(".jpg"):
|
||||
return "raw"
|
||||
if low.startswith("calibrated-") and low.endswith((".fit", ".tif")):
|
||||
return "calibrated"
|
||||
return None
|
||||
|
||||
if name.startswith("_"):
|
||||
return "intermediates"
|
||||
if name.startswith("master-") and low.endswith(".fit"):
|
||||
return "stacks/masters"
|
||||
if name.startswith("notes-") and low.endswith(".md"):
|
||||
return "science/notes"
|
||||
if low.endswith(".csv"):
|
||||
return "science/catalogues"
|
||||
if name.startswith("sb-") and low.endswith((".fits", ".npy", ".txt")):
|
||||
return "science/data"
|
||||
if low.endswith(".png") and any(f"-{p}-" in name for p in ("gc", "sb", "mo")):
|
||||
return "science/figures"
|
||||
if name.startswith(("NGC5128-LRGB", "NGC5128-img-")):
|
||||
return "renderings"
|
||||
if name == "METHODS.md":
|
||||
return "."
|
||||
return None
|
||||
|
||||
|
||||
def plan():
|
||||
moves = []
|
||||
for name in sorted(os.listdir(ROOT)):
|
||||
path = os.path.join(ROOT, name)
|
||||
if os.path.isfile(path):
|
||||
d = destination(name, from_stacked=False)
|
||||
if d:
|
||||
moves.append((path, os.path.join(ROOT, d, name)))
|
||||
for name in sorted(os.listdir(STACKED)):
|
||||
path = os.path.join(STACKED, name)
|
||||
if name in ("final", "original", "scripts"):
|
||||
continue
|
||||
if os.path.isdir(path):
|
||||
if name.startswith("_"):
|
||||
moves.append((path, os.path.join(ROOT, "intermediates", name)))
|
||||
continue
|
||||
d = destination(name, from_stacked=True)
|
||||
if d:
|
||||
target = ROOT if d == "." else os.path.join(ROOT, d)
|
||||
moves.append((path, os.path.join(target, name)))
|
||||
moves.append((os.path.join(STACKED, "final"), os.path.join(ROOT, "final")))
|
||||
moves.append((os.path.join(STACKED, "original"),
|
||||
os.path.join(ROOT, "stacks", "original")))
|
||||
return moves
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
moves = plan()
|
||||
counts = {}
|
||||
for src, dst in moves:
|
||||
rel = os.path.relpath(os.path.dirname(dst), ROOT)
|
||||
counts[rel] = counts.get(rel, 0) + 1
|
||||
print(f"{len(moves)} moves\n")
|
||||
for d in sorted(counts):
|
||||
print(f" {d + '/':24s} {counts[d]:3d}")
|
||||
|
||||
unplaced = []
|
||||
for name in sorted(os.listdir(ROOT)):
|
||||
if os.path.isfile(os.path.join(ROOT, name)) and \
|
||||
not destination(name, False):
|
||||
unplaced.append(name)
|
||||
for name in sorted(os.listdir(STACKED)):
|
||||
p = os.path.join(STACKED, name)
|
||||
if os.path.isfile(p) and not destination(name, True):
|
||||
unplaced.append("stacked/" + name)
|
||||
if unplaced:
|
||||
print(f"\nNOT PLACED by any rule ({len(unplaced)}):")
|
||||
for n in unplaced:
|
||||
print(f" {n}")
|
||||
|
||||
if not APPLY:
|
||||
print("\nDRY RUN - nothing moved. Re-run with --apply")
|
||||
sys.exit(0)
|
||||
|
||||
for d in DIRS:
|
||||
os.makedirs(os.path.join(ROOT, d), exist_ok=True)
|
||||
for src, dst in moves:
|
||||
os.makedirs(os.path.dirname(dst), exist_ok=True)
|
||||
if os.path.exists(dst):
|
||||
print(f" SKIP (exists): {dst}")
|
||||
continue
|
||||
shutil.move(src, dst)
|
||||
print(f"moved {len(moves)} items")
|
||||
Loading…
Add table
Add a link
Reference in a new issue