def test_temperature_units_conversion(input_temperature, expected_temperature_K, verbose=True, *args, **kwargs): setup_test_line_databases() # add HITRAN-CO-TEST in ~/.radis if not there sf = SpectrumFactory( wavelength_min=4300, wavelength_max=4500, wstep=0.01, cutoff=1e-30, pressure=1, mole_fraction=1, isotope=[1], Tref=300 * u.K, verbose=verbose, ) sf.load_databank("HITRAN-CO-TEST") s = sf.eq_spectrum(Tgas=input_temperature, pressure=20 * u.mbar, path_length=1 * u.mm) assert np.isclose(s.conditions["Tgas"], expected_temperature_K) assert np.isclose(s.conditions["path_length"], 0.1) # cm assert np.isclose(s.conditions["pressure_mbar"], 20)
def test_media_line_shift(plot=False, verbose=True, warnings=True, *args, **kwargs): ''' See wavelength difference in air and vacuum ''' if plot: # Make sure matplotlib is interactive so that test are not stuck in pytest plt.ion() try: if verbose: printm('>>> _test_media_line_shift') setup_test_line_databases( ) # add HITRAN-CO-TEST in ~/.radis if not there sf = SpectrumFactory(wavelength_min=4500, wavelength_max=4600, wstep=0.001, parallel=False, bplot=False, cutoff=1e-30, path_length=0.1, mole_fraction=400e-6, isotope=[1], db_use_cached=True, medium='vacuum', broadening_max_width=10, verbose=verbose) sf.warnings['MissingSelfBroadeningWarning'] = 'ignore' sf.warnings['GaussianBroadeningWarning'] = 'ignore' sf.load_databank('HITRAN-CO-TEST') # Calculate a spectrum s = sf.eq_spectrum(2000) # Compare if plot: fig = plt.figure(fig_prefix + 'Propagating media line shift') s.plot('radiance_noslit', wunit='nm_vac', nfig=fig.number, lw=2, label='Vacuum') plt.title('CO spectrum (2000 K)') s.plot('radiance_noslit', wunit='nm', nfig=fig.number, lw=2, color='r', label='Air') # ... there should be about ~1.25 nm shift at 4.5 µm: assert np.isclose( s.get('radiance_noslit', wunit='nm_vac')[0][0] - s.get('radiance_noslit', wunit='nm')[0][0], 1.2540436086346745) except DatabankNotFound as err: assert IgnoreMissingDatabase(err, __file__, warnings)
def test_eq_vs_noneq_isotope(verbose=True, plot=False, warnings=True, *args, **kwargs): ''' Test same spectrum for 2 different calculation codes (equilibrium, non-equilibrium) in the presence of isotopes Notes ----- On the old NeQ package the test used [HITEMP-2010]_ Starting from RADIS 1.0.1, the test is run on [HITRAN-2016]_, which is not valid for these temperatures but can be more conveniently downloaded automatically and thus executed everytime with [Travis]_ ''' try: Tgas = 1500 sf = SpectrumFactory(wavelength_min=4250, wavelength_max=4350, mole_fraction=1, path_length=1, cutoff=1e-25, molecule='CO2', isotope='1,2', db_use_cached=True, verbose=verbose) sf.warnings['MissingSelfBroadeningWarning'] = 'ignore' sf.warnings['NegativeEnergiesWarning'] = 'ignore' sf.warnings['HighTemperatureWarning'] = 'ignore' sf.fetch_databank( ) # uses HITRAN: not really valid at this temperature, but runs on all machines without install # sf.load_databank('HITEMP-CO2-DUNHAM') s_nq = sf.non_eq_spectrum(Tvib=Tgas, Trot=Tgas, name='Non-eq') s_eq = sf.eq_spectrum(Tgas=Tgas, name='Eq') rtol = 5e-3 # 2nd isotope calculated with placeholder energies match_eq_vs_non_eq = s_eq.compare_with(s_nq, spectra_only='abscoeff', rtol=rtol, plot=plot) match_eq_vs_non_eq *= s_eq.compare_with(s_nq, spectra_only='radiance_noslit', rtol=rtol, plot=plot) if verbose: printm('Tested eq vs non-eq (<{0:.1f}% error) with isotopes: {1}'. format(rtol * 100, bool(match_eq_vs_non_eq))) assert match_eq_vs_non_eq except DatabankNotFound as err: assert IgnoreMissingDatabase(err, __file__, warnings)
def test_eq_vs_noneq_isotope(verbose=True, plot=False, warnings=True, *args, **kwargs): """Test same spectrum for 2 different calculation codes (equilibrium, non-equilibrium) in the presence of isotopes Notes ----- On the old NeQ package the test used [HITEMP-2010]_ Starting from RADIS 1.0.1, the test is run on [HITRAN-2016]_, which is not valid for these temperatures but can be more conveniently downloaded automatically and thus executed everytime with `Travis CI <https://travis-ci.com/radis/radis>`_ """ Tgas = 1500 sf = SpectrumFactory( wavelength_min=4250, wavelength_max=4350, mole_fraction=1, path_length=1, cutoff=1e-25, molecule="CO2", isotope="1,2", db_use_cached=True, verbose=verbose, ) sf.warnings["MissingSelfBroadeningWarning"] = "ignore" sf.warnings["NegativeEnergiesWarning"] = "ignore" sf.warnings["HighTemperatureWarning"] = "ignore" sf.fetch_databank( ) # uses HITRAN: not really valid at this temperature, but runs on all machines without install # sf.load_databank('HITEMP-CO2-DUNHAM') s_nq = sf.non_eq_spectrum(Tvib=Tgas, Trot=Tgas, name="Non-eq") s_eq = sf.eq_spectrum(Tgas=Tgas, name="Eq") rtol = 5e-3 # 2nd isotope calculated with placeholder energies match_eq_vs_non_eq = s_eq.compare_with(s_nq, spectra_only="abscoeff", rtol=rtol, plot=plot) match_eq_vs_non_eq *= s_eq.compare_with(s_nq, spectra_only="radiance_noslit", rtol=rtol, plot=plot) if verbose: printm( "Tested eq vs non-eq (<{0:.1f}% error) with isotopes: {1}".format( rtol * 100, bool(match_eq_vs_non_eq))) assert match_eq_vs_non_eq
def _distribute_eq_spectrum(args): ''' Clone the Factory and calculate eq_spectrum over several clones ''' cast_factory, Tgas, mole_fraction, path_length = args # ... (dev) must match p.map(_distribute_eq_spectrum...) order factory = deepcopy(cast_factory) # Update id factory._id = uuid1() return SpectrumFactory.eq_spectrum(factory, Tgas, mole_fraction=mole_fraction, path_length=path_length)
def test_media_line_shift(plot=False, verbose=True, warnings=True, *args, **kwargs): """ See wavelength difference in air and vacuum """ if plot: # Make sure matplotlib is interactive so that test are not stuck in pytest plt.ion() if verbose: printm(">>> _test_media_line_shift") setup_test_line_databases() # add HITRAN-CO-TEST in ~/.radis if not there sf = SpectrumFactory( wavelength_min=4500, wavelength_max=4600, wstep=0.001, parallel=False, bplot=False, cutoff=1e-30, path_length=0.1, mole_fraction=400e-6, isotope=[1], db_use_cached=True, medium="vacuum", broadening_max_width=10, verbose=verbose, ) sf.warnings["MissingSelfBroadeningWarning"] = "ignore" sf.warnings["GaussianBroadeningWarning"] = "ignore" sf.load_databank("HITRAN-CO-TEST") # Calculate a spectrum s = sf.eq_spectrum(2000) # Compare if plot: fig = plt.figure(fig_prefix + "Propagating media line shift") s.plot("radiance_noslit", wunit="nm_vac", nfig=fig.number, lw=2, label="Vacuum") plt.title("CO spectrum (2000 K)") s.plot( "radiance_noslit", wunit="nm", nfig=fig.number, lw=2, color="r", label="Air", ) # ... there should be about ~1.25 nm shift at 4.5 µm: assert np.isclose( s.get("radiance_noslit", wunit="nm_vac")[0][0] - s.get("radiance_noslit", wunit="nm")[0][0], 1.2540436086346745, )
def test_populations(verbose=True, *args, **kwargs): """ Test that vib and rovib populations are calculated correctly """ from radis.lbl import SpectrumFactory from radis.misc.basics import all_in export = ["vib", "rovib"] sf = SpectrumFactory( 2000, 2300, export_populations=export, db_use_cached=True, cutoff=1e-25, isotope="1", ) sf.warnings.update({ "MissingSelfBroadeningWarning": "ignore", "VoigtBroadeningWarning": "ignore" }) sf.load_databank("HITRAN-CO-TEST") s = sf.non_eq_spectrum(2000, 2000) pops = sf.get_populations(export) if not all_in(["rovib", "vib"], list(pops["CO"][1]["X"].keys())): raise AssertionError( "vib and rovib levels should be defined after non_eq_spectrum calculation!" ) if not "nvib" in list(pops["CO"][1]["X"]["vib"].keys()): raise AssertionError( "Vib populations should be defined after non_eq_spectrum calculation!" ) s = sf.eq_spectrum(300) pops = sf.get_populations(export) if "nvib" in list(pops["CO"][1]["X"]["vib"].keys()): raise AssertionError( "Vib levels should not be defined anymore after eq_spectrum calculation!" ) # Any of these is True and something went wrong s = sf.non_eq_spectrum(2000, 2000) s2 = sf.non_eq_spectrum(300, 300) # printm(all(s2.get_vib_levels(isotope=1) == s.get_vib_levels(isotope=1))) assert not (s2.get_vib_levels() is s.get_vib_levels()) assert not (s2.get_rovib_levels() == s.get_rovib_levels()).all().all() assert not (s2.get_rovib_levels() is s.get_rovib_levels()) return True # if no AssertionError
def test_load_spectrum(plot=False, verbose=True, warnings=True, *args, **kwargs): ''' Test load / save Fast version: dont save lines / populations, compare spectra only ''' setup_test_line_databases() temp_file_name = '_test_database_co2_tempfile.spec' assert (not exists(temp_file_name)) try: sf = SpectrumFactory( wavelength_min=4190, wavelength_max=4200, mole_fraction=400e-6, path_length=0.1, # cm isotope=[1], db_use_cached=True, cutoff=1e-20, verbose=verbose) sf.warnings['MissingSelfBroadeningWarning'] = 'ignore' sf.load_databank('HITRAN-CO2-TEST') s1 = sf.eq_spectrum(Tgas=300) s1.apply_slit(2, verbose=False) s1.update() s2 = load_spec(s1.store(temp_file_name, compress=True)) s2.update() if plot: fig = plt.figure(fig_prefix + 'Calculated vs stored+retrieved') s1.plot('absorbance', nfig=fig.number, lw=3, label='calculated') s2.plot('absorbance', nfig=fig.number, color='r', label='stored (compressed) and retrieved') plt.legend() assert s1.compare_with(s2, spectra_only=True, plot=False) except DatabankNotFound as err: assert IgnoreMissingDatabase(err, __file__, warnings) finally: # cleaning if exists(temp_file_name): os.remove(temp_file_name) return True
def test_load_spectrum(plot=False, verbose=True, warnings=True, *args, **kwargs): """Test load / save Fast version: dont save lines / populations, compare spectra only """ setup_test_line_databases() temp_file_name = "_test_database_co2_tempfile.spec" assert not exists(temp_file_name) try: sf = SpectrumFactory( wavelength_min=4190, wavelength_max=4200, mole_fraction=400e-6, path_length=0.1, # cm isotope=[1], db_use_cached=True, cutoff=1e-20, verbose=verbose, ) sf.warnings["MissingSelfBroadeningWarning"] = "ignore" sf.load_databank("HITRAN-CO2-TEST") s1 = sf.eq_spectrum(Tgas=300) s1.apply_slit(2, verbose=False) s1.update() s2 = load_spec(s1.store(temp_file_name, compress=True)) s2.update() if plot: fig = plt.figure(fig_prefix + "Calculated vs stored+retrieved") s1.plot("absorbance", nfig=fig.number, lw=3, label="calculated") s2.plot( "absorbance", nfig=fig.number, color="r", label="stored (compressed) and retrieved", ) plt.legend() assert s1.compare_with(s2, spectra_only=True, plot=False) finally: # cleaning if exists(temp_file_name): os.remove(temp_file_name) return True
def test_populations(verbose=True, *args, **kwargs): ''' Test that vib and rovib populations are calculated correctly ''' from radis.lbl import SpectrumFactory from radis.misc.basics import all_in export = ['vib', 'rovib'] sf = SpectrumFactory(2000, 2300, export_populations=export, db_use_cached=True, cutoff=1e-25, isotope='1') sf.warnings.update({ 'MissingSelfBroadeningWarning': 'ignore', 'VoigtBroadeningWarning': 'ignore' }) sf.load_databank('HITRAN-CO-TEST') s = sf.non_eq_spectrum(2000, 2000) pops = sf.get_populations(export) if not all_in(['rovib', 'vib'], list(pops['CO'][1]['X'].keys())): raise AssertionError( 'vib and rovib levels should be defined after non_eq_spectrum calculation!' ) if not 'nvib' in list(pops['CO'][1]['X']['vib'].keys()): raise AssertionError( 'Vib populations should be defined after non_eq_spectrum calculation!' ) s = sf.eq_spectrum(300) pops = sf.get_populations(export) if 'nvib' in list(pops['CO'][1]['X']['vib'].keys()): raise AssertionError( 'Vib levels should not be defined anymore after eq_spectrum calculation!' ) # Any of these is True and something went wrong s = sf.non_eq_spectrum(2000, 2000) s2 = sf.non_eq_spectrum(300, 300) #printm(all(s2.get_vib_levels(isotope=1) == s.get_vib_levels(isotope=1))) assert not (s2.get_vib_levels() is s.get_vib_levels()) assert not (s2.get_rovib_levels() == s.get_rovib_levels()).all().all() assert not (s2.get_rovib_levels() is s.get_rovib_levels()) return True # if no AssertionError
def test_pathlength_units_conversion( input_pathlength, expected_pathlength_cm, verbose=True, *args, **kwargs ): setup_test_line_databases() # add HITRAN-CO-TEST in ~/.radis if not there sf = SpectrumFactory( wavelength_min=4300, wavelength_max=4500, wstep=0.01, cutoff=1e-30, pressure=1, path_length=input_pathlength, mole_fraction=1, isotope=[1], verbose=verbose, ) sf.load_databank("HITRAN-CO-TEST") s = sf.eq_spectrum(Tgas=300) assert np.isclose(s.conditions["path_length"], expected_pathlength_cm)
def test_wavenumber_units_conversion( input_wavenumbers, expected_wavenumbers_cm1, verbose=True, *args, **kwargs ): setup_test_line_databases() # add HITRAN-CO-TEST in ~/.radis if not there wmin, wmax = input_wavenumbers expected_wmin, expected_wmax = expected_wavenumbers_cm1 sf = SpectrumFactory( wavenum_min=wmin, wavenum_max=wmax, wstep=0.01, cutoff=1e-30, pressure=1, path_length=1, mole_fraction=1, isotope=[1], verbose=verbose, ) sf.load_databank("HITRAN-CO-TEST") s = sf.eq_spectrum(Tgas=300) assert np.isclose(s.get_wavenumber().min(), expected_wmin) assert np.isclose(s.get_wavenumber().max(), expected_wmax)
def test_spec_generation(plot=True, verbose=2, warnings=True, *args, **kwargs): """ Test spectrum generation Can be used as a base to generate spectra in your codes Non-regression test: compare with past version (see conditions below) Compare results from a reference case to results calculated on 30/12/2017 This is not a validation case (30/12/2017 results are not a physically validated case), but it makes sure results dont change over time Conditions (30/12/2017):: Physical Conditions ---------------------------------------- Tgas 300 K Trot 300 K Tvib 300 K pressure 1.01325 bar isotope 1,2 mole_fraction 1 molecule CO2 path_length 1 cm wavelength_max 4400.0 nm wavelength_min 4150.0 nm wavenum_max 2409.6385542168673 cm-1 wavenum_min 2272.7272727272725 cm-1 Computation Parameters ---------------------------------------- Tref 296 K broadening_max_width 10 cm-1 cutoff 1e-25 cm-1/(#.cm-2) db_assumed_sorted True db_use_cached True dbformat cdsd dbpath # USER-DEPENDANT: CDSD-HITEMP fillmissinglevelswithzero False levelsfmt cdsd levelspath # USER-DEPENDANT: CDSD-4000 medium vacuum parfuncfmt cdsd parfuncpath # USER-DEPENDANT: CDSD-4000 rot_distribution boltzmann self_absorption True vib_distribution boltzmann wavenum_max_calc 2414.6385542168673 cm-1 wavenum_min_calc 2267.7272727272725 cm-1 waveunit cm-1 wstep 0.01 cm-1 ---------------------------------------- Notes ----- Performance test. How long it tooks to calculate this Spectrum? Test with cutoff 1e-25, broadening_max_width=10 - 0.9.15: >>> 33s - 0.9.16*: (replaced groupby().apply() with iteration over indexes) >>> 32s [but large impact expected on big files] - 0.9.16*: (upgraded cache files to h5) >>> 25s - 0.9.16*: (also added h5 cache file for levels) >>> 21s - 0.9.16*: (with Whiting slit voigt function) >>> 5.8s Test with cutoff 1e-27, broadening_max_width=50 : ("Spectrum calculated in ... ", including database loading time) - 0.9.16*: (same code as last) >>> 12.5s including 7.6s of broadening - 0.9.16**: (with pseudo_continuum_threshold=0.01) >>> 7.8s including 2.3s of broadening - 0.9.18 (normal code, no pseudo continuum). >>> ? - 0.9.21 (normal code) >>> 13.7s, including 8.7s of broadening (with pseudo_continuum_threshold=0.01) >>> 4.3s, including 2.6s of broadening - 0.9.21* >>> 14.0s (added the manual lineshape normalization instead of Whitings's polynomial) - 0.9.22 (normal code) >>> 11.3s (without energy level lookup, for eq. calculations) (with pseudo_continuum_threshold=0.01) >>> 5.9s - 0.9.23 (normal code) >>> 7.2s (added jit in Voigt broadening) >>> 7.1s (chunksize = None) (and much faster for more lines) (with pseudo_continuum_threshold=0.01) >>> 4.9s RADIS: - 0.9.19 (normal code) >>> 6.3 s - 0.9.20 (normal code) >>> 6.3 s (with pseudo_continuum_threshold=0.01) >>> ??? (with DLM) >>> 2.3 s """ if plot: # Make sure matplotlib is interactive so that test are not stuck in pytest plt.ion() from time import time t0 = time() if verbose: printm(">>> _test_spec_generation") # This is how you get a spectrum (see calc.py for front-end functions # that do just that) sf = SpectrumFactory( wavelength_min=4150, wavelength_max=4400, parallel=False, bplot=False, cutoff=1e-27, isotope="1,2", db_use_cached=True, broadening_max_width=50, # chunksize='DLM', # pseudo_continuum_threshold=0.01, medium="vacuum", verbose=verbose, ) sf.warnings["MissingSelfBroadeningWarning"] = "ignore" sf.warnings["NegativeEnergiesWarning"] = "ignore" sf.load_databank( "HITEMP-CO2-DUNHAM", load_energies=False, # no need to load energies at equilibrium ) s = sf.eq_spectrum(Tgas=300) if verbose: printm( ">>> _test_spec_generation: Spectrum calculated in {0:.2f}s".format( time() - t0 ) ) if plot: plt.figure(fig_prefix + "Reference spectrum CDSD-HITEMP (radiance)") # Iunit is arbitrary. Use whatever makes sense s.plot("radiance_noslit", Iunit="µW/cm2/sr/nm", nfig="same") s.rescale_path_length(0.01) # Here we get some extra informations: if plot: sf.plot_broadening(i=0) # show broadening of one line plt.xlim((2267.20, 2268.30)) # Compare with harcoded results # ... code previously used to export hardcoded results: # ... and header contains all input conditions: # np.savetxt('output.txt', np.vstack(s.get('abscoeff', wunit='nm')).T[::10]) # print(s) # ................ from radis.test.utils import getTestFile wref, Iref = np.loadtxt(getTestFile("CO2abscoeff_300K_4150_4400nm.txt")).T match_reference = np.allclose(s.get("abscoeff", wunit="nm")[1][::10], Iref) if not match_reference: # give some more information before raising error printm( "Error: {0:.2f}%".format( np.mean(abs(s.get("abscoeff", wunit="nm")[1][::10] / Iref - 1)) * 100 ) ) # Store the faulty spectrum s.store( "test_factory_failed_{0}.spec".format(radis.get_version()), if_exists_then="replace", ) # Plot comparison if plot: plt.figure(fig_prefix + "Reference spectrum (abscoeff)") # , show_points=True) # show_points to have an s.plot( "abscoeff", wunit="nm", medium="air", nfig="same", lw=3, label="RADIS, this version", ) # idea of the resolution plt.plot(wref, Iref, "or", ms=3, label="version NEQ 0.9.20 (12/05/18)") plt.legend() plt.title("All close: {0}".format(match_reference)) plt.tight_layout() # Another example, at higher temperature. # Removed because no test is associated with it and it takes time for # nothing # s2 = sf.non_eq_spectrum(Tvib=1000, Trot=300) # if plot: s2.plot('abscoeff', wunit='nm') if verbose: printm( "Spectrum calculation (no database loading) took {0:.1f}s\n".format( s.conditions["calculation_time"] ) ) printm("_test_spec_generation finished in {0:.1f}s\n".format(time() - t0)) assert match_reference
def test_optically_thick_limit_1iso(verbose=True, plot=True, *args, **kwargs): """ Test that we find Planck in the optically thick limit In particular, this test will fail if : - linestrength are not properly calculated - at noneq, linestrength and emission integrals are mixed up The test should be run for 1 and several isotopes, because different calculations paths are used internally, and this can lead to different errors. Also, this test is used to run with DEBUG_MODE = True, which will check that isotopes and molecule ids are what we expect in all the groupby() loops that make the production code very fast. Notes ----- switched from large band calculation with [HITRAN-2016]_ to a calculation with the embedded [HITEMP-2010]_ fragment (shorter range, but no need to download files) """ if plot: # Make sure matplotlib is interactive so that test are not stuck in pytest plt.ion() # Force DEBUG_MODE DEBUG_MODE = radis.DEBUG_MODE radis.DEBUG_MODE = True try: wavenum_min = 2284.2 wavenum_max = 2284.6 P = 0.017 # bar wstep = 0.001 # cm-1 Tgas = 1200 # %% Generate some CO2 emission spectra # -------------- sf = SpectrumFactory( wavenum_min=wavenum_min, wavenum_max=wavenum_max, molecule="CO2", mole_fraction=1, path_length=0.05, cutoff=1e-25, broadening_max_width=1, export_populations=False, #'vib', export_lines=False, isotope=1, use_cached=True, wstep=wstep, pseudo_continuum_threshold=0, pressure=P, verbose=False, ) # sf.fetch_databank('astroquery') sf.warnings["NegativeEnergiesWarning"] = "ignore" sf.load_databank("HITEMP-CO2-TEST") pb = ProgressBar(3, active=verbose) s_eq = sf.eq_spectrum(Tgas=Tgas, mole_fraction=1, name="Equilibrium") pb.update(1) s_2T = sf.non_eq_spectrum(Tvib=Tgas, Trot=Tgas, mole_fraction=1, name="Noneq (2T)") pb.update(2) s_4T = sf.non_eq_spectrum(Tvib=(Tgas, Tgas, Tgas), Trot=Tgas, mole_fraction=1, name="Noneq (4T)") pb.update(3) s_plck = sPlanck( wavelength_min=2000, # =wavelength_min, wavelength_max= 5000, # =wavelength_max - wstep, # there is a border effect on last point T=Tgas, ) pb.done() # %% Post process: # MAke optically thick, and compare with Planck for s in [s_eq, s_2T, s_4T]: s.rescale_path_length(1e6) if plot: nfig = "test_opt_thick_limit_1iso {0}".format(s.name) plt.figure(nfig).clear() s.plot(wunit="nm", nfig=nfig, lw=4) s_plck.plot(wunit="nm", nfig=nfig, Iunit="mW/cm2/sr/nm", lw=2) plt.legend() if verbose: printm( "Residual between opt. thick CO2 spectrum ({0}) and Planck: {1:.2g}" .format( s.name, get_residual(s, s_plck, "radiance_noslit", ignore_nan=True), )) # assert get_residual(s, s_plck, 'radiance_noslit', ignore_nan=True) < 1e-3 assert get_residual(s, s_plck, "radiance_noslit", ignore_nan=True) < 0.9e-4 if verbose: printm("Tested optically thick limit is Planck (1 isotope): OK") finally: # Reset DEBUG_MODE radis.DEBUG_MODE = DEBUG_MODE
def test_populations(plot=True, verbose=True, warnings=True, *args, **kwargs): """ See wavelength difference in air and vacuum """ if plot: # Make sure matplotlib is interactive so that test are not stuck in pytest plt.ion() try: if verbose: printm(">>> _test_media_line_shift") setup_test_line_databases( ) # add HITRAN-CO-TEST in ~/.radis if not there sf = SpectrumFactory( wavelength_min=4500, wavelength_max=4600, wstep=0.001, parallel=False, bplot=False, cutoff=1e-30, path_length=0.1, mole_fraction=400e-6, isotope=[1], db_use_cached=True, medium="vacuum", broadening_max_width=10, export_populations="rovib", verbose=verbose, ) sf.warnings["MissingSelfBroadeningWarning"] = "ignore" sf.load_databank("HITRAN-CO-TEST") # Populations cannot be calculated at equilibrium (no access to energy levels) s = sf.eq_spectrum(300) with pytest.raises(ValueError): # .. we expect this error here! pops = s.get_populations("CO", isotope=1, electronic_state="X") # Calculate populations using the non-equilibrium module: s = sf.non_eq_spectrum(300, 300) pops = s.get_populations("CO", isotope=1, electronic_state="X") if not "n" in list(pops["rovib"].keys()): raise ValueError("Populations not calculated") if plot: s.plot_populations() # Compare with factory # Plot populations: with pytest.raises(ValueError): sf.plot_populations() # no isotope given: error expected if plot: sf.plot_populations("rovib", isotope=1) plt.close() # no need to keep it open, we just tested the function # Test calculated quantities are there assert hasattr(sf.df1, "Qref") assert hasattr(sf.df1, "Qvib") assert hasattr(sf.df1, "Qrotu") assert hasattr(sf.df1, "Qrotl") # Test hardcoded populations assert np.isclose(pops["rovib"]["n"].iloc[0], 0.0091853446840826653) assert np.isclose(pops["rovib"]["n"].iloc[1], 0.027052543988733215) assert np.isclose(pops["rovib"]["n"].iloc[2], 0.04345502115897712) return True except DatabankNotFound as err: assert IgnoreMissingDatabase(err, __file__, warnings)
def test_all_calc_methods_CO2pcN(verbose=True, plot=False, warnings=True, rtol=1e-3, *args, **kwargs): """Test same spectrum for 3 different calculation variants (equilibrium, non-equilibrium, per band and recombine Uses CO2 Levels database where the energy partitioning is done as follow: 2 nonequilibrium modes Evib is the minimum of a "p,c,N" group Erot = E - Evib This corresponds to the levelsfmt = 'cdsd-pcN' in :data:`~radis.lbl.loader.KNOWN_LVLFORMAT` """ from radis.misc.config import getDatabankEntries from radis.test.utils import ( define_Evib_as_min_of_polyad, discard_lines_with_na_levels, setup_test_line_databases, ) if plot: # Make sure matplotlib is interactive so that test are not stuck in pytest import matplotlib.pyplot as plt plt.ion() #%% Tgas = 500 iso = 1 sf = SpectrumFactory( wavenum_min=2284, wavenum_max=2285, broadening_max_width=5, # TODO @EP: crashes with 0.3? mole_fraction=1, path_length=0.025, cutoff=1e-25, molecule="CO2", isotope=iso, db_use_cached=True, lvl_use_cached=True, verbose=verbose, ) sf.warnings["MissingSelfBroadeningWarning"] = "ignore" sf.warnings["NegativeEnergiesWarning"] = "ignore" sf.warnings["HighTemperatureWarning"] = "ignore" # Preparation: setup_test_line_databases() # Generate a Levels database with p,c,N energy partitioning # ... copy "HITEMP-CO2-HAMIL-TEST" info database_kwargs = getDatabankEntries("HITEMP-CO2-HAMIL-TEST") # ... adapt it to 'cdsd-pcN' mode del database_kwargs["info"] database_kwargs["levelsfmt"] = "cdsd-pcN" # ... load the new database sf.load_databank(**database_kwargs) # Now, define Evib: Q_calc = sf.parsum_calc["CO2"][1]["X"] Q_calc.df = define_Evib_as_min_of_polyad(Q_calc.df, keys=["p", "c", "N"]) # With this Evib definition, clean the Lines database from where Evib is not defined # (because Levels does not exist in the reduced, test Level Database) discard_lines_with_na_levels(sf) # %%--------------------- # Ready, let's start the tests: s_bands = sf.non_eq_bands(Tvib=Tgas, Trot=Tgas) lvl = LevelsList(sf.parsum_calc["CO2"][iso]["X"], s_bands, sf.params.levelsfmt) s_bd = lvl.non_eq_spectrum(Tvib=Tgas, Trot=Tgas) s_nq = sf.non_eq_spectrum(Tvib=Tgas, Trot=Tgas) s_eq = sf.eq_spectrum(Tgas=Tgas) # if plot: fig = plt.figure(fig_prefix + "Compare all calc methods") s_bd.plot(nfig=fig.number, color="b", lw=5, label="from bands code") s_nq.plot(nfig=fig.number, lw=3, label="non eq code") s_eq.plot(nfig=fig.number, lw=2, color="r", label="equilibrum code") plt.legend() assert np.isclose(s_bd.get_integral("abscoeff"), s_nq.get_integral("abscoeff"), rtol=rtol) assert np.isclose(s_bd.get_integral("abscoeff"), s_eq.get_integral("abscoeff"), rtol=rtol) assert np.isclose(s_nq.get_integral("abscoeff"), s_eq.get_integral("abscoeff"), rtol=rtol) # TODO @EP: assertion fail in emission. This is due to the slight shift # in intensity also observed in the Planck test (test_base.py::test_optically_thick_limit_1iso()). # assert np.isclose(s_bd.get_power(), s_nq.get_power(), rtol=rtol) # assert np.isclose(s_bd.get_power(), s_eq.get_power(), rtol=rtol) # assert np.isclose(s_nq.get_power(), s_eq.get_power(), rtol=rtol) return True
def test_populations_CO2_hamiltonian( plot=True, verbose=True, warnings=True, *args, **kwargs ): """Calculate nonequilibrium modes with the CO2 Hamiltonian ..warning:: as we only use a reduced set of the CO2 effective Hamiltonian (< 3000 cm-1), many levels of the Line Database will not appear in the Levels Database. We will need to either filter the Line Database beforehand, or run it a first time and remove all levels not found. This database is obviously not to be used in a Production code! """ if plot: # Make sure matplotlib is interactive so that test are not stuck in pytest plt.ion() if verbose: printm(">>> _test_media_line_shift") setup_test_line_databases() # add HITRAN-CO-TEST in ~/.radis if not there sf = SpectrumFactory( wavenum_min=2283.7, wavenum_max=2285.1, wstep=0.001, cutoff=1e-30, path_length=0.1, mole_fraction=400e-6, isotope=[1], medium="vacuum", broadening_max_width=10, export_populations="rovib", verbose=verbose, ) sf.warnings["MissingSelfBroadeningWarning"] = "ignore" sf.load_databank("HITEMP-CO2-HAMIL-TEST") # First run a calculation at equilibrium s = sf.eq_spectrum(300) s.name = "equilibrium" # Now generate vibrational energies for a 2-T model # ... Note that this is arbitrary. Lookup Pannier & Dubuet 2020 for more. levels = sf.parsum_calc["CO2"][1]["X"].df levels["Evib"] = levels.Evib1 + levels.Evib2 + levels.Evib3 # Calculate populations using the non-equilibrium module: # This will crash the first time (see error in docstrings of the function). with pytest.raises(AssertionError): sf.non_eq_spectrum(300, 300) sf.df0.dropna(inplace=True) # Retry: s_noneq = sf.non_eq_spectrum(300, 300) s_noneq.name = "nonequilibrium" # Tests: # s.compare_with(s_noneq, plot=plot) assert s_noneq.get_power() > 0 # TODO: implement actual Assertions (right now we're just checking that # functions are properly parsed) # TODO. Fix below (and move in dedicated test): # s.line_survey() return True
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) - RADIS 0.9.28: ParallelFactory is removed. Finished test_compare_torch_CO2 in 45s 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 = SpectrumFactory( wavenum_min=wmin, wavenum_max=wmax, mole_fraction=None, path_length=None, molecule="CO2", isotope="1,2", wstep=wstep, export_lines=False, # saves some memory export_populations=False, # saves some memory cutoff=1e-25, 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, db_use_cached=use_cache, ) # saves some memory # sf.init_databank('CDSD-4000') # CO sfco = SpectrumFactory( wavenum_min=wmin, wavenum_max=wmax, mole_fraction=None, path_length=None, molecule="CO", isotope="1,2", wstep=wstep, export_lines=False, # saves some memory export_populations=False, # saves some memory cutoff=1e-25, 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", db_use_cached=use_cache) # Calculate all slabs # .. CO2 at equilibrium slabsco2 = [] for Tgas, xCO2 in zip(conds.T_K, conds.CO2): slabsco2.append( sf.eq_spectrum(Tgas=Tgas, mole_fraction=xCO2, path_length=slab_width)) # .. CO at equilibrium slabsco = [] for Tgas, xCO in zip(conds.T_K, conds.CO): slabsco.append( sfco.eq_spectrum(Tgas=Tgas, mole_fraction=xCO, path_length=slab_width)) # Room absorption s0 = sf.eq_spectrum(Tgas=300, mole_fraction=330e-6, path_length=600) # 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 2019 paper 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 RTE along the 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", wunit="nm", Iunit=unit) stot_corr = experimental_spectrum( wtot, Itot - I0spectro, # hack to remove wunit="nm", # in air by default # emission from within # spectrometer Iunit=unit, ) # %% 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, wunit="nm", Iunit="mW/cm2/sr") 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)))
def test_all_calc_methods( verbose=True, plot=False, warnings=True, rtol=1e-3, *args, **kwargs ): """ Test same spectrum for 3 different calculation variants (equilibrium, non-equilibrium, per band and recombine """ if plot: # Make sure matplotlib is interactive so that test are not stuck in pytest import matplotlib.pyplot as plt plt.ion() try: Tgas = 1500 iso = 1 sf = SpectrumFactory( wavelength_min=4170, wavelength_max=4175, mole_fraction=1, path_length=0.025, cutoff=1e-25, molecule="CO2", isotope=iso, db_use_cached=True, lvl_use_cached=True, verbose=verbose, ) sf.warnings["MissingSelfBroadeningWarning"] = "ignore" sf.warnings["NegativeEnergiesWarning"] = "ignore" sf.warnings["HighTemperatureWarning"] = "ignore" # sf.fetch_databank() # uses HITRAN: not really valid at this temperature, but runs on all machines without install sf.load_databank("CDSD-HITEMP-PC") s_bands = sf.non_eq_bands(Tvib=Tgas, Trot=Tgas) lvl = LevelsList(sf.parsum_calc["CO2"][iso]["X"], s_bands, sf.params.levelsfmt) s_bd = lvl.non_eq_spectrum(Tvib=Tgas, Trot=Tgas) s_nq = sf.non_eq_spectrum(Tvib=Tgas, Trot=Tgas) s_eq = sf.eq_spectrum(Tgas=Tgas) # if plot: fig = plt.figure(fig_prefix + "Compare all calc methods") s_bd.plot(nfig=fig.number, color="b", lw=5, label="from bands code") s_nq.plot(nfig=fig.number, lw=3, label="non eq code") s_eq.plot(nfig=fig.number, lw=2, color="r", label="equilibrum code") plt.legend() assert np.isclose(s_bd.get_power(), s_nq.get_power(), rtol=rtol) assert np.isclose(s_bd.get_power(), s_eq.get_power(), rtol=rtol) if verbose: printm( "Eq == non-eq:\t", np.isclose(s_eq.get_power(), s_nq.get_power(), rtol=rtol), ) printm( "Bands == Non-eq:\t", np.isclose(s_bd.get_power(), s_nq.get_power(), rtol=rtol), ) if verbose: printm("Test all methods comparison: OK") return True except DatabankNotFound as err: assert IgnoreMissingDatabase(err, __file__, warnings)