def normal_ordered_form(expr, independent=False, recursive_limit=10, _recursive_depth=0): """Write an expression with bosonic or fermionic operators on normal ordered form, where each term is normally ordered. Note that this normal ordered form is equivalent to the original expression. Parameters ========== expr : expression The expression write on normal ordered form. recursive_limit : int (default 10) The number of allowed recursive applications of the function. Examples ======== >>> from sympy.physics.quantum import Dagger >>> from sympy.physics.quantum.boson import BosonOp >>> from sympy.physics.quantum.operatorordering import normal_ordered_form >>> a = BosonOp("a") >>> normal_ordered_form(a * Dagger(a)) 1 + Dagger(a)*a """ if _recursive_depth > recursive_limit: warn.warning("Warning: too many recursions, aborting") return expr if isinstance(expr, Add): return _normal_ordered_form_terms(expr, recursive_limit=recursive_limit, _recursive_depth=_recursive_depth, independent=independent) elif isinstance(expr, Mul): return _normal_ordered_form_factor(expr, recursive_limit=recursive_limit, _recursive_depth=_recursive_depth, independent=independent) else: return expr
def normal_order(expr, recursive_limit=10, _recursive_depth=0): """Normal order an expression with bosonic or fermionic operators. Note that this normal order is not equivalent to the original expression, but the creation and annihilation operators in each term in expr is reordered so that the expression becomes normal ordered. Parameters ========== expr : expression The expression to normal order. recursive_limit : int (default 10) The number of allowed recursive applications of the function. Examples ======== >>> from sympy.physics.quantum import Dagger >>> from sympy.physics.quantum.boson import BosonOp >>> from sympy.physics.quantum.operatorordering import normal_order >>> a = BosonOp("a") >>> normal_order(a * Dagger(a)) Dagger(a)*a """ if _recursive_depth > recursive_limit: warn.warning("Warning: too many recursions, aborting") return expr if isinstance(expr, Add): return _normal_order_terms(expr, recursive_limit=recursive_limit, _recursive_depth=_recursive_depth) elif isinstance(expr, Mul): return _normal_order_factor(expr, recursive_limit=recursive_limit, _recursive_depth=_recursive_depth) else: return expr
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: if isinstance(normalize, tuple): wrange = normalize else: wrange = () wdiff, dI = get_diff( s1.take(var).normalize(wrange=wrange, normalize_how=normalize_how), s2.take(var).normalize(wrange=wrange, normalize_how=normalize_how), var, resample=True, diff_window=diff_window, ) else: 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")
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')