Ejemplo n.º 1
0
def test_serial_operator(verbose=True, plot=False, *args, **kwargs):
    import matplotlib.pyplot as plt
    s = load_spec(getTestFile('CO_Tgas1500K_mole_fraction0.01.spec'))
    s.update()
    s1 = s.rescale_path_length(10, inplace=False)  # make non optically thin
    s2 = s.rescale_path_length(20, inplace=False)  # make non optically thin
    s3 = s.rescale_path_length(30, inplace=False)  # make non optically thin
    if plot:
        #        s.plot('radiance_noslit', lw=2, nfig='Line of sight (SerialSlabs): s > s > s')
        plt.figure('test_serial_operator').clear()
        SerialSlabs(s1, s2, s3).apply_slit(1).plot(nfig='same')
        ((s1 > s2) > s3).apply_slit(1).plot(nfig='same')
    assert SerialSlabs(s1, s2, s3).compare_with((s1 > s2) > s3,
                                                spectra_only=True,
                                                plot=False)
    assert (s1 > (s2 > s3)) == ((s1 > s2) > s3)
    # Forbidden syntax:
    with pytest.raises(ArithmeticError):
        assert SerialSlabs(s1, s2, s3).compare_with(s1 > s2 > s3,
                                                    spectra_only=True,
                                                    plot=False)
