Example #3: non-equilibrium spectrum (Tvib, Trot, x_CO)¶
With the new fitting module introduced in fit_spectrum() function,
and in the example of Tgas fitting using new fitting module, we can see its 1-temperature fitting
performance for equilibrium condition.
This example features how new fitting module can fit non-equilibrium spectrum, with multiple fit parameters, such as vibrational/rotational temperatures, or mole fraction, etc.
This is a real fitting case introduced Grimaldi’s thesis: https://doi.org/10.2514/1.T6768 . This case features CO molecule emitting on a wide range of spectrum. This case also includes a user-defined trapezoid slit function, which is accounted by the distortion (dispersion) of the slit, as a result of the influences from experimental parameters and spectrometer dispersion parameters during the experiment.
======================= COMMENCE FITTING PROCESS =======================
Successfully retrieved the experimental data in 0.0006387233734130859s.
Acquired spectral quantity 'radiance' from the spectrum.
NaN values successfully purged.Number of data points left: 1479 points.
Successfully refined the experimental data in 0.0002295970916748047s.
0.17s - Loaded database
Commence fitting process for non-LTE spectrum!
/home/docs/checkouts/readthedocs.org/user_builds/radis/checkouts/develop/radis/misc/warning.py:434: PerformanceWarning: 'gu' was recomputed although 'gp' already in DataFrame. All values are equal
warnings.warn(WarningType(message))
[[Fit Statistics]]
# fitting method = L-BFGS-B
# function evals = 96
# data points = 1
# variables = 3
chi-square = 4.1191e-21
reduced chi-square = 4.1191e-21
Akaike info crit = -40.9386489
Bayesian info crit = -46.9386489
## Warning: uncertainties could not be estimated:
this fitting method does not natively calculate uncertainties
and numdifftools is not installed for lmfit to do this. Use
`pip install numdifftools` for lmfit to estimate uncertainties
with this fitting method.
[[Variables]]
Tvib: 4019.23956 (init = 6000)
Trot: 3213.32471 (init = 4000)
mole_fraction: 0.06307478 (init = 0.05)
Successfully finished the fitting process in 5.624126434326172s.
/home/docs/checkouts/readthedocs.org/user_builds/radis/checkouts/develop/radis/misc/curve.py:240: UserWarning: Presence of NaN in curve_divide!
Think about interpolation=2
warnings.warn(
======================== END OF FITTING PROCESS ========================
Residual history:
[np.float64(1.6884210236199499e-10), np.float64(1.6884210440381976e-10), np.float64(1.6884210060033468e-10), np.float64(1.688421067136535e-10), np.float64(3.7385607833419127e-10), np.float64(3.738560776891107e-10), np.float64(3.7385607874976396e-10), np.float64(3.7385607573061175e-10), np.float64(1.1128815368154832e-10), np.float64(1.1128815386673341e-10), np.float64(1.1128815415450849e-10), np.float64(1.1128815290701178e-10), np.float64(1.0954119407604127e-10), np.float64(1.095411945790136e-10), np.float64(1.0954119426916211e-10), np.float64(1.0954119410139886e-10), np.float64(1.0815468217516548e-10), np.float64(1.081546827629771e-10), np.float64(1.0815468230825383e-10), np.float64(1.0815468237197641e-10), np.float64(1.0308407699815074e-10), np.float64(1.0308407794778126e-10), np.float64(1.0308407689940763e-10), np.float64(1.0308407780252369e-10), np.float64(2.5622137633580595e-10), np.float64(2.5622137978645347e-10), np.float64(2.5622137609875424e-10), np.float64(2.5622137566526895e-10), np.float64(9.533545352732892e-11), np.float64(9.533545478807875e-11), np.float64(9.533545329633652e-11), np.float64(9.533545460776691e-11), np.float64(8.484278666606685e-11), np.float64(8.484278803539322e-11), np.float64(8.484278643134863e-11), np.float64(8.484278763673576e-11), np.float64(2.9421603805650496e-10), np.float64(2.942160348713639e-10), np.float64(2.942160387245155e-10), np.float64(2.942160369909142e-10), np.float64(7.545779416178807e-11), np.float64(7.545779518317105e-11), np.float64(7.54577940909344e-11), np.float64(7.545779462082892e-11), np.float64(6.932655577026052e-11), np.float64(6.932655439919306e-11), np.float64(6.932655641941991e-11), np.float64(6.932655441366059e-11), np.float64(7.949295401768293e-11), np.float64(7.949295541142762e-11), np.float64(7.949295374974318e-11), np.float64(7.949295492727656e-11), np.float64(6.814984180974783e-11), np.float64(6.814984127328906e-11), np.float64(6.814984222613549e-11), np.float64(6.814984098176355e-11), np.float64(6.719214701336819e-11), np.float64(6.71921466208809e-11), np.float64(6.719214730868505e-11), np.float64(6.719214635144555e-11), np.float64(6.549161959461511e-11), np.float64(6.5491619581456e-11), np.float64(6.549161947592724e-11), np.float64(6.549161940246052e-11), np.float64(6.525776498973532e-11), np.float64(6.525776500094872e-11), np.float64(6.525776485832874e-11), np.float64(6.525776484073401e-11), np.float64(6.423320863605763e-11), np.float64(6.423320849770837e-11), np.float64(6.423320864991242e-11), np.float64(6.423320853886716e-11), np.float64(6.418825491123364e-11), np.float64(6.418825498656769e-11), np.float64(6.418825488978427e-11), np.float64(6.4188254948713e-11), np.float64(6.418046440995909e-11), np.float64(6.418046440155933e-11), np.float64(6.418046441523032e-11), np.float64(6.418046440501189e-11), np.float64(6.418033839618138e-11), np.float64(6.418033839454073e-11), np.float64(6.418033839742568e-11), np.float64(6.418033839463649e-11), np.float64(6.41803259770893e-11), np.float64(6.418032597676107e-11), np.float64(6.418032597741024e-11), np.float64(6.418032597662923e-11), np.float64(6.418032367204677e-11), np.float64(6.418032367208248e-11), np.float64(6.418032367202962e-11), np.float64(6.418032367205845e-11), np.float64(6.418032366726754e-11), np.float64(6.418032366727056e-11), np.float64(6.418032366726585e-11), np.float64(6.418032366726905e-11), np.float64(6.418032366726754e-11)]
Fitted values history:
[6000.0, 4000.0, 0.05]
[6000.00002, 4000.0, 0.05]
[6000.0, 4000.000024494898, 0.05]
[6000.0, 4000.0, 0.0500000005]
[5105.589018638822, 4855.661711084132, 0.012435519381435901]
[5105.5890428942585, 4855.661711084132, 0.012435519381435901]
[5105.589018638822, 4855.661735829848, 0.012435519381435901]
[5105.589018638822, 4855.661711084132, 0.01243551971142224]
[5818.1902298659425, 4187.474366077638, 0.04066587315545442]
[5818.190251108292, 4187.474366077638, 0.04066587315545442]
[5818.1902298659425, 4187.4743908815235, 0.04066587315545442]
[5818.1902298659425, 4187.474366077638, 0.04066587364666456]
[5807.164852841079, 4147.480386703035, 0.041997575235356965]
[5807.164874151452, 4147.480386703035, 0.041997575235356965]
[5807.164852841079, 4147.480411453246, 0.041997575235356965]
[5807.164852841079, 4147.480386703035, 0.041997575728911545]
[5757.35968971065, 4111.453794611598, 0.04251231198035729]
[5757.359711318627, 4111.453794611598, 0.04251231198035729]
[5757.35968971065, 4111.453819307815, 0.04251231198035729]
[5757.35968971065, 4111.453794611598, 0.042512312474718955]
[5551.640563642928, 3968.2486534622326, 0.04457882939917948]
[5551.640586323431, 3968.2486534622326, 0.04457882939917948]
[5551.640563642928, 3968.2486778901684, 0.04457882939917948]
[5551.640563642928, 3968.2486534622326, 0.04457882989623189]
[2363.249376768358, 2028.034909542598, 0.08815003377117044]
[2363.2493637903126, 2028.034909542598, 0.08815003377117044]
[2363.249376768358, 2028.0349058091201, 0.08815003377117044]
[2363.249376768358, 2028.034909542598, 0.08815003409436928]
[5270.46034928257, 3795.364739489556, 0.04688423442172476]
[5270.460373065738, 3795.364739489556, 0.04688423442172476]
[5270.46034928257, 3795.3647634759877, 0.04688423442172476]
[5270.46034928257, 3795.364739489556, 0.04688423492075302]
[4949.513775661849, 3610.0316685439625, 0.049418538866642214]
[4949.513800254404, 3610.0316685439625, 0.049418538866642214]
[4949.513775661849, 3610.0316919062316, 0.049418538866642214]
[4949.513775661849, 3610.0316685439625, 0.0494185393666084]
[2440.7362736686623, 2341.042395445625, 0.07075972420068198]
[2440.7362878441095, 2341.042395445625, 0.07075972420068198]
[2440.7362736686623, 2341.0424080507905, 0.07075972420068198]
[2440.7362736686623, 2341.042395445625, 0.07075972465554832]
[4677.684454051518, 3460.7172196365955, 0.051517385561693434]
[4677.684478988293, 3460.7172196365955, 0.051517385561693434]
[4677.684454051518, 3460.7172423739903, 0.051517385561693434]
[4677.684454051518, 3460.7172196365955, 0.05151738606146314]
[4198.1387128777515, 3209.915463716623, 0.05518699198830375]
[4198.138737694841, 3209.915463716623, 0.05518699198830375]
[4198.1387128777515, 3209.9154851308285, 0.05518699198830375]
[4198.1387128777515, 3209.915463716623, 0.05518699248560598]
[4786.937523568357, 3491.189273237789, 0.05073182833636444]
[4786.937548403146, 3491.189273237789, 0.05073182833636444]
[4786.937523568357, 3491.1892961120125, 0.05073182833636444]
[4786.937523568357, 3491.189273237789, 0.05073182883631088]
[4316.412724865164, 3265.0317793454296, 0.054292006852435765]
[4316.412749797664, 3265.0317793454296, 0.054292006852435765]
[4316.412724865164, 3265.031801082158, 0.054292006852435765]
[4316.412724865164, 3265.0317793454296, 0.05429200735059023]
[4284.404410148909, 3228.845832072341, 0.05493288528636168]
[4284.404435055772, 3228.845832072341, 0.05493288528636168]
[4284.404410148909, 3228.845853599457, 0.05493288528636168]
[4284.404410148909, 3228.845832072341, 0.05493288578392239]
[4145.561159800911, 3098.522362436569, 0.057620449144262814]
[4145.561184548382, 3098.522362436569, 0.057620449144262814]
[4145.561159800911, 3098.5223831388885, 0.057620449144262814]
[4145.561159800911, 3098.522362436569, 0.05762044963842157]
[4126.632854965879, 3101.825177880715, 0.058242179053020315]
[4126.632879685501, 3101.825177880715, 0.058242179053020315]
[4126.632854965879, 3101.8251986053556, 0.058242179053020315]
[4126.632854965879, 3101.825177880715, 0.058242179546180176]
[4017.8316356185815, 3184.58345168471, 0.062491130889201156]
[4017.8316601492024, 3184.58345168471, 0.062491130889201156]
[4017.8316356185815, 3184.5834729442477, 0.062491130889201156]
[4017.8316356185815, 3184.58345168471, 0.06249113137334697]
[4030.630557947752, 3216.413561474998, 0.06286712005276221]
[4030.6305825031836, 3216.413561474998, 0.06286712005276221]
[4030.630557947752, 3216.413582928217, 0.06286712005276221]
[4030.630557947752, 3216.413561474998, 0.06286712053592235]
[4019.0353342818726, 3214.7623678999807, 0.06308862304274042]
[4019.0353588148564, 3214.7623678999807, 0.06308862304274042]
[4019.0353342818726, 3214.7623893433115, 0.06308862304274042]
[4019.0353342818726, 3214.7623678999807, 0.06308862352530523]
[4019.7015733526864, 3213.618119420504, 0.06306124378520396]
[4019.7015978869754, 3213.618119420504, 0.06306124378520396]
[4019.7015733526864, 3213.6181408569723, 0.06306124378520396]
[4019.7015733526864, 3213.618119420504, 0.06306124426784294]
[4019.465244631916, 3213.397877778115, 0.06306791802089486]
[4019.4652691657425, 3213.397877778115, 0.06306791802089486]
[4019.465244631916, 3213.3978992132616, 0.06306791802089486]
[4019.465244631916, 3213.397877778115, 0.06306791850351577]
[4019.2484811180757, 3213.320478275058, 0.06307448425482146]
[4019.2485056514774, 3213.320478275058, 0.06307448425482146]
[4019.2484811180757, 3213.3204997097396, 0.06307448425482146]
[4019.2484811180757, 3213.320478275058, 0.0630744847374246]
[4019.239555043352, 3213.3247117710193, 0.06307478481611177]
[4019.239579576736, 3213.3247117710193, 0.06307478481611177]
[4019.239555043352, 3213.3247332057267, 0.06307478481611177]
[4019.239555043352, 3213.3247117710193, 0.06307478529871409]
[4019.239555043352, 3213.3247117710193, 0.06307478481611177]
Total fitting time:
5.624126434326172 s
import astropy.units as u
import numpy as np
from radis import load_spec
from radis.test.utils import getTestFile
from radis.tools.new_fitting import fit_spectrum
# The following function and parameters reproduce the slit function in Dr. Corenti Grimaldi's thesis.
def slit_dispersion(w):
phi = -6.33
f = 750
gr = 300
m = 1
phi *= -2 * np.pi / 360
d = 1e-3 / gr
disp = (
w
/ (2 * f)
* (-np.tan(phi) + np.sqrt((2 * d / m / (w * 1e-9) * np.cos(phi)) ** 2 - 1))
)
return disp # nm/mm
slit = 1500 # µm
pitch = 20 # µm
top_slit_um = slit - pitch # µm
base_slit_um = slit + pitch # µm
center_slit = 5090
dispersion = slit_dispersion(center_slit)
top_slit_nm = top_slit_um * 1e-3 * dispersion
base_slit_nm = base_slit_um * 1e-3 * dispersion * 1.33
# -------------------- Step 1. Load experimental spectrum -------------------- #
specName = (
"Corentin_0_100cm_DownSampled_20cm_10pctCO2_1-wc-gw450-gr300-sl1500-acc5000-.spec"
)
s_experimental = load_spec(getTestFile(specName)).offset(-0.6, "nm")
# -------------------- Step 2. Fill ground-truths and data -------------------- #
# Experimental conditions which will be used for spectrum modeling. Basically, these are known ground-truths.
experimental_conditions = {
"molecule": "CO", # Molecule ID
"isotope": "1,2,3", # Isotope ID, can have multiple at once
"wmin": 2270
* u.nm, # Starting wavelength/wavenumber to be cropped out from the original experimental spectrum.
"wmax": 2400 * u.nm, # Ending wavelength/wavenumber for the cropping range.
"pressure": 1.01325
* u.bar, # Total pressure of gas, in "bar" unit by default, but you can also use Astropy units.
"path_length": 1
/ 195
* u.cm, # Experimental path length, in "cm" unit by default, but you can also use Astropy units.
"slit": { # Experimental slit. In simple form: "[value] [unit]", i.e. "-0.2 nm". In complex form: a dict with parameters of apply_slit()
"slit_function": (top_slit_nm, base_slit_nm),
"unit": "nm",
"shape": "trapezoidal",
"center_wavespace": center_slit,
"slit_dispersion": slit_dispersion,
"inplace": False,
},
"cutoff": 0, # (RADIS native) Discard linestrengths that are lower that this to reduce calculation time, in cm-1.
"databank": "hitemp", # Databank used for calculation. Must be stated.
}
# List of parameters to be fitted, accompanied by its initial value
fit_parameters = {
"Tvib": 6000, # Vibrational temperature, in K.
"Trot": 4000, # Rotational temperature, in K.
"mole_fraction": 0.05, # Species mole fraction, from 0 to 1.
}
# List of bounding ranges applied for those fit parameters above.
# You can skip this step and let it use default bounding ranges, but this is not recommended.
# Bounding range must be at format [<lower bound>, <upper bound>].
bounding_ranges = {
"Tvib": [2000, 7000],
"Trot": [2000, 7000],
"mole_fraction": [0, 0.1],
}
# Fitting pipeline setups.
fit_properties = {
"method": "lbfgsb", # Preferred fitting method. By default, "leastsq".
"fit_var": "radiance", # Spectral quantity to be extracted for fitting process, such as "radiance", "absorbance", etc.
"normalize": False, # Either applying normalization on both spectra or not.
"max_loop": 300, # Max number of loops allowed. By default, 200.
"tol": 1e-20, # Fitting tolerance, only applicable for "lbfgsb" method.
}
"""
For the fitting method, you can try one among 17 different fitting methods and algorithms of LMFIT,
introduced in `LMFIT method list <https://lmfit.github.io/lmfit-py/fitting.html#choosing-different-fitting-methods>`.
You can see the benchmark result of these algorithms here:
`RADIS Newfitting Algorithm Benchmark <https://github.com/radis/radis-benchmark/blob/master/manual_benchmarks/plot_newfitting_comparison_algorithm.py>`.
"""
# -------------------- Step 3. Run the fitting and retrieve results -------------------- #
# Conduct the fitting process!
s_best, result, log = fit_spectrum(
s_exp=s_experimental, # Experimental spectrum.
fit_params=fit_parameters, # Fit parameters.
bounds=bounding_ranges, # Bounding ranges for those fit parameters.
model=experimental_conditions, # Experimental ground-truths conditions.
pipeline=fit_properties, # # Fitting pipeline references.
)
# Now investigate the result logs for additional information about what's going on during the fitting process
print("\nResidual history: \n")
print(log["residual"])
print("\nFitted values history: \n")
for fit_val in log["fit_vals"]:
print(fit_val)
print("\nTotal fitting time: ")
print(log["time_fitting"], end=" s\n")
Total running time of the script: (0 minutes 6.445 seconds)

