fix(digital-twin): use exact string comparisons

Replace substring membership checks with equality for modes, stripes, scene names, and plot identifiers so partial strings cannot select the wrong branch.
This commit is contained in:
2026-06-09 15:41:10 +02:00
parent 1a20282499
commit 6bce6f8907
7 changed files with 29 additions and 29 deletions
@@ -183,7 +183,7 @@ def calc_positions(cfg: ConfigDict) -> dict[str, dict[str, float]]:
if cfg["fm_stripe"] in ("Rh (toroid)", "Pt (toroid)"):
# TRY
if cfg["fm_stripe"] in "Rh (toroid)":
if cfg["fm_stripe"] == "Rh (toroid)":
r = bl.fm.r[0]
h_cyl = bl.fm.hToroid[0]
else: # PT toroid
@@ -199,7 +199,7 @@ def calc_positions(cfg: ConfigDict) -> dict[str, dict[str, float]]:
pos["fm_try"] = {"value": fm_height}
# TRX
if cfg["fm_stripe"] in "Rh (toroid)":
if cfg["fm_stripe"] == "Rh (toroid)":
x_cyl = -bl.fm.xToroid[0]
else:
x_cyl = -bl.fm.xToroid[1]
@@ -213,7 +213,7 @@ def calc_positions(cfg: ConfigDict) -> dict[str, dict[str, float]]:
pos["fm_try"] = {"value": fm_height}
# TRX
if cfg["fm_stripe"] in "Rh (flat)":
if cfg["fm_stripe"] == "Rh (flat)":
x_flat = -bl.fm.xFlat[0]
else:
x_flat = -bl.fm.xFlat[1]
@@ -27,7 +27,7 @@ def calc_sideview(cfg: ConfigDict) -> DataDict:
beam["y"].append(bl.sourceHeight)
beam["x"].append(bl.cm.center[1]) # CM
beam["y"].append(bl.sourceHeight)
if cfg["mo1_mode"] in "Monochromatic":
if cfg["mo1_mode"] == "Monochromatic":
diag = bl.mo1.xtalGap[0] / np.sin(cfg["mo1_bragg"]) # Calculations for Mono
dy = diag * np.sin(2 * (cfg["cm_pitch"] + cfg["mo1_bragg"]))
dz = diag * np.cos(2 * (cfg["cm_pitch"] + cfg["mo1_bragg"]))
@@ -65,7 +65,7 @@ def calc_surfaces(cfg: ConfigDict) -> SurfaceDict:
height_beam = 2 * bl.cm.center[1] * np.tan(cfg["v_acc"])
w = height_beam / np.sin(cfg["mo1_bragg"])
if cfg["mo1_mode"] in "Monochromatic":
if cfg["mo1_mode"] == "Monochromatic":
out["mo1_1"]["x"] = [
xtal_pos - width_beam / 2,
xtal_pos + width_beam / 2,
@@ -258,7 +258,7 @@ def fm_ideal_pitch(
"""
p = bl.fm.center[1] # posFM
q = smpl - bl.fm.center[1] # dist posFM to posEX
if fm_focus in "Defocused":
if fm_focus == "Defocused":
assert sldi_hacc is not None, "sldi_hacc must be provided for Defocused mode"
assert sldi_vacc is not None, "sldi_vacc must be provided for Defocused mode"
assert fm_focx is not None, "fm_focx must be provided for Defocused mode"
@@ -294,9 +294,9 @@ def cm_critical_angle(cm_stripe: Literal["Si", "Pt", "Rh"], energy) -> float:
Returns:
float: Critical angle in rad
"""
if cm_stripe in "Si":
if cm_stripe == "Si":
stripe = bl.stripeSi
elif cm_stripe in "Pt":
elif cm_stripe == "Pt":
stripe = bl.stripePt
else:
stripe = bl.stripeRh
@@ -320,15 +320,15 @@ def mirror_surface_geometries(
dict[str, tuple[float, float, float, float]]: Dictionary mapping surface
names to tuples of (x, y, width, height).
"""
if mirror in "cm":
if mirror == "cm":
surface = bl.cm.surface
lim_opt_x = bl.cm.limOptX
lim_opt_y = bl.cm.limOptY
elif mirror in "fm_toroid":
elif mirror == "fm_toroid":
surface = bl.fm.surfaceToroid
lim_opt_x = bl.fm.limOptXToroid
lim_opt_y = bl.fm.limOptYToroid
elif mirror in "fm_flat":
elif mirror == "fm_flat":
surface = bl.fm.surfaceFlat
lim_opt_x = bl.fm.limOptXFlat
lim_opt_y = bl.fm.limOptYFlat
@@ -354,7 +354,7 @@ def mo_surface_geometries(
dict[str, tuple[float, float, float, float]]: Dictionary mapping surface
names to tuples of (x, y, width, height).
"""
if mo in "mo1":
if mo == "mo1":
xtal = bl.mo1.xtal
xtal_width = bl.mo1.xtalWidth
xtal_offset_x = bl.mo1.xtalOffsetX
@@ -309,10 +309,10 @@ class DigitalTwin(BECWidget, QWidget):
ConfigDict: config of the assistant
"""
fm_focus = self.input.fm_focus.currentText()
if fm_focus in "Manual":
if fm_focus == "Manual":
fm_rotx = self.input.fm_rotx.value()
fm_qy = None
elif fm_focus in "Focused":
elif fm_focus == "Focused":
fm_rotx = self.input.fm_rotx_ideal.value()
fm_qy = None
else: # Focused
@@ -600,13 +600,13 @@ class DigitalTwin(BECWidget, QWidget):
selection of the focus strategy.
"""
fm_focus = self.input.fm_focus.currentText()
if fm_focus in "Manual":
if fm_focus == "Manual":
self.input.fm_rotx.setVisible(True)
self.input.fm_rotx_ideal.setVisible(True)
self.input.fm_focx.setVisible(False)
self.input.fm_focy.setVisible(False)
self.input.fm_rotx_ideal.setLabel("Incidence Angle for focused beam")
elif fm_focus in "Focused":
elif fm_focus == "Focused":
self.input.fm_rotx.setVisible(False)
self.input.fm_rotx_ideal.setVisible(True)
self.input.fm_focx.setVisible(False)
@@ -659,7 +659,7 @@ class DigitalTwin(BECWidget, QWidget):
"""
fm_stripe = self.input.fm_stripe.currentText()
fm_focus = self.input.fm_focus.currentText()
if fm_focus in "Manual":
if fm_focus == "Manual":
fm_rotx = -self.input.fm_rotx.value() * 1e-3
else:
fm_rotx = -self.input.fm_rotx_ideal.value() * 1e-3
@@ -745,11 +745,11 @@ class DigitalTwin(BECWidget, QWidget):
Calculates bragg angle in rad
"""
xtal = self.input.mo1_xtal.currentText()
if xtal in "Si(111)":
if xtal == "Si(111)":
d_spacing = self.dev.mo1_bragg.crystal.d_spacing_si111.read(cached=True)[
"mo1_bragg_crystal_d_spacing_si111"
]["value"]
elif xtal in "Si(311)":
elif xtal == "Si(311)":
d_spacing = self.dev.mo1_bragg.crystal.d_spacing_si311.read(cached=True)[
"mo1_bragg_crystal_d_spacing_si311"
]["value"]
@@ -767,7 +767,7 @@ class DigitalTwin(BECWidget, QWidget):
Updates the monochromator input group based on the
selection of the mode.
"""
if self.input.mo1_mode.currentText() in "Monochromatic":
if self.input.mo1_mode.currentText() == "Monochromatic":
self.input.mo1_xtal.setVisible(True)
self.input.mo1_bragg_angle.setVisible(True)
self.input.mo1_eres.setVisible(True)
@@ -74,7 +74,7 @@ class SurfacePlots(QWidget):
# Create surfaces
for idx, scene in enumerate(self.surfaces):
for name, _ in self.surfaces[scene].items():
if scene in "assistant":
if scene == "assistant":
brush = QBrush(QColor(*self.colors[idx], 255), Qt.BrushStyle.DiagCrossPattern)
pen = pg.mkPen(
QColor(*self.colors[idx], 255), width=1, style=Qt.PenStyle.DashLine
@@ -130,7 +130,7 @@ class SurfacePlots(QWidget):
for idx, scene in enumerate(self.surfaces):
for name, _ in self.surfaces[scene].items():
if scene in "assistant":
if scene == "assistant":
brush = QBrush(QColor(*self.colors[idx], 255), Qt.BrushStyle.DiagCrossPattern)
pen = pg.mkPen(
QColor(*self.colors[idx], 255), width=1, style=Qt.PenStyle.DashLine
@@ -165,13 +165,13 @@ class SurfacePlots(QWidget):
self.texts.append(text)
for name, plot in self.plots.items():
if name in "cm":
if name == "cm":
plot_surface(plot["widget"], mirror_surface_geometries("cm"))
elif name in "mo1_1":
elif name == "mo1_1":
plot_surface(plot["widget"], mo_surface_geometries("mo1", 0))
elif name in "mo1_2":
elif name == "mo1_2":
plot_surface(plot["widget"], mo_surface_geometries("mo1", 1))
elif name in "fm":
elif name == "fm":
plot_surface(plot["widget"], mirror_surface_geometries("fm_flat"))
plot_surface(plot["widget"], mirror_surface_geometries("fm_toroid"))
else:
@@ -223,7 +223,7 @@ class SideviewPlot(QWidget):
self.walls = []
for idx, scene in enumerate(self.data.keys()):
if scene in "assistant":
if scene == "assistant":
pen = pg.mkPen(color=self.colors[idx], width=2, style=Qt.PenStyle.DotLine)
z_value = 2
else:
@@ -281,7 +281,7 @@ class SideviewPlot(QWidget):
self.text_color = (0, 0, 0)
for idx, scene in enumerate(self.data):
if scene in "assistant":
if scene == "assistant":
brush = QBrush(QColor(*self.colors[idx], 255), Qt.BrushStyle.DiagCrossPattern)
pen = pg.mkPen(QColor(*self.colors[idx], 255), width=3, style=Qt.PenStyle.DashLine)
else:
@@ -485,7 +485,7 @@ class MoveWidget(QWidget):
def _on_motion_finished(self):
"""Finished a movement"""
target = self.target
if self.status not in Status.ERROR:
if self.status != Status.ERROR:
if abs(self.fb - target) <= self.deadband:
self._set_status(Status.IN_POSITION)
else: