This repository provides the Flask back‑end for the Raston Lab Virtual FTMW Spectrometer.
git clone https://github.com/FTMW-Scientific-Simulator/Virtual-FTMW-Spectrometer
cd Virtual-FTMW-Functions
python3 -m venv .venv
pip install -r requirements.txt
python app.py- 
app.py
- 
Initializes a Flask application with CORS enabled.
 - 
Reads
version.txt(if present) and exposes it viaapp.config["VERSION"]. - 
Defines three routes:
- 
GET /
- Returns a simple HTML title showing the API name and version.
 
 - 
POST /acquire_spectrum
- Parses incoming JSON parameters and forwards them to 
acquire_spectrainacquire_spectra.py. - Returns JSON with success status and arrays of X and Y values.
 
 - Parses incoming JSON parameters and forwards them to 
 - 
POST /find_peaks
- Parses incoming JSON containing 
x,y, andthreshold, then callsfind_peaksinacquire_spectra.py. - Returns JSON with success status and a mapping of peak frequencies to intensities.
 
 - Parses incoming JSON containing 
 
 - 
 - 
When run as a script, listens on
0.0.0.0:5001(debug off by default). 
 - 
 
- 
acquire_spectra_utils.py
- 
Contains helper functions shared by acquisition and peak‑finding logic:
- 
get_datafile(molecule, directory="linelists")- Maps a molecule string to a local data filename and returns its full path.
 - Raises 
ValueErrorif no mapping exists. 
 - 
param_check(params)- Verifies that the incoming parameter dictionary has exactly the expected keys and no null values.
 - Returns 
Trueif all checks pass, otherwiseFalse. 
 - 
lorentzian_profile(grid, center, fwhm)- Generates a Lorentzian line shape on 
grid, centered atcenterwith given full width at half maximum. 
 - Generates a Lorentzian line shape on 
 - 
add_white_noise(spectrum, num_cycles_per_step, is_cavity_mode)- Adds Gaussian noise scaled by 
num_cycles_per_step; uses different noise levels for cavity mode. 
 - Adds Gaussian noise scaled by 
 - 
apply_cavity_mode_response(params, frequency_grid, spectrum, v_res=8206.4, Q=10000, Pmax=1.0)- Applies one or more cavity‑mode filter functions to 
spectrum, based onacquisitionType. - Adds white noise to the cavity response before multiplying it into the spectrum.
 
 - Applies one or more cavity‑mode filter functions to 
 
 - 
 
 - 
 
- 
acquire_spectra.py
- 
Implements two main functions:
- 
acquire_spectra(params, window=25, resolution=0.001, fwhm=0.007, Q=10000, Pmax=1.0)- 
Validates
paramswithparam_check. Returns error JSON if invalid. - 
Extracts molecule name and resolution parameter
vres. - 
Loads line list data via
get_datafile, reads into a DataFrame, and filters by frequency bounds. - 
For each spectral line:
- Builds a local frequency grid around the line center ± 
window. - Computes two Lorentzian components (Doppler‑shifted split peaks).
 - Sums them into a local spectrum.
 
 - Builds a local frequency grid around the line center ± 
 - 
Defines a global frequency grid (
crop_mintocrop_max) and interpolates all local spectra onto it. - 
Adds white noise and applies cavity mode response.
 - 
Returns JSON:
 
{ "success": true, "x": ["freq1","freq2",...], "y": ["int1","int2",...] } - 
 - 
find_peaks(x_data, y_data, threshold=0, min_distance=100)- Converts inputs to NumPy arrays and calls SciPy’s 
find_peaks. - Catches exceptions and returns an error JSON if something goes wrong.
 - Builds and returns a dictionary mapping each peak frequency (to 4 decimal places) to its intensity (to 4 decimals).
 
 - Converts inputs to NumPy arrays and calls SciPy’s 
 
 - 
 
 - 
 
This section describes how incoming requests are handled:
- 
Version handling
- On startup, attempts to read 
version.txt. If found, setsapp.config["VERSION"]. - The root route displays this version in the HTML header.
 
 - On startup, attempts to read 
 - 
Spectrum acquisition
POST /acquire_spectrum→ callsacquire_spectra→ returns spectrum JSON.
 - 
Peak finding
POST /find_peaks→ callsfind_peaks→ returns peaks JSON.
 
Returns the path to a line list file for the requested molecule. Mappings:
{
  "C6H5CN": "C6H5CN.dat",
  "HC7N":   "HC7N.dat",
  …
}Ensures exactly 11 keys: molecule, stepSize, frequencyMin, frequencyMax, numCyclesPerStep, microwavePulseWidth, mwBand, repetitionRate, molecularPulseWidth, acquisitionType, vres.
(1/pi) * (hwhm / ((grid - center)**2 + hwhm**2)) where hwhm = fwhm/2.
Draws from np.random.normal(0, noise_level, spectrum.shape) with noise_level scaled by 1/sqrt(num_cycles_per_step).
- single mode: one Lorentzian filter at 
vres. - range mode: sum of Lorentzian filters spaced by 
stepSize. 
- Reads frequency/intensity pairs from the line list.
 - Filters by 
vres +/- windowor[frequencyMin-window, frequencyMax+window]. - For each line, makes two Lorentzian peaks to simulate Doppler splitting.
 - Interpolates and sums onto a global grid.
 - Adds noise and cavity response, then takes absolute value.
 
- Uses 
scipy.signal.find_peaks(y, height=threshold, distance=min_distance). - Maps results to a JSON of 
{ "freq": "intensity" }entries.