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::LaserUnitonly 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. NoHardwareObjectorSettingsStoragedependency: callers build theNodelist from settings snapshots and hand it toassemble().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.0if 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 equalslaserToOutput(). Used to record each node’s resolved affine mapping when snapshotting the topology. Returns-1.0if 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 onesstageOutput()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 makesstageOutput()return-1.0at 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 (seestageInput()). 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
truewhen 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: anyInputRefof typeStagefails to resolve to aNodein nodes; a node’s input count does not match itsOp(NHG=1, SFG/DFG=2); the graph does not have exactly one node withisFinalset; 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 beinputs[0].For a
DFGthe 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 asinputs[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 (seestageOutputCoeffs()).
Private Members
-
bool d_identity = {true}
trueiff 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}
trueiff assembly succeeded.
-
QString errorString
Populated iff
!ok.
-
LifConversion conversion
Valid iff
ok.
-
bool ok = {false}
-
LifConversion()