LifConversion

LifConversion is the assembled, validated form of a LIF frequency-conversion topology: an affine model, resolved in vacuum wavenumber (cm⁻¹) throughout, that maps the tunable laser’s fundamental through zero or more conversion nodes to the FINAL excitation (output) beam. It is a pure value type — no HardwareObject or SettingsStorage dependency — so it can be constructed, copied, and evaluated from any thread. LifConversion::assemble() is the sole validating construction path; every other member reads a successfully-assembled (or default-identity) instance. The architecture this class sits in — where node lists come from, how they are joined with hardware-owned op/harmonic state, and how the result reaches the laser and each conversion stage during acquisition — is covered in full on the Frequency conversion section of LIF Acquisition and Visualization.

assemble takes a std::vector<BC::LifConv::Node> — one node per conversion stage, each carrying its operation (BC::LifConv::Op::NHG / SFG / DFG), a harmonic order for NHG, one or two BC::LifConv::InputRef inputs (each a reference to the tunable laser, another node’s output, or a fixed mixing beam), and an isFinal marker. An empty node list assembles to the identity conversion (output equals fundamental, no FINAL marker required). A non-empty list is rejected — returning AssemblyResult{false, errorString, {}} — when an input reference does not resolve, a node’s input count does not match its operation, the graph does not have exactly one FINAL node, the graph contains a cycle, or the FINAL beam has no net dependence on the tunable source. Nothing outside assemble performs this validation; callers that need a joined node list build one via lifConversionNodesFromSnapshot, LifConversionSnapshot::toNodes(), or their own caller-supplied list, documented on LifFreqConversionStage and LifConversionSnapshot.

Once assembled, laserToOutput/outputToLaser convert between the fundamental and the FINAL beam (exact, since the topology is affine — no numerics involved); stageInput/stageOutput return a named node’s local input and output wavenumbers for a given fundamental, used both to drive each conversion stage’s setpoint during acquisition (HardwareManager::setLifConversionStages()) and to record the resolved per-node coefficients when writing liftopology.csv (LifConfig::writeTopologyFile()); outputRange maps a laser’s native cm⁻¹ range through the topology, used by ExperimentTypePage::updateLifLaserBounds to compute the scan-axis bounds shown in the wizard; and isIdentity reports the no-conversion-stages case that several call sites treat as a sentinel (see Key invariants on LIF Acquisition and Visualization).

API Reference

class LifConversion

Pure value type representing an assembled LIF frequency-conversion topology, from the tunable grating fundamental through zero or more conversion nodes to the FINAL output beam.

All values are vacuum wavenumber (cm⁻¹) end to end; convert to/from a user-facing BC::LifConv::LaserUnit only at display call sites (see lifunits.h). assemble() is the only validating construction path — every other member reads a successfully-assembled (or default-identity) instance. No HardwareObject or SettingsStorage dependency: callers build the Node list from settings snapshots and hand it to assemble().

Public Functions

LifConversion()

Construct the identity conversion: output == fundamental (the zero-stage case).

double laserToOutput(double fundamentalCm1) const

Return the FINAL beam wavenumber (cm⁻¹) for a given grating fundamental (cm⁻¹).

double outputToLaser(double outputCm1) const

Analytic inverse of laserToOutput: the grating fundamental (cm⁻¹) that produces a given FINAL beam wavenumber (cm⁻¹).

Exact (the topology is affine in the fundamental); no numerics.

double stageInput(const QString &stageKey, double fundamentalCm1) const

Return the local tunable-tracking input-beam wavenumber (cm⁻¹) seen by the node named stageKey, for a given grating fundamental (cm⁻¹) — what that FCU calibrates its phase-match motion against. This is whichever input carries the tunable dependence, not necessarily inputs[0].

Returns -1.0 if stageKey does not name a node in this conversion. A physical beam wavenumber is never negative, so this sentinel is unambiguous.

double stageOutput(const QString &stageKey, double fundamentalCm1) const

Return the OUTPUT-beam wavenumber (cm⁻¹) produced by the node named stageKey, for a given grating fundamental (cm⁻¹) — the node’s own conversion applied to its inputs.

Symmetric partner to stageInput(): for the FINAL node this equals laserToOutput(). Used to record each node’s resolved affine mapping when snapshotting the topology. Returns -1.0 if stageKey does not name a node in this conversion (an unambiguous sentinel, as a physical beam wavenumber is never negative).

std::pair<double, double> stageOutputCoeffs(const QString &stageKey) const

Return the affine coefficients {a, b} of the OUTPUT beam produced by the node named stageKey: wavenumber = a*fundamentalCm1 + b (cm⁻¹).

These are the exact values fixed at assemble() time — the same ones stageOutput() evaluates — so a caller that persists or analyzes a stage’s mapping reads them directly instead of reconstructing them from sampled evaluations. Returns {0.0, -1.0} for an unknown stageKey; that sentinel is unambiguous (a physical beam is never negative) and makes stageOutput() return -1.0 at any fundamental for the same key.

std::pair<double, double> stageInputCoeffs(const QString &stageKey) const

Return the affine coefficients {a, b} of the tunable-tracking INPUT beam seen by the node named stageKey (see stageInput()). Returns {0.0, -1.0} for an unknown stageKey.

std::pair<double, double> outputRange(double laserMinCm1, double laserMaxCm1) const

Return the FINAL-beam bounds (cm⁻¹) corresponding to the grating’s native laserMinCm1 / laserMaxCm1, sorted ascending (the topology may reverse direction, e.g. doubling maps a max wavelength to a min wavelength).

bool isIdentity() const

Return true when this conversion has no stages (output == fundamental).

Public Static Functions

static AssemblyResult assemble(const std::vector<BC::LifConv::Node> &nodes)

Assemble and validate a conversion graph from per-stage node descriptors.

An empty nodes list yields the identity conversion (no FINAL marker required). Otherwise, validation rejects the graph (returning {false, errorString, {}}) when: any InputRef of type Stage fails to resolve to a Node in nodes; a node’s input count does not match its Op (NHG=1, SFG/DFG=2); the graph does not have exactly one node with isFinal set; the graph contains a cycle; or the assembled FINAL beam has no net dependence on the tunable laser source (see the comment in the .cpp on why this is the currently-representable proxy for “more than one tunable source”).

A two-input stage may carry the tunable beam in either slot; stageInput() reports whichever input tracks the fundamental, so there is no requirement that the tunable beam be inputs[0].

For a DFG the output is the difference beam |in0 - in1|, held as a signed affine expression rather than an absolute value (so the inverse and the persisted coefficients stay exact). A valid crystal never operates across a zero-crossing, so the higher-frequency input is fixed for the whole scan and must be wired as inputs[0]; the difference is then the physical (non-negative) beam. assemble() has no tuning range and cannot check this, so the construction UI warns when a stage’s output beam would reach zero or below over the laser’s range (see stageOutputCoeffs()).

Private Members

bool d_identity = {true}

true iff assembled from an empty node list (or default-constructed).

BC::LifConv::detail::AffineCoeffs d_output

FINAL beam coefficients vs. the fundamental.

std::map<QString, BC::LifConv::detail::AffineCoeffs> d_primaryInput

Per-stage tunable-tracking input coefficients (see stageInput()).

std::map<QString, BC::LifConv::detail::AffineCoeffs> d_stageOutput

Per-stage OUTPUT-beam coefficients.

struct AssemblyResult

Public Members

bool ok = {false}

true iff assembly succeeded.

QString errorString

Populated iff !ok.

LifConversion conversion

Valid iff ok.