Commit cbeec47d authored by Vacaliuc, Bogdan's avatar Vacaliuc, Bogdan
Browse files

slides/5 and 5a: add Qt Signal lane; retitle 5a to "Qt Leakage"



Slide 5 (peak-drag-sequence): added a fifth swim-lane "Qt Signal"
between the "Qt GUI layer" and "Configuration / DataManager"
columns.  Step 2 (motion_notify_event / changeRegionValues) moved
into the new column, relieving the vertical pressure in the UI
lane and making the handoff from widget event → signal → config
extraction visible as a horizontal flow instead of a tight vertical
stack.

The "UI THREAD LOCKED · 1–10 s" red bar is now on the right edge of
the UI lane; the rotated label is placed in the Qt Signal lane
beside the bar so it does not overlap the graphic.  Arrows
redrawn for a cleaner L→R flow through all 5 lanes.

Slide 5a: title changed from "Where the Debt Accumulates" to
"Qt Leakage" per user.  Removed the in-slide reference to commit
aa32022 — the commit citation lives in the knowledge base
(12-parameter-propagation-and-qt-leakage.md §6) where it belongs.

Co-Authored-By: default avatarClaude Opus 4.7 (1M context) <noreply@anthropic.com>
parent 7a79dc7d
Loading
Loading
Loading
Loading
−927 B (157 KiB)
Loading image diff...
+106 −85
Original line number Diff line number Diff line
@@ -9,6 +9,10 @@
      <stop offset="0%" stop-color="#FFF3E6"/>
      <stop offset="100%" stop-color="#FEE4CB"/>
    </linearGradient>
    <linearGradient id="signalLane" x1="0" x2="0" y1="0" y2="1">
      <stop offset="0%" stop-color="#F6EEDA"/>
      <stop offset="100%" stop-color="#EEDFB9"/>
    </linearGradient>
    <linearGradient id="cfgLane" x1="0" x2="0" y1="0" y2="1">
      <stop offset="0%" stop-color="#FFF8E7"/>
      <stop offset="100%" stop-color="#FAEBC0"/>
@@ -43,122 +47,139 @@
  <text x="960" y="55" font-size="34" font-weight="700" fill="white" text-anchor="middle">A Peak Drag, Traced from Click to Plot</text>
  <text x="960" y="85" font-size="17" fill="#B8D4E8" text-anchor="middle">What happens in the 1–10 seconds between moving a peak line and seeing the new reflectivity</text>

  <!-- ─── Swim lanes ─── -->
  <rect x="40" y="130" width="280" height="830" rx="10" fill="url(#uiLane)" stroke="#E87722" stroke-width="2"/>
  <text x="180" y="162" font-size="18" font-weight="700" fill="#8C3A00" text-anchor="middle">Qt GUI layer</text>

  <rect x="330" y="130" width="480" height="830" rx="10" fill="url(#cfgLane)" stroke="#D2A000" stroke-width="2"/>
  <text x="570" y="162" font-size="18" font-weight="700" fill="#3A2C00" text-anchor="middle">Configuration / DataManager</text>

  <rect x="820" y="130" width="520" height="830" rx="10" fill="url(#reduxLane)" stroke="#4A90C2" stroke-width="2"/>
  <text x="1080" y="162" font-size="18" font-weight="700" fill="#002E5D" text-anchor="middle">Reduction back-end (runs on Qt thread!)</text>

  <rect x="1350" y="130" width="530" height="830" rx="10" fill="url(#mantidLane)" stroke="#6DA64F" stroke-width="2"/>
  <text x="1615" y="162" font-size="18" font-weight="700" fill="#1F5B1F" text-anchor="middle">Mantid (the reduction engine)</text>

  <!-- ─── UI-LOCKED overlay: a vertical bar in the UI lane from step 2 to step 9 ─── -->
  <rect x="48" y="360" width="14" height="480" rx="4" fill="url(#lockGrad)" stroke="#C8102E" stroke-width="1.5"/>
  <g transform="translate(55, 600)">
  <!-- ─── Five swim lanes ─── -->
  <!-- Column widths:
       UI:           40..260   (220 wide)
       Qt Signal:    270..480  (210 wide)
       Config/DM:    490..860  (370 wide)
       Reduction:    870..1360 (490 wide)
       Mantid:       1370..1880 (510 wide)
  -->
  <rect x="40" y="130" width="220" height="830" rx="10" fill="url(#uiLane)" stroke="#E87722" stroke-width="2"/>
  <text x="150" y="162" font-size="17" font-weight="700" fill="#8C3A00" text-anchor="middle">Qt GUI layer</text>

  <rect x="270" y="130" width="210" height="830" rx="10" fill="url(#signalLane)" stroke="#D2A000" stroke-width="2"/>
  <text x="375" y="162" font-size="17" font-weight="700" fill="#3A2C00" text-anchor="middle">Qt Signal</text>

  <rect x="490" y="130" width="370" height="830" rx="10" fill="url(#cfgLane)" stroke="#D2A000" stroke-width="2"/>
  <text x="675" y="162" font-size="17" font-weight="700" fill="#3A2C00" text-anchor="middle">Configuration / DataManager</text>

  <rect x="870" y="130" width="490" height="830" rx="10" fill="url(#reduxLane)" stroke="#4A90C2" stroke-width="2"/>
  <text x="1115" y="162" font-size="17" font-weight="700" fill="#002E5D" text-anchor="middle">Reduction back-end (runs on Qt thread!)</text>

  <rect x="1370" y="130" width="510" height="830" rx="10" fill="url(#mantidLane)" stroke="#6DA64F" stroke-width="2"/>
  <text x="1625" y="162" font-size="17" font-weight="700" fill="#1F5B1F" text-anchor="middle">Mantid (the reduction engine)</text>

  <!-- ─── UI LOCKED indicator on the right edge of the UI lane ─── -->
  <rect x="235" y="335" width="16" height="525" rx="5" fill="url(#lockGrad)" stroke="#C8102E" stroke-width="1.5"/>
  <!-- Rotated label placed in the Qt-Signal lane beside the bar so it does not overlap the bar -->
  <g transform="translate(330, 595)">
    <g transform="rotate(-90)">
      <text x="0" y="0" font-size="20" font-weight="700" fill="#C8102E" text-anchor="middle">UI THREAD LOCKED · 1–10 s</text>
      <text x="0" y="0" font-size="18" font-weight="700" fill="#C8102E" text-anchor="middle">UI THREAD LOCKED · 1–10 s</text>
    </g>
  </g>

  <!-- ═══════════ Steps ═══════════ -->
  <!-- ═══════════════ Steps ═══════════════ -->

  <!-- Step 1: user drags peak line -->
  <!-- Step 1 (UI): user drags peak line -->
  <g>
    <circle cx="95" cy="225" r="22" fill="#E87722" stroke="#8C3A00" stroke-width="2"/>
    <text x="95" y="232" font-size="20" font-weight="700" fill="white" text-anchor="middle">1</text>
    <text x="130" y="218" font-size="15" font-weight="700" fill="#002E5D">User drags peak line</text>
    <text x="130" y="238" font-size="13" fill="#3E2C00">on the detector plot</text>
    <text x="130" y="256" font-size="12" fill="#606060" font-style="italic">mplwidget mouse event</text>
    <circle cx="90" cy="235" r="22" fill="#E87722" stroke="#8C3A00" stroke-width="2"/>
    <text x="90" y="242" font-size="20" font-weight="700" fill="white" text-anchor="middle">1</text>
    <text x="125" y="225" font-size="14" font-weight="700" fill="#002E5D">User drags peak line</text>
    <text x="125" y="244" font-size="12" fill="#3E2C00">on the detector plot</text>
    <text x="125" y="262" font-size="11" fill="#606060" font-style="italic">mplwidget mouse event</text>
  </g>
  <path d="M 180 278 L 180 305" stroke="#002E5D" stroke-width="2.5" marker-end="url(#flowArrow)"/>
  <!-- arrow 1 → 2 (UI → Qt Signal) -->
  <path d="M 260 260 Q 285 275 295 310" stroke="#002E5D" stroke-width="2.5" fill="none" marker-end="url(#flowArrow)"/>

  <!-- Step 2: Qt signal fires -->
  <!-- Step 2 (Qt Signal lane): motion_notify_event / changeRegionValues -->
  <g>
    <circle cx="95" cy="335" r="22" fill="#E87722" stroke="#8C3A00" stroke-width="2"/>
    <text x="95" y="342" font-size="20" font-weight="700" fill="white" text-anchor="middle">2</text>
    <text x="130" y="328" font-size="15" font-weight="700" fill="#002E5D">Qt signal fires</text>
    <text x="130" y="348" font-size="12" fill="#606060" font-family="monospace">motion_notify_event</text>
    <text x="130" y="366" font-size="12" fill="#3E2C00" font-style="italic">MainHandler.changeRegionValues</text>
    <circle cx="325" cy="340" r="22" fill="#D2A000" stroke="#6F5500" stroke-width="2"/>
    <text x="325" y="347" font-size="20" font-weight="700" fill="white" text-anchor="middle">2</text>
    <text x="358" y="322" font-size="14" font-weight="700" fill="#3A2C00">Qt signal fires</text>
    <text x="358" y="342" font-size="11" fill="#3A2C00" font-family="monospace">motion_notify_event</text>
    <text x="358" y="360" font-size="11" fill="#3A2C00" font-style="italic">MainHandler.changeRegionValues</text>
  </g>
  <path d="M 300 395 L 330 395" stroke="#002E5D" stroke-width="2.5" marker-end="url(#flowArrow)"/>
  <!-- arrow 2 → 3 (Qt Signal → Config) -->
  <path d="M 480 395 L 510 395" stroke="#002E5D" stroke-width="2.5" marker-end="url(#flowArrow)"/>

  <!-- Step 3: update_configuration_from_ui -->
  <!-- Step 3 (Config lane): update_configuration_from_ui -->
  <g>
    <circle cx="360" cy="395" r="22" fill="#D2A000" stroke="#6F5500" stroke-width="2"/>
    <text x="360" y="402" font-size="20" font-weight="700" fill="white" text-anchor="middle">3</text>
    <text x="395" y="388" font-size="15" font-weight="700" fill="#3A2C00">update_configuration_from_ui()</text>
    <text x="395" y="406" font-size="12" fill="#3A2C00">Read every widget → write Configuration instance</text>
    <text x="395" y="422" font-size="12" fill="#3A2C00" font-style="italic">~40 widget.value() / isChecked() / currentIndex() calls</text>
    <circle cx="535" cy="395" r="22" fill="#D2A000" stroke="#6F5500" stroke-width="2"/>
    <text x="535" y="402" font-size="20" font-weight="700" fill="white" text-anchor="middle">3</text>
    <text x="568" y="385" font-size="14" font-weight="700" fill="#3A2C00">update_configuration_from_ui()</text>
    <text x="568" y="403" font-size="12" fill="#3A2C00">Read every widget → write Configuration instance</text>
    <text x="568" y="420" font-size="11" fill="#3A2C00" font-style="italic">~40 widget.value() / isChecked() / currentIndex() calls</text>
  </g>
  <path d="M 570 445 L 570 475" stroke="#002E5D" stroke-width="2.5" marker-end="url(#flowArrow)"/>
  <!-- arrow 3 → 4 (down in Config lane) -->
  <path d="M 675 445 L 675 485" stroke="#002E5D" stroke-width="2.5" marker-end="url(#flowArrow)"/>

  <!-- Step 4: DataManager.update_configuration -->
  <!-- Step 4 (Config lane): DataManager.update_configuration -->
  <g>
    <circle cx="360" cy="510" r="22" fill="#D2A000" stroke="#6F5500" stroke-width="2"/>
    <text x="360" y="517" font-size="20" font-weight="700" fill="white" text-anchor="middle">4</text>
    <text x="395" y="497" font-size="15" font-weight="700" fill="#3A2C00">DataManager.update_configuration</text>
    <text x="395" y="515" font-size="12" fill="#3A2C00">Routes Configuration to every loaded NexusData</text>
    <text x="395" y="532" font-size="11" fill="#8C3A00" font-style="italic">class-attributes of Configuration are NOT copied</text>
    <circle cx="535" cy="520" r="22" fill="#D2A000" stroke="#6F5500" stroke-width="2"/>
    <text x="535" y="527" font-size="20" font-weight="700" fill="white" text-anchor="middle">4</text>
    <text x="568" y="508" font-size="14" font-weight="700" fill="#3A2C00">DataManager.update_configuration</text>
    <text x="568" y="526" font-size="12" fill="#3A2C00">Routes Configuration to every NexusData</text>
    <text x="568" y="544" font-size="11" fill="#8C3A00" font-style="italic">class-attributes of Configuration are NOT copied</text>
  </g>
  <path d="M 570 560 L 570 590" stroke="#002E5D" stroke-width="2.5" marker-end="url(#flowArrow)"/>
  <!-- arrow 4 → 5 -->
  <path d="M 675 575 L 675 615" stroke="#002E5D" stroke-width="2.5" marker-end="url(#flowArrow)"/>

  <!-- Step 5: deepcopy -->
  <!-- Step 5 (Config lane): deepcopy -->
  <g>
    <circle cx="360" cy="625" r="22" fill="#D2A000" stroke="#6F5500" stroke-width="2"/>
    <text x="360" y="632" font-size="20" font-weight="700" fill="white" text-anchor="middle">5</text>
    <text x="395" y="611" font-size="15" font-weight="700" fill="#3A2C00">deepcopy × N cross-sections</text>
    <text x="395" y="629" font-size="12" fill="#3A2C00" font-family="monospace">self.configuration = copy.deepcopy(configuration)</text>
    <text x="395" y="647" font-size="11" fill="#C8102E" font-style="italic">2–4 deepcopies per peak drag · ~1–5 ms each</text>
    <circle cx="535" cy="650" r="22" fill="#D2A000" stroke="#6F5500" stroke-width="2"/>
    <text x="535" y="657" font-size="20" font-weight="700" fill="white" text-anchor="middle">5</text>
    <text x="568" y="638" font-size="14" font-weight="700" fill="#3A2C00">deepcopy × N cross-sections</text>
    <text x="568" y="656" font-size="11" fill="#3A2C00" font-family="monospace">self.configuration = copy.deepcopy(configuration)</text>
    <text x="568" y="674" font-size="11" fill="#C8102E" font-style="italic">2–4 deepcopies per peak drag · ~1–5 ms each</text>
  </g>
  <path d="M 795 660 L 820 660" stroke="#002E5D" stroke-width="2.5" marker-end="url(#flowArrow)"/>
  <!-- arrow 5 → 6 (Config → Reduction) -->
  <path d="M 845 690 L 885 690" stroke="#002E5D" stroke-width="2.5" marker-end="url(#flowArrow)"/>

  <!-- Step 6: calculate_reflectivity -->
  <!-- Step 6 (Reduction): calculate_reflectivity -->
  <g>
    <circle cx="850" cy="660" r="22" fill="#4A90C2" stroke="#002E5D" stroke-width="2"/>
    <text x="850" y="667" font-size="20" font-weight="700" fill="white" text-anchor="middle">6</text>
    <text x="885" y="646" font-size="15" font-weight="700" fill="#002E5D">NexusData.calculate_reflectivity(…)</text>
    <text x="885" y="664" font-size="12" fill="#1F3A5F">Groups workspaces; builds ~35 MRR kwargs;</text>
    <text x="885" y="681" font-size="12" fill="#1F3A5F">applies <tspan font-family="monospace">_as_ints</tspan> (one of two local variants)</text>
    <circle cx="910" cy="690" r="22" fill="#4A90C2" stroke="#002E5D" stroke-width="2"/>
    <text x="910" y="697" font-size="20" font-weight="700" fill="white" text-anchor="middle">6</text>
    <text x="945" y="673" font-size="14" font-weight="700" fill="#002E5D">NexusData.calculate_reflectivity(…)</text>
    <text x="945" y="691" font-size="12" fill="#1F3A5F">Groups workspaces; builds ~35 MRR kwargs;</text>
    <text x="945" y="709" font-size="11.5" fill="#1F3A5F">applies <tspan font-family="monospace">_as_ints</tspan> (one of two local variants)</text>
  </g>
  <path d="M 1315 700 L 1350 700" stroke="#002E5D" stroke-width="2.5" marker-end="url(#flowArrow)"/>
  <!-- arrow 6 → 7 (Reduction → Mantid) -->
  <path d="M 1340 730 L 1380 730" stroke="#002E5D" stroke-width="2.5" marker-end="url(#flowArrow)"/>

  <!-- Step 7: MRR.PyExec -->
  <!-- Step 7 (Mantid): MRR.PyExec -->
  <g>
    <circle cx="1380" cy="700" r="22" fill="#6DA64F" stroke="#1F5B1F" stroke-width="2"/>
    <text x="1380" y="707" font-size="20" font-weight="700" fill="white" text-anchor="middle">7</text>
    <text x="1415" y="684" font-size="15" font-weight="700" fill="#002E5D">MagnetismReflectometryReduction.PyExec</text>
    <text x="1415" y="702" font-size="12" fill="#1F3A1F">859 LOC Python, per cross-section executes:</text>
    <text x="1415" y="720" font-size="11.5" fill="#1F5B1F" font-family="monospace">Rebin · RefRoi (×2) · Minus · NormaliseByCurrent ·</text>
    <text x="1415" y="736" font-size="11.5" fill="#1F5B1F" font-family="monospace">Divide · ConvertToPointData · Rebin · cleanup</text>
    <circle cx="1405" cy="730" r="22" fill="#6DA64F" stroke="#1F5B1F" stroke-width="2"/>
    <text x="1405" y="737" font-size="20" font-weight="700" fill="white" text-anchor="middle">7</text>
    <text x="1440" y="712" font-size="14" font-weight="700" fill="#002E5D">MagnetismReflectometryReduction.PyExec</text>
    <text x="1440" y="730" font-size="11.5" fill="#1F3A1F">859 LOC Python, per cross-section executes:</text>
    <text x="1440" y="748" font-size="11" fill="#1F5B1F" font-family="monospace">Rebin · RefRoi (×2) · Minus · NormaliseByCurrent ·</text>
    <text x="1440" y="763" font-size="11" fill="#1F5B1F" font-family="monospace">Divide · ConvertToPointData · Rebin · cleanup</text>
  </g>
  <!-- return arrow from 7 back to 8 -->
  <path d="M 1610 750 L 1610 770 L 885 770 L 885 780" stroke="#002E5D" stroke-width="2.5" fill="none" marker-end="url(#flowArrow)"/>
  <!-- arrow 7 → 8 (Mantid result returns to Reduction) -->
  <path d="M 1625 780 L 1625 810 L 945 810 L 945 830" stroke="#002E5D" stroke-width="2.5" fill="none" marker-end="url(#flowArrow)"/>

  <!-- Step 8: CrossSection caches -->
  <!-- Step 8 (Reduction): CrossSection caches result -->
  <g>
    <circle cx="850" cy="795" r="22" fill="#4A90C2" stroke="#002E5D" stroke-width="2"/>
    <text x="850" y="802" font-size="20" font-weight="700" fill="white" text-anchor="middle">8</text>
    <text x="885" y="780" font-size="15" font-weight="700" fill="#002E5D">CrossSectionData caches Q, R, dR</text>
    <text x="885" y="798" font-size="12" fill="#1F3A5F">Applies QuickNXS compat scale factor</text>
    <text x="885" y="815" font-size="11.5" fill="#1F3A5F" font-style="italic">stores the reflectivity workspace for the UI to read</text>
    <circle cx="910" cy="850" r="22" fill="#4A90C2" stroke="#002E5D" stroke-width="2"/>
    <text x="910" y="857" font-size="20" font-weight="700" fill="white" text-anchor="middle">8</text>
    <text x="945" y="833" font-size="14" font-weight="700" fill="#002E5D">CrossSectionData caches Q, R, dR</text>
    <text x="945" y="851" font-size="12" fill="#1F3A5F">Applies QuickNXS compat scale factor</text>
    <text x="945" y="868" font-size="11" fill="#1F3A5F" font-style="italic">stores the reflectivity workspace for the UI to read</text>
  </g>
  <!-- arrow from step 8 back to UI lane step 9 (now below) -->
  <path d="M 820 820 L 180 820 L 180 830" stroke="#002E5D" stroke-width="2.5" fill="none" marker-end="url(#flowArrow)"/>
  <!-- arrow 8 → 9 (Reduction back to UI via single sweep) -->
  <path d="M 885 860 L 200 860 L 200 890" stroke="#002E5D" stroke-width="2.5" fill="none" marker-end="url(#flowArrow)"/>

  <!-- Step 9: Plot redraws (NOW BELOW Step 8) -->
  <!-- Step 9 (UI): Plot redraws — below step 1 and step 2 -->
  <g>
    <circle cx="95" cy="865" r="22" fill="#E87722" stroke="#8C3A00" stroke-width="2"/>
    <text x="95" y="872" font-size="20" font-weight="700" fill="white" text-anchor="middle">9</text>
    <text x="130" y="855" font-size="15" font-weight="700" fill="#002E5D">Plot widget redraws</text>
    <text x="130" y="873" font-size="12" fill="#3E2C00" font-style="italic">matplotlib canvas update</text>
    <text x="130" y="891" font-size="12" fill="#C8102E" font-weight="700">UI unlocks here</text>
    <circle cx="90" cy="920" r="22" fill="#E87722" stroke="#8C3A00" stroke-width="2"/>
    <text x="90" y="927" font-size="20" font-weight="700" fill="white" text-anchor="middle">9</text>
    <text x="125" y="910" font-size="14" font-weight="700" fill="#002E5D">Plot widget redraws</text>
    <text x="125" y="928" font-size="12" fill="#3E2C00" font-style="italic">matplotlib canvas update</text>
    <text x="125" y="946" font-size="11" fill="#C8102E" font-weight="700">UI unlocks here</text>
  </g>

  <!-- ─── Time / cost banner ─── -->
  <!-- Time / cost banner -->
  <g transform="translate(40, 985)">
    <rect x="0" y="0" width="1840" height="44" rx="8" fill="#002E5D" stroke="#001A35" stroke-width="1.5"/>
    <text x="20" y="28" font-size="14.5" fill="#F5C13A" font-weight="700">Cost of one peak-drag:</text>
