API
Contents
Overview of the modules of spectro_inlets_quantification
The spectro_inlets_quantification package tries to make the best of modular, object-oriented programming to capture all the physics involved in quantitative mass spectrometry with a Spectro Inlets inlet system. Modules and classes do their best to represent physically intuitive concepts in the system and in your workflow. This section gives a very brief description of each module as it exists in quant.physics v1.0, with examples of some of the most important interfaces in the accompanying Ipython notebook.
Most of the equations in the previous sections of this document appear somewhere in the package. It is much bigger than that, though, because of the need to keep various pieces of information in the right places accessible through intuitive interfaces.
The code is pretty well self-documented, so don’t hesitate to import anything and input it to python’s help
function to see the docstring. There are code examples to go along with these explanations for each module in the accompanying Ipython notebook. The modules have an explicit hierarchy, and this section goes through them from lowest to highest in that hierarchy.
The config
module
This module contains the singleton Config
class, which contains all package wide configurable setting. Importantly, this allows the configuration of the base data directory, from which all other data directories (e.g. Config.molecule_directory
, which contains the data files that define e.g. the Henry’s-Law parameters for each molecule) are derived.
The constants
module
The constants
module defines constants used throughout spectro_inlets_quantification, such as:
The physical constants used in spectro_inlets_quantification such as the
GAS_CONSTANT
representing \(R=8.3143\) [J/mol/K].The chip design parameters including
STANDARD_CAPILLARY_WIDTH = 6e-6
[m]Standard conditions including
STANDARD_TEMPERATURE = 298.15
[K]Plotting preferences such as
STANDARD_COLORS
The tools
module
The tools module contains useful pythony stuff used in multiple places like a Singleton
metaclass.
It also includes some little function for parsing mass strings. For example:
>>> from spectro_inlets_quantification.tools import mass_to_M, mass_to_setting
>>> mass_to_M("M32-CEM")
32.0
>>> mass_to_setting("M32-CEM")
'CEM'
It also includes a string (tools.TODAY
) made when spectro_inlets_quantification is imported that represent the day’s date in Soren’s format. For example, the 13th of November 2020 is “20K13” where ‘K’ (the 11th letter) represents November (the 11th month). This string is used by default when new calibrations are defined.
The medium
module
The medium module’s only purpose is to give a home to the one-and-only pressure and temperature of the system, so that different classes agree on these two external conditions. That home, Medium
, is a singleton. Accessing the attributes T
or p
of any other class in any of the modules of quant including Quantifier
, Molecule
, Chip
, or Gas
will return Medium.T
or Medium.p
, respectively.
The molecule
module
The molecule module defines the Molecule
class. Instances of this class, instantiated with the Molecule.load()
(alternative constructor) class method which takes the molecule name (e.g. “H2”), load a number of constants including Henry’s-Law constant, thermochemistry, molecular diameter, ionization cross-section data, and reference spectrum from a .json data file in the Config.molecule_directory
.
The Molecule
thus instantiated wraps this data with some useful methods, such as one to calculate the volatility constant as a function of temperature (used to generate the data for Figure 2) and plot the reference spectrum (such as Figure 5.
The module also defines a MoleculeDict
, a singleton whose only instance is called mdict
everywhere it is used in spectro_inlets_quantification. The mdict
collects Molecule
instances when they are instantiated with the mdict.get()
method which takes the molecule name as its argument, and then makes them available by method or by indexing as well. MoleculeDict.get()
is almost always preferred over Molecule.load()
because it avoids an unnecessary second read of the molecule file.
The mixture
module
The mixture module has a base class Mixture
which serves as a framework for dealing with a mixture of molecules. The most important attribute of its instances (mixture
) is Mixture.comp
, which is a dictionary of {\(i\): \(x^i\)} where \(i\) is the name of a molecule and \(x^i\) is its mol fraction in the mixture. If abc
is an attribute of Molecule
, then mixture.abc
returns the mol-weighted average of abc
for each of the molecules in the mixture. Mixture.make()
is a constructor that takes a comp
dictionary or the name of a molecule or the name of a standard mixture (such as "air"
), and populates the mixture accordingly.
The Gas
class inherits from Mixture
and adds a couple of things: First, it has an updated viscosity correction that overrides the weighted average inherited from Mixture
and instead uses the algorithm in Davidson1993. This was used to generate the data for Figure 4. Second, Gas.saturated_with()
takes a molecule as input and returns a gas that contains that molecule at the mol fraction dictated its vapor pressure and the system pressure.
The chip
module
The chip module defines the Chip
class, which is basically a wrapper around the capillary equation, Equation (4). An instance of Chip
can be defined with the Chip.load()
method which takes as its argument the name of a .json file in the Config.chip_directory
, which contains the capillary dimensions if they differ from the defaults of a known chip. It can also be initialized with the default dimensions directly from chip=Chip()
. Either can take p
, T
, carrier
, and solvent
as arguments, where the first two set the system Medium.p
and Medium.T
, respectively.
Chip.gas
represents the gas in the chip. By default, it is Chip.carrier
saturated with Chip.solvent
. The capillary equation is called with Chip.calc_n_dot_0()
. It can take a gas
, p
, and T
as inputs but by default uses those of the chips. This method was used to generate the data in Figure 3. It also has a Chip.calc_n_dot()
function which returns a dictionary giving the flux in [mol/s] for each of the molecules in its gas.
The Chip
also has a number of methods for calculating the partial pressure of the gases in it given a set of quantified fluxes, including that which solves Equation (20). This resets the chip’s gas.
The peak
module
The peak module defines a Peak
base class and classes that inherit from it (so far only GaussPeak
). Each of these classes is initiated with x-and-y data, and have methods for extracting a height
, width
, and center
from it. For the base class, these are extracted by simple means (for example, height is the maximum y value), while for a gauss_peak
(instance of GaussPeak
), they come from the Gaussian fit. A peak that fails to fit raises a PeakFitError
. A peaks also has a signal
attribute, which is the height unless it is flagged with peak.error=True
, in which case peak.signal
returns 0.
Each Peak
class has a plot
method for visualization. Figure 6 was made with gauss_peak.plot()
.
The signal
module
The signal module contains three classes for organizing, visualizing, and analyzing raw data.
The SignalDict
class stores signals, as defined in Definition 1. When a signal is added, either its time is also added or it gets timestamped, so that SignalDict
knows its history. Besides that, it acts like a dictionary which returns the latest signal in [A] when indexed with a mass-setting string.
The SignalProcessor
class is the main data-processing class of spectro_inlets_quantification. It can be loaded from a processor file containing data on non-linearity and background, or initiated directly. Either way, it can be given a peak_type
which specifies which Peak
class the instance, signal_processor
, uses. Its SignalProcessor.calc_signal()
method class takes in raw x-and-y data, corrects it for non-linearity and/or background, makes a Peak
, and then calculates the signal, adds it to its SignalDict
, and returns it.
The sensitivity
module
The sensitivity module contains several classes for managing sensitivity factors.
First, the SensitivityFactor
class is a wrapper around a single sensitivity factor. A sensitivity_factor
has the actual number in [C/mol] as its attribute SensitivityFactor.F
, with its attributes SensitivityFactor.mol
and SensitivityFactor.mass
specifying the molecule and mass-setting for which it applies. The SensitivityUnion
class can unite sensitivity factors with matching mol and mass. Its SensitivityUnion.F
is the average of those of its members, and it has a property SensitivityUnion.accuracy
telling the relative deviation thereof.
The SensitivityList
is a wrapper around a list of sensitivity factors with a SensitivityList.filter()
method that returns a smaller SensitivityList
based on any attribute of the sensitivity_factors
. It also has a SensitivityList.to_sensitivity_matrix()
method which takes mol_list
and mass_list
as arguments and passes them on, with the needed sensitivity_factors
to SensitivityMatrix
.
The SensitivityMatrix
class is the home of the central calculation in quantification, Equation (17) for counting flux, which is SensitivityMatrix.calc_n_dot()
. In this method, the inverse to SensitivityMatrix.F_mat
(\(\mat{F}\)) is taken and matrix multiplied onto the signals
or signal_dict
given as an argument, and the result is rearranged as a dictionary n_dot
. SensitivityMatrix.F_mat
is a matrix spanning SensitivityMatrix.mol_list
and SensitivityMatrix.mass_list
where any entry that was not available from the sensitivity_list
that initiated it is predicted by the method described in Section Predicting sensitivity factors (F-vs-f).
That prediction is done by the class SensitivityFit
. A sensitivity_fit
has a SensitivityFit.fit()
method which determines the parameters SensitivityFit.alpha
and SensitivityFit.beta
(\(\alpha\) and \(\beta\) in Equation (26)), and a SensitivityFit.plot_F_vs_f()
method for visualization (Figure 8).
The calibration
module
The calibration module defines two classes, each of which inherit from classes in the sensitivity
module.
CalPoint
inherits from SensitivityFactor
and adds to its parent metadata attributes and specs such as CalPoint.precision
and CalPoint.background_std
where the latter can be used to calculate its detection limit. A CalPoint
should be initialized directly with all of these attributes, which are descriptions of and results from a calibration experiment.
Calibration
inherits from SensitivityList
and adds to its parent methods for visualization, saving, loading, and fitting. Calibration
is the class for collecting and saving calibration results for later use. During quantification, a Calibration
is loaded and used to generate sensitivity_matrices
with an enhanced version of the inherited Calibration.make_sensitivity_matrix()
function. Calibration.fit
, whose parameters are saved and loaded with the CalPoints
, is passed on to the sensitivity matrices that calibration
makes. The fit is mainly to be able to sanity-check the calibration
, usually after filter
’ing for a specific setting. The Calibration.plot_as_spectrum()
method makes figures like Figure 7. It also has a Calibration.print_report()
method, which generates a text output report.
The quantifier
module
Finally, the quantifier module defines the Quantifier
class, which is initiated with a calibration_file
, a mol_list
and mass_list
, and a chip
, as well as a few other options. The quantifier
loads the calibration
from the file and immediately uses it to build a sensitivity_matrix
based on the mol_list
and mass_list
.
Most importantly, quantifier
binds the methods for quantification according to the procedure in Section (\vec{x}, \vec{y}) \rightarrow \vec{S} \rightarrow \vec{\dot{n}} \rightarrow \vec{p} \rightarrow \vec{c}:
Quantifier.calc_n_dot()
for flux quantification,Quantifier.calc_pp()
for partial pressure quantification, andQuantifier.calc_c()
for concentration quantification.
That concludes our tour of spectro_inlets_quantification, most of which is in the Ipython notebook. We hope you enjoyed it and find the tools and physics here useful!