def test_compare_torch_CO2(verbose=True,
                           plot=False,
                           save=False,
                           warnings=True,
                           use_cache=True,
                           *args,
                           **kwargs):
    """Reproduce the plasma torch experiment of Packan 2003 in in atmospheric air

    Notes
    -----

    Thresholds parameters are reduced for a faster calculation time. For instance:

    - broadening_max_width should be 50 rather than 20
    - cutoff should be 1e-27 rather than 1e-25
    - wstep should be 0.01 or even 0.008 rather than 0.1

    Performance:

    - neq==0.9.20: Finished test_compare_torch_CO2 in 758.640324s

    - neq==0.9.21: Finished test_compare_torch_CO2 in 672s

    - neq==0.9.21*: (with ParallelFactory) Finished test_compare_torch_CO2 in 298s

    - neq==0.9.22: (Parallel + continuum) Finished in 65s
      RADIS 0.9.9 == neq 0.9.24

    - RADIS 0.9.26: Finished test_compare_torch_CO2 in 57s (DLM, no continuum)

    Reference
    --------

    Packan et al 2003 "Measurement and Modeling of OH, NO, and CO Infrared Radiation
    at 3400 K", JTHT

    """

    if plot:  # Make sure matplotlib is interactive so that test are not stuck in pytest
        plt.ion()

    t0 = time()

    # %% Conditions

    wlmin = 4100
    wlmax = 4900

    wmin = nm2cm(wlmax)
    wmax = nm2cm(wlmin)
    wstep = 0.1

    # Load concentration profile
    conds = pd.read_csv(
        getValidationCase(
            "test_compare_torch_CO2_data/test_compare_torch_CO2_conditions_JTHT2003.dat"
        ),
        comment="#",
        delim_whitespace=True,
    )
    slab_width = 0.05  # cm,  WARNING. Hardcoded (look up the table)

    # %% Calculate slabs

    # CO2
    sf = ParallelFactory(
        wavenum_min=wmin,
        wavenum_max=wmax,
        mole_fraction=None,
        path_length=None,
        molecule="CO2",
        isotope="1,2",
        parallel=False,
        wstep=wstep,
        db_use_cached=use_cache,
        export_lines=False,  # saves some memory
        export_populations=False,  # saves some memory
        cutoff=1e-25,
        Nprocs=cpu_count() - 1,  # warning with memory if too many procs
        broadening_max_width=20,
        # pseudo_continuum_threshold=0.01, # use pseudo-continuum, no DLM. Note : 56s on 20/08.
        # optimization=None,
        pseudo_continuum_threshold=
        0,  # use DLM, no pseudo-continuum. Note : 84s on 20/08
        optimization="min-RMS",
        verbose=False,
    )
    sf.warnings["MissingSelfBroadeningWarning"] = "ignore"
    sf.warnings["NegativeEnergiesWarning"] = "ignore"
    #        # Init database: only if we want to save all spectra being calculated
    # (discarded for the moment)
    #        if use_cache:
    #            sf.init_database('test_compare_torch_CO2_SpectrumDatabase_HITEMP_1e25',
    #                             add_info=['Tgas'])
    sf.init_databank("HITEMP-CO2-DUNHAM",
                     load_energies=False)  # saves some memory
    #    sf.init_databank('CDSD-4000')

    # CO
    sfco = ParallelFactory(
        wavenum_min=wmin,
        wavenum_max=wmax,
        mole_fraction=None,
        path_length=None,
        molecule="CO",
        isotope="1,2",
        parallel=False,
        wstep=wstep,
        db_use_cached=use_cache,
        export_lines=False,  # saves some memory
        export_populations=False,  # saves some memory
        cutoff=1e-25,
        Nprocs=cpu_count() - 1,
        broadening_max_width=20,
        optimization=None,
        verbose=False,
    )
    sfco.warnings["MissingSelfBroadeningWarning"] = "ignore"
    # Init database: only if we want to save all spectra being calculated
    # (discarded for the moment)
    #        if use_cache:
    #            sfco.init_database(
    #                'test_compare_torch_CO_SpectrumDatabase_HITEMP_1e25', add_info=['Tgas'])
    sfco.init_databank("HITEMP-CO-DUNHAM")

    # Calculate all slabs
    # .. CO2 at equilibrium
    slabsco2 = sf.eq_spectrum(list(conds.T_K),
                              mole_fraction=list(conds.CO2),
                              path_length=slab_width)
    # .. CO at equilibrium, but with non_eq to calculate PartitionFunctions instead of using
    # ... tabulated ones (which are limited to 3000 K in HAPI)
    slabsco = sfco.non_eq_spectrum(
        list(conds.T_K),
        list(conds.T_K),
        mole_fraction=list(conds.CO),
        path_length=slab_width,
    )

    # Room absorption
    with pytest.warns(
            UserWarning
    ):  # we expect a "using ParallelFactory for single case" warning
        s0 = sf.eq_spectrum(Tgas=300, mole_fraction=330e-6, path_length=600)[0]
    # Warning: This slab includes the CO2 emission from the 300 K air
    # within the spectrometer. But experimentally it is substracted
    # by there the chopper (this is corrected below)
    # ... see RADIS Article for more details

    # Add radiance for everyone if not calculated (ex: loaded from database)
    for s in slabsco2 + slabsco + [s0]:
        s.update()

    # Merge CO + CO2 for each slab
    slabstot = [MergeSlabs(s, sco) for (s, sco) in zip(slabsco2, slabsco)]

    # %% Line-of-sight

    # Solve ETR along line of sight
    # --------
    # two semi profile, + room absortion
    line_of_sight = slabstot[1:][::-1] + slabstot + [s0]
    stot = SerialSlabs(*line_of_sight)
    #        stot = SerialSlabs(*slabstot[1:][::-1], *slabstot, s0)  # Python 3 syntax only

    # Also calculate the contribution of pure CO
    # ---------
    s0tr = s0.copy()  # transmittance only
    s0tr.conditions["thermal_equilibrium"] = False
    s0tr._q["radiance_noslit"] *= 0  # hack to remove CO2 emission
    s0tr._q["emisscoeff"] *= 0  # hack to remove CO2 emission
    line_of_sight = slabsco[1:][::-1] + slabsco + [s0tr]
    sco = SerialSlabs(*line_of_sight)
    #        sco = SerialSlabs(*slabsco[1:][::-1], *slabsco, s0tr)  # Python 3 syntax only

    # Generate Slit
    # ------
    disp = 4  # dispersion conversion function (nm/mm)
    s_in = 1  # entrance slit (mm)
    s_out = 2.8  # exit slit (mm)
    top = (s_out - s_in) * disp
    base = (s_out + s_in) * disp
    slit_function = (top, base)  # (nm)

    # Final plot unit
    unit = "µW/cm2/sr"
    norm_by = "max"  # should be 'max' if unit ~ 'µW/cm2/sr',
    # 'area' if unit ~ 'µW/cm2/sr/nm'

    # Convolve with Slit
    # -------
    sco.apply_slit(slit_function,
                   unit="nm",
                   norm_by=norm_by,
                   shape="trapezoidal")
    stot.apply_slit(slit_function,
                    unit="nm",
                    norm_by=norm_by,
                    shape="trapezoidal")

    # Remove emission from within the spectrometer (substracted
    # by the chopper experimentaly)
    # -------
    s0spectro = s0.copy()
    s0spectro.rescale_path_length(75 * 4)  # spectrometer length
    s0spectro.apply_slit(slit_function,
                         unit="nm",
                         norm_by=norm_by,
                         shape="trapezoidal")
    _, I0spectro = s0spectro.get("radiance", Iunit=unit)

    wtot, Itot = stot.get("radiance", Iunit=unit)
    stot_corr = experimental_spectrum(
        wtot,
        Itot - I0spectro,  # hack to remove
        # emission from within
        # spectrometer
        Iunit=unit,
        conditions={"medium": "air"},
    )

    # %% Compare with experiment data

    # Plot experimental data
    # ------
    exp = pd.read_csv(
        getValidationCase(
            "test_compare_torch_CO2_data/test_compare_torch_CO2_spectrum_JTHT2003.dat"
        ),
        skiprows=5,
        delim_whitespace=True,
    )
    exp.w /= 10  # Angstrom to nm
    exp = exp[(exp.w > wlmin) & (exp.w < wlmax)]
    sexp = experimental_spectrum(exp.w,
                                 exp.I,
                                 Iunit="mW/cm2/sr",
                                 conditions={"medium": "air"})

    if plot:

        sexp.plot("radiance",
                  wunit="nm",
                  Iunit=unit,
                  lw=2,
                  label="Packan 2003")

        # Plot calculated
        # ----------

        stot.plot(
            "radiance",
            wunit="nm",
            Iunit=unit,
            nfig="same",
            color="r",
            ls="--",
            label="All: CO$_2$+CO",
        )

        # Plot internal spectrometer emission
        s0spectro.plot(
            "radiance",
            wunit="nm",
            Iunit=unit,
            nfig="same",
            color="b",
            label="CO$_2$ in Spectrometer",
        )

        stot_corr.plot(
            "radiance",
            wunit="nm",
            Iunit=unit,
            nfig="same",
            color="r",
            lw=2,
            label="All-CO$_2$ in Spectro",
            zorder=10,
        )

        sco.plot(
            "radiance",
            wunit="nm",
            Iunit=unit,
            nfig="same",
            color="g",
            ls="-",
            label="CO",
        )

        plt.ylim((0, 9))
        plt.legend(loc="upper right")

        if save:
            plt.savefig("test_compare_torch_CO2_brd20.png")
            plt.savefig("test_compare_torch_CO2_brd20k.pdf")

    assert get_residual(stot_corr, sexp, "radiance") < 0.02

    if verbose:
        print(("Finished test_compare_torch_CO2 in {0:.0f}s".format(time() -
                                                                    t0)))