@@ -175,6 +196,6 @@

  <!-- Footer -->
  <rect x="0" y="1045" width="1920" height="35" fill="#001A35"/>
  <text x="40" y="1068" font-size="12" fill="#6A90B0">Source: 12-parameter-propagation-and-qt-leakage.md §1–§5 · the "where the debt accumulates" breakdown is on slide 5a</text>
  <text x="40" y="1068" font-size="12" fill="#6A90B0">Source: 12-parameter-propagation-and-qt-leakage.md §1–§5 · the "Qt Leakage" breakdown is on slide 5a</text>
  <text x="1880" y="1068" font-size="12" fill="#6A90B0" text-anchor="end">Reflectometry Hack-a-thon 2026 · slide 5</text>
</svg>
−3.68 KiB (175 KiB)
Loading image diff...
+3 −3
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@

  <!-- Header -->
  <rect x="0" y="0" width="1920" height="110" fill="url(#headerGrad)"/>
  <text x="960" y="58" font-size="34" font-weight="700" fill="white" text-anchor="middle">Where the Debt Accumulates</text>
  <text x="960" y="58" font-size="34" font-weight="700" fill="white" text-anchor="middle">Qt Leakage</text>
  <text x="960" y="93" font-size="18" fill="#B8D4E8" text-anchor="middle">Five patterns that scientists perceive as "Qt leaking into the reduction" — but no Qt imports leave the UI layer</text>

  <!-- Subtitle -->
@@ -50,8 +50,8 @@
    <g font-size="15" fill="#3E2C00">
      <text x="690" y="300">Configuration is copied on every UI event:</text>
      <text x="710" y="328">UI → NexusData → CrossSectionData × N</text>
      <text x="690" y="365">Introduced in commit <tspan font-family="monospace" fill="#002E5D">aa32022</tspan> to stop the UI from</text>
      <text x="690" y="388">mutating old reductions retroactively.</text>
      <text x="690" y="365">This stops the UI from mutating old reductions</text>
      <text x="690" y="388">retroactively.</text>
      <text x="690" y="425" font-weight="700" fill="#C8102E">But class-attributes bypass the deepcopy.</text>
      <text x="690" y="453">~22 "global options" on the Configuration class</text>
      <text x="690" y="476">remain shared across every run.</text>