Commit 9ec1f817 authored by Vacaliuc, Bogdan's avatar Vacaliuc, Bogdan
Browse files

slides: add slide 6 — the ideal reduce() contract



Pseudocode of the unified back-end's top function signature plus
its typed value objects. Shows:

- Main function: reduce(workspace, configuration, direct_beam=None,
  output_dir=None, *, write_quicknxs=True, ...) -> ReducedRun.
  Inside: inspect → build_mrr_kwargs (one place) → MRR →
  ReducedRun.
- ReductionConfig dataclass (frozen): PixelRange typed ROIs, proper
  BinningType enum, AngleSource enum that kills the use_dangle
  inversion.
- ReducedRun value object: q, r, dr, dq numpy arrays + per-
  cross-section curves + DataInfo.
- "What this replaces" red callout enumerating six items removed
  by the contract.
- Two caller examples at bottom (quicknxsv2 GUI · mr_reduction
  autoreduce) showing that both hit the same function.

Supports Day-3 requirements document and Day-4 ticket drafting.

Co-Authored-By: default avatarClaude Opus 4.7 (1M context) <noreply@anthropic.com>
parent 0dc70d63
Loading
Loading
Loading
Loading
+221 KiB
Loading image diff...
+165 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080" width="1920" height="1080" font-family="Helvetica, Arial, sans-serif">
  <defs>
    <linearGradient id="headerGrad" x1="0" x2="0" y1="0" y2="1">
      <stop offset="0%" stop-color="#002E5D"/>
      <stop offset="100%" stop-color="#004B8D"/>
    </linearGradient>
    <linearGradient id="codeBg" x1="0" x2="0" y1="0" y2="1">
      <stop offset="0%" stop-color="#1E1E2E"/>
      <stop offset="100%" stop-color="#16162A"/>
    </linearGradient>
    <filter id="softShadow" x="-10%" y="-10%" width="120%" height="120%">
      <feGaussianBlur in="SourceAlpha" stdDeviation="2"/>
      <feOffset dx="1" dy="2" result="offset"/>
      <feComponentTransfer><feFuncA type="linear" slope="0.22"/></feComponentTransfer>
      <feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
    </filter>
    <marker id="arrowDark" viewBox="0 0 12 9" refX="11" refY="4.5" markerWidth="9" markerHeight="7" orient="auto">
      <path d="M 0 0 L 12 4.5 L 0 9 z" fill="#002E5D"/>
    </marker>
  </defs>

  <rect width="1920" height="1080" fill="#FAFAFA"/>

  <!-- Header -->
  <rect x="0" y="0" width="1920" height="100" fill="url(#headerGrad)"/>
  <text x="960" y="55" font-size="34" font-weight="700" fill="white" text-anchor="middle">The Ideal reduce() Contract</text>
  <text x="960" y="85" font-size="17" fill="#B8D4E8" text-anchor="middle">One function, shared by GUI and autoreduce — the structural fix for every silent default in slide 3</text>

  <!-- Subtitle -->
  <text x="40" y="140" font-size="16" fill="#2A2A2A">A single function signature on the unified back-end library.  Scientists and developers read it once; the two consumers cannot drift because</text>
  <text x="40" y="162" font-size="16" fill="#2A2A2A">they pass the same typed configuration through the same parameter-construction path.  Below: what the signature looks like and what's inside each type.</text>

  <!-- ============ Main code block (pseudocode contract) ============ -->
  <rect x="40" y="190" width="1120" height="610" rx="12" fill="url(#codeBg)" stroke="#002E5D" stroke-width="2" filter="url(#softShadow)"/>

  <!-- Code chrome - title bar -->
  <rect x="40" y="190" width="1120" height="32" rx="12" fill="#2A2A40"/>
  <rect x="40" y="210" width="1120" height="14" fill="#2A2A40"/>
  <circle cx="62" cy="206" r="6" fill="#FF5F57"/>
  <circle cx="82" cy="206" r="6" fill="#FEBC2E"/>
  <circle cx="102" cy="206" r="6" fill="#28C840"/>
  <text x="600" y="211" font-size="13" fill="#A0A0B8" text-anchor="middle" font-family="monospace">mr_core/reduce.py — public API</text>

  <!-- Code content -->
  <g font-family="monospace" font-size="15" fill="#E0E0E5">
    <text x="60" y="255"><tspan fill="#7FBAFF">from</tspan> mr_core.types <tspan fill="#7FBAFF">import</tspan> ReductionConfig, ReducedRun, MantidWorkspace</text>
    <text x="60" y="285"><tspan fill="#7FBAFF">def</tspan> <tspan fill="#FFB454" font-weight="700">reduce</tspan>(</text>
    <text x="60" y="310">    workspace:          MantidWorkspace,           <tspan fill="#7E9AB6"># one run, grouped by cross-section</tspan></text>
    <text x="60" y="335">    configuration:      ReductionConfig,           <tspan fill="#7E9AB6"># typed, immutable, explicit</tspan></text>
    <text x="60" y="360">    direct_beam:        Optional[DirectBeamRef] = <tspan fill="#FFB454">None</tspan>,</text>
    <text x="60" y="385">    output_dir:         Optional[Path]          = <tspan fill="#FFB454">None</tspan>,</text>
    <text x="60" y="410">    *,</text>
    <text x="60" y="435">    write_quicknxs:     <tspan fill="#FFB454">bool</tspan> = <tspan fill="#FFB454">True</tspan>,    <tspan fill="#7E9AB6"># legacy .dat</tspan></text>
    <text x="60" y="460">    write_orso:         <tspan fill="#FFB454">bool</tspan> = <tspan fill="#FFB454">True</tspan>,    <tspan fill="#7E9AB6"># .ort standard</tspan></text>
    <text x="60" y="485">    write_html_report:  <tspan fill="#FFB454">bool</tspan> = <tspan fill="#FFB454">True</tspan>,</text>
    <text x="60" y="510">) -> ReducedRun:</text>
    <text x="60" y="540">    <tspan fill="#9BBE8C">"""Reduce one run to reflectivity, writing artifacts if requested."""</tspan></text>

    <text x="60" y="580"><tspan fill="#9BBE8C">    # 1. Inspect the workspace (peak / background / low-res ROIs)</tspan></text>
    <text x="60" y="605">    info = inspect(workspace, configuration)</text>

    <text x="60" y="640"><tspan fill="#9BBE8C">    # 2. Build MRR kwargs ONE PLACE.  No default drift.</tspan></text>
    <text x="60" y="665">    kwargs = build_mrr_kwargs(configuration, info, direct_beam)</text>

    <text x="60" y="700"><tspan fill="#9BBE8C">    # 3. Invoke Mantid's MR algorithm</tspan></text>
    <text x="60" y="725">    reflectivity = MagnetismReflectometryReduction(**kwargs)</text>

    <text x="60" y="760"><tspan fill="#9BBE8C">    # 4. Wrap result in a typed value object</tspan></text>
    <text x="60" y="785">    <tspan fill="#7FBAFF">return</tspan> ReducedRun(reflectivity, info, configuration)</text>
  </g>

  <!-- ============ Right column: type definitions and callers ============ -->

  <!-- ReductionConfig box -->
  <g>
    <rect x="1180" y="190" width="700" height="215" rx="10" fill="#FFFFFF" stroke="#4A90C2" stroke-width="2" filter="url(#softShadow)"/>
    <rect x="1180" y="190" width="700" height="36" rx="10" fill="#4A90C2"/>
    <text x="1200" y="215" font-size="16" fill="white" font-weight="700" font-family="monospace">@dataclass(frozen=True)  class ReductionConfig</text>

    <g font-size="13" font-family="monospace" fill="#1F3A5F">
      <text x="1200" y="252">peak_roi:             <tspan fill="#8C3A00">PixelRange</tspan>           <tspan fill="#606060"># (min, max) inclusive</tspan></text>
      <text x="1200" y="272">bck_roi:              <tspan fill="#8C3A00">PixelRange</tspan></text>
      <text x="1200" y="292">low_res_roi:          <tspan fill="#8C3A00">PixelRange</tspan></text>
      <text x="1200" y="312">subtract_background:  <tspan fill="#8C3A00">bool</tspan></text>
      <text x="1200" y="332">tof_range:            <tspan fill="#8C3A00">tuple[float, float]</tspan></text>
      <text x="1200" y="352">q_step:               <tspan fill="#8C3A00">float</tspan>               <tspan fill="#606060"># negative = log</tspan></text>
      <text x="1200" y="372">binning:              <tspan fill="#8C3A00">BinningType</tspan>          <tspan fill="#606060"># proper enum</tspan></text>
      <text x="1200" y="392">angle_source:         <tspan fill="#8C3A00">AngleSource</tspan>          <tspan fill="#606060"># SANGLE | DANGLE</tspan></text>
    </g>
  </g>

  <!-- ReducedRun box -->
  <g>
    <rect x="1180" y="420" width="700" height="185" rx="10" fill="#FFFFFF" stroke="#6DA64F" stroke-width="2" filter="url(#softShadow)"/>
    <rect x="1180" y="420" width="700" height="36" rx="10" fill="#6DA64F"/>
    <text x="1200" y="445" font-size="16" fill="white" font-weight="700" font-family="monospace">class ReducedRun</text>

    <g font-size="13" font-family="monospace" fill="#1F3A1F">
      <text x="1200" y="482">q:                    <tspan fill="#8C3A00">np.ndarray</tspan>           <tspan fill="#606060"># Q values</tspan></text>
      <text x="1200" y="502">r:                    <tspan fill="#8C3A00">np.ndarray</tspan>           <tspan fill="#606060"># reflectivity</tspan></text>
      <text x="1200" y="522">dr:                   <tspan fill="#8C3A00">np.ndarray</tspan>           <tspan fill="#606060"># 1σ error</tspan></text>
      <text x="1200" y="542">dq:                   <tspan fill="#8C3A00">np.ndarray</tspan>           <tspan fill="#606060"># Q resolution</tspan></text>
      <text x="1200" y="562">cross_sections:       <tspan fill="#8C3A00">dict[str, Curve]</tspan>     <tspan fill="#606060"># per-polarization</tspan></text>
      <text x="1200" y="582">info:                 <tspan fill="#8C3A00">DataInfo</tspan>             <tspan fill="#606060"># peak/bg/angle</tspan></text>
    </g>
  </g>

  <!-- What this replaces -->
  <g>
    <rect x="1180" y="620" width="700" height="180" rx="10" fill="#FEF4EE" stroke="#E87722" stroke-width="2" stroke-dasharray="6 4"/>
    <text x="1200" y="650" font-size="16" font-weight="700" fill="#8C3A00">What this replaces</text>
    <g font-size="13" fill="#3E2C00">
      <text x="1210" y="678">✗  Two MRR call sites in data_set.py with different defaults</text>
      <text x="1210" y="698">✗  A third call site in mr_reduction.mr_reduction.py</text>
      <text x="1210" y="718">✗  Two local <tspan font-family="monospace">_as_ints()</tspan> helpers (the pixel off-by-one)</text>
      <text x="1210" y="738">✗  Three copies of the QuickNXS scaling formula (with/without +1.0)</text>
      <text x="1210" y="758">✗  Class-attribute globals on Configuration (immutable → no "global")</text>
      <text x="1210" y="778">✗  Silent type-drift between BinningType enum and int</text>
    </g>
  </g>

  <!-- ============ Two callers at bottom ============ -->
  <g>
    <rect x="40" y="820" width="900" height="200" rx="10" fill="#FFFFFF" stroke="#E87722" stroke-width="2" filter="url(#softShadow)"/>
    <rect x="40" y="820" width="900" height="36" rx="10" fill="#E87722"/>
    <text x="60" y="845" font-size="15" fill="white" font-weight="700">Caller #1 — quicknxsv2 GUI</text>

    <g font-size="13" font-family="monospace" fill="#2A2A2A">
      <text x="60" y="876"><tspan fill="#7FBAFF">def</tspan> on_reduce_clicked(<tspan fill="#B54F22">self</tspan>):</text>
      <text x="60" y="896">    config = ReductionConfig.from_ui(<tspan fill="#B54F22">self</tspan>.ui)   <tspan fill="#606060"># widget values → typed config</tspan></text>
      <text x="60" y="916">    result = mr_core.reduce(</text>
      <text x="60" y="936">        workspace   = <tspan fill="#B54F22">self</tspan>.active_workspace,</text>
      <text x="60" y="956">        configuration = config,</text>
      <text x="60" y="976">        direct_beam = <tspan fill="#B54F22">self</tspan>.matched_direct_beam,</text>
      <text x="60" y="996">    )</text>
    </g>
  </g>

  <g>
    <rect x="960" y="820" width="920" height="200" rx="10" fill="#FFFFFF" stroke="#6DA64F" stroke-width="2" filter="url(#softShadow)"/>
    <rect x="960" y="820" width="920" height="36" rx="10" fill="#6DA64F"/>
    <text x="980" y="845" font-size="15" fill="white" font-weight="700">Caller #2 — mr_reduction autoreduce</text>

    <g font-size="13" font-family="monospace" fill="#2A2A2A">
      <text x="980" y="876"><tspan fill="#7FBAFF">def</tspan> reduce_REF_M(file_path, output_dir, **form_opts):</text>
      <text x="980" y="896">    ws     = LoadEventNexus(file_path)</text>
      <text x="980" y="916">    config = ReductionConfig.from_dict(form_opts)  <tspan fill="#606060"># Flask form → typed config</tspan></text>
      <text x="980" y="936">    result = mr_core.reduce(</text>
      <text x="980" y="956">        workspace   = ws,</text>
      <text x="980" y="976">        configuration = config,</text>
      <text x="980" y="996">        output_dir  = output_dir,</text>
      <text x="980" y="1016">    )</text>
    </g>
  </g>

  <!-- Arrows from code block to callers showing flow -->
  <path d="M 580 800 L 580 820" stroke="#002E5D" stroke-width="2" marker-end="url(#arrowDark)"/>
  <path d="M 600 800 L 1400 820" stroke="#002E5D" stroke-width="2" marker-end="url(#arrowDark)" stroke-dasharray="0"/>

  <!-- Footer -->
  <rect x="0" y="1055" width="1920" height="25" fill="#001A35"/>
  <text x="40" y="1073" font-size="12" fill="#6A90B0">Corresponds to 11-technical-debt.md § Tier-2 (unified MRR parameter construction) · Day 3 stretch goal in the agenda</text>
  <text x="1880" y="1073" font-size="12" fill="#6A90B0" text-anchor="end">Reflectometry Hack-a-thon 2026 · slide 6 of 8</text>
</svg>