def test_multiplyAndAddition(verbose=True, plot=False, *args, **kwargs): s = load_spec(getTestFile("CO_Tgas1500K_mole_fraction0.01.spec"), binary=True) s.update("radiance_noslit", verbose=False) s.apply_slit(0.1) s = Radiance(s) assert s.units["radiance"] == "mW/cm2/sr/nm" s_bis = add_constant(s, 1, "mW/cm2/sr/nm") w, Idiff = get_diff(s_bis, s, "radiance") test = Idiff[1] - 1 assert np.all(test < 1e-10) s_ter = multiply(multiply(s, 50), 1 / 50) # plot_diff(s_ter, s_5) diff = get_diff(s_ter, s, "radiance") ratio = abs(np.trapz(diff[1], x=diff[0]) / s.get_integral("radiance")) assert ratio < 1e-10
def test_invariants(*args, **kwargs): """ Ensures adding 0 or multiplying by 1 does not change the spectra """ from radis import load_spec from radis.test.utils import getTestFile s = load_spec(getTestFile("CO_Tgas1500K_mole_fraction0.01.spec")) s.update() s = Radiance_noslit(s) assert s.compare_with( add_constant(s, 0, "W/cm2/sr/nm"), plot=False, spectra_only="radiance_noslit" ) assert s.compare_with(multiply(s, 1), plot=False, spectra_only="radiance_noslit") assert 3 * s / 3 == s assert (1 + s) - 1 == s
def get_residual(s1, s2, var, norm='L2', ignore_nan=False, diff_window=0, normalize=False, normalize_how='max'): # type: (Spectrum, Spectrum, str, bool, int) -> np.array, np.array ''' Returns L2 norm of ``s1`` and ``s2`` For ``I1``, ``I2``, the values of variable ``var`` in ``s1`` and ``s2``, respectively, residual is calculated as: For ``L2`` norm: .. math:: res = \\frac{\\sqrt{\\sum_i {(s_1[i]-s_2[i])^2}}}{N}. For ``L1`` norm: .. math:: res = \\frac{\\sqrt{\\sum_i {|s_1[i]-s_2[i]|}}}{N}. Parameters ---------- s1, s2: :class:`~radis.spectrum.spectrum.Spectrum` objects if not on the same range, ``s2`` is resampled on ``s1``. var: str spectral quantity norm: 'L2', 'L1' which norm to use Other Parameters ---------------- ignore_nan: boolean if ``True``, ignore nan in the difference between s1 and s2 (ex: out of bound) when calculating residual. Default ``False``. Note: ``get_residual`` will still fail if there are nan in initial Spectrum. normalize: bool, or tuple if ``True``, normalize the two spectra before calculating the residual. If a tuple (ex: ``(4168, 4180)``), normalize on this range only. The unit is that of the first Spectrum. Ex:: s_exp # in 'nm' s_calc # in 'cm-1' get_residual(s_exp, s_calc, normalize=(4178, 4180)) # interpreted as 'nm' normalize_how: ``'max'``, ``'area'``, ``'mean'`` how to normalize. ``'max'`` is the default but may not be suited for very noisy experimental spectra. ``'area'`` will normalize the integral to 1. ``'mean'`` will normalize by the mean amplitude value Notes ----- 0 values for I1 yield nans except if I2 = I1 = 0 when s1 and s2 dont have the size wavespace range, they are automatically resampled through get_diff on 's1' range Implementation of ``L2`` norm:: np.sqrt((dI**2).sum())/len(dI) Implementation of ``L1`` norm:: np.abs(dI).sum()/len(dI) See Also -------- :func:`~radis.spectrum.compare.get_diff`, :func:`~radis.spectrum.compare.get_ratio`, :func:`~radis.spectrum.compare.get_distance`, :func:`~radis.spectrum.compare.plot_diff`, :func:`~radis.spectrum.compare.get_residual_integral`, :meth:`~radis.spectrum.spectrum.compare_with` ''' if normalize: from radis.spectrum.operations import multiply if isinstance(normalize, tuple): wmin, wmax = normalize w1, I1 = s1.get(var, copy=False) # (faster not to copy) b = (w1 > wmin) & (w1 < wmax) if normalize_how == 'max': norm1 = I1[b].max() elif normalize_how == 'mean': norm1 = I1[b].mean() elif normalize_how == 'area': norm1 = np.abs(np.trapz(I1[b], w1[b])) else: raise ValueError( 'Unexpected `normalize_how`: {0}'.format(normalize_how)) # now normalize s2. Ensure we use the same unit system! w2, I2 = s2.get(var, Iunit=s1.units[var], wunit=s1.get_waveunit()) b = (w2 > wmin) & (w2 < wmax) if normalize_how == 'max': norm2 = I2[b].max() elif normalize_how == 'mean': norm2 = I2[b].mean() elif normalize_how == 'area': norm2 = np.abs(np.trapz(I2[b], w2[b])) else: raise ValueError( 'Unexpected `normalize_how`: {0}'.format(normalize_how)) s1 = multiply(s1, 1 / norm1, var=var) s2 = multiply(s2, 1 / norm2, var=var) else: if normalize_how == 'max': norm1 = s1.get(var, copy=False)[1].max() norm2 = s2.get(var)[1].max() elif normalize_how == 'mean': norm1 = s1.get(var, copy=False)[1].mean() norm2 = s2.get(var)[1].mean() elif normalize_how == 'area': norm1 = s1.get_integral(var) norm2 = s2.get_integral(var, wunit=s1.get_waveunit(), Iunit=s1.units[var]) else: raise ValueError( 'Unexpected `normalize_how`: {0}'.format(normalize_how)) # Ensure we use the same unit system! s1 = multiply(s1, 1 / norm1, var=var) s2 = multiply(s2, 1 / norm2, var=var) # mask for 0 wdiff, dI = get_diff(s1, s2, var, resample=True, diff_window=diff_window) if ignore_nan: b = np.isnan(dI) wdiff, dI = wdiff[~b], dI[~b] warningText = 'NaN output in residual. You should use "ignore_nan=True". Read the help.' if norm == 'L2': output = np.sqrt((dI**2).sum()) / len(dI) if np.isnan(output): warn(warningText, UserWarning) return output elif norm == 'L1': output = (np.abs(dI)).sum() / len(dI) if np.isnan(output): warn.warning(warningText, UserWarning) return output else: raise ValueError('unexpected value for norm')