lime-stable 2.0.dev7__py3-none-any.whl → 2.0.dev8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lime/archives/read_fits.py +44 -38
- lime/fitting/lines.py +2 -15
- lime/io.py +4 -1
- lime/lime.toml +1 -1
- lime/observations.py +12 -5
- lime/plotting/plots.py +4 -40
- lime/plotting/plots_interactive.py +1 -1
- lime/retrieve/line_bands.py +226 -0
- lime/transitions.py +67 -60
- lime/workflow.py +9 -300
- {lime_stable-2.0.dev7.dist-info → lime_stable-2.0.dev8.dist-info}/METADATA +1 -1
- {lime_stable-2.0.dev7.dist-info → lime_stable-2.0.dev8.dist-info}/RECORD +15 -14
- {lime_stable-2.0.dev7.dist-info → lime_stable-2.0.dev8.dist-info}/WHEEL +1 -1
- {lime_stable-2.0.dev7.dist-info → lime_stable-2.0.dev8.dist-info}/licenses/LICENSE.rst +0 -0
- {lime_stable-2.0.dev7.dist-info → lime_stable-2.0.dev8.dist-info}/top_level.txt +0 -0
lime/archives/read_fits.py
CHANGED
|
@@ -257,35 +257,44 @@ def check_fits_instructions(fits_source, online_provider=False):
|
|
|
257
257
|
else:
|
|
258
258
|
fits_reader = None
|
|
259
259
|
|
|
260
|
-
# # Check for url location for surveys function
|
|
261
|
-
# if online_provider:
|
|
262
|
-
# if hasattr(UrlFitsSurvey, fits_source):
|
|
263
|
-
# url_locator = getattr(UrlFitsSurvey, fits_source)
|
|
264
|
-
# else:
|
|
265
|
-
# raise LiMe_Error(f'Input {fits_source} does not have a url manager for LiMe could not be created.')
|
|
266
|
-
# else:
|
|
267
|
-
# url_locator = None
|
|
268
|
-
|
|
269
260
|
return fits_reader
|
|
270
261
|
|
|
271
|
-
def load_txt(text_address):
|
|
262
|
+
def load_txt(text_address, **kwargs):
|
|
272
263
|
|
|
273
264
|
# Columns
|
|
274
|
-
out_array = np.loadtxt(text_address)
|
|
265
|
+
out_array = np.loadtxt(text_address, **kwargs)
|
|
275
266
|
|
|
276
|
-
#
|
|
277
|
-
|
|
278
|
-
|
|
267
|
+
# File address
|
|
268
|
+
if not type(text_address).__name__ == "UploadedFile":
|
|
269
|
+
with open(text_address, "r") as f:
|
|
270
|
+
lines = f.readlines()
|
|
279
271
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
if not line.startswith("#") or (line.startswith("# LiMe")):
|
|
284
|
-
break
|
|
272
|
+
# Uploaded file
|
|
273
|
+
else:
|
|
274
|
+
lines = text_address.getvalue().decode("utf-8").splitlines()
|
|
285
275
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
276
|
+
# Reverse loop over the lines
|
|
277
|
+
params_dict = {}
|
|
278
|
+
for line in reversed(lines):
|
|
279
|
+
line = line.strip()
|
|
280
|
+
if not line.startswith("#") or line.startswith("# LiMe"):
|
|
281
|
+
break
|
|
282
|
+
key, value = line[1:].split(":", 1)
|
|
283
|
+
params_dict[key.strip()] = value.strip()
|
|
284
|
+
|
|
285
|
+
# # Transform foot comments as dictionary data
|
|
286
|
+
# params_dict = {}
|
|
287
|
+
# with open(text_address, "r") as f:
|
|
288
|
+
#
|
|
289
|
+
# # Reverse loop while the lines start by a "#"
|
|
290
|
+
# for line in reversed(f.readlines()):
|
|
291
|
+
# line = line.strip()
|
|
292
|
+
# if not line.startswith("#") or (line.startswith("# LiMe")):
|
|
293
|
+
# break
|
|
294
|
+
#
|
|
295
|
+
# # Extract key-value pairs
|
|
296
|
+
# key, value = line[1:].split(":", 1) # Split at the first ':'
|
|
297
|
+
# params_dict[key.strip()] = value.strip()
|
|
289
298
|
|
|
290
299
|
return out_array, params_dict
|
|
291
300
|
|
|
@@ -362,10 +371,10 @@ class OpenFits:
|
|
|
362
371
|
|
|
363
372
|
return
|
|
364
373
|
|
|
365
|
-
def parse_data_from_file(self, file_address, pixel_mask
|
|
374
|
+
def parse_data_from_file(self, file_address, pixel_mask, **kwargs):
|
|
366
375
|
|
|
367
376
|
# Read the fits data
|
|
368
|
-
wave_array, flux_array, err_array, header_list, fits_params = self.fits_reader(file_address)
|
|
377
|
+
wave_array, flux_array, err_array, header_list, fits_params = self.fits_reader(file_address, **kwargs)
|
|
369
378
|
pixel_mask = pixel_mask if pixel_mask is not None else fits_params['pixel_mask']
|
|
370
379
|
|
|
371
380
|
# Mask requested entries
|
|
@@ -441,10 +450,10 @@ class OpenFits:
|
|
|
441
450
|
return fits_args
|
|
442
451
|
|
|
443
452
|
@staticmethod
|
|
444
|
-
def text(file_address):
|
|
453
|
+
def text(file_address, **kwargs):
|
|
445
454
|
|
|
446
455
|
# Read text file dividing the columns into the spectrum axis and the comments as its parameters
|
|
447
|
-
data_arr, params_dict = load_txt(file_address)
|
|
456
|
+
data_arr, params_dict = load_txt(file_address, **kwargs)
|
|
448
457
|
|
|
449
458
|
# Unpack the columns into the spectrum axes
|
|
450
459
|
wave_array, flux_array = data_arr[:, 0], data_arr[:, 1]
|
|
@@ -456,16 +465,13 @@ class OpenFits:
|
|
|
456
465
|
# Convert strings to expected format
|
|
457
466
|
params_dict['redshift'] = float(params_dict['redshift']) if 'redshift' in params_dict else None
|
|
458
467
|
params_dict['norm_flux'] = float(params_dict['norm_flux']) if 'norm_flux' in params_dict else None
|
|
459
|
-
params_dict['id_label'] = params_dict['id_label'] if '
|
|
468
|
+
params_dict['id_label'] = params_dict['id_label'] if 'id_label' in params_dict else None
|
|
460
469
|
params_dict['pixel_mask'] = mask_array
|
|
461
470
|
|
|
462
|
-
# metadata['units_wave'] = au.Unit(metadata['units_wave']) if 'units_wave' in metadata else au.Unit('AA')
|
|
463
|
-
# metadata['units_flux'] = au.Unit(metadata['units_flux']) if 'units_flux' in metadata else au.Unit('FLAM')
|
|
464
|
-
|
|
465
471
|
return wave_array, flux_array, err_array, None, params_dict
|
|
466
472
|
|
|
467
473
|
@staticmethod
|
|
468
|
-
def nirspec(fits_address, data_ext_list=1, hdr_ext_list=(0, 1),
|
|
474
|
+
def nirspec(fits_address, data_ext_list=1, hdr_ext_list=(0, 1), **kwargs):
|
|
469
475
|
|
|
470
476
|
"""
|
|
471
477
|
|
|
@@ -503,7 +509,7 @@ class OpenFits:
|
|
|
503
509
|
return wave_array, flux_array, err_array, header_list, params_dict
|
|
504
510
|
|
|
505
511
|
@staticmethod
|
|
506
|
-
def isis(fits_address, data_ext_list=0, hdr_ext_list=0,
|
|
512
|
+
def isis(fits_address, data_ext_list=0, hdr_ext_list=0, **kwargs):
|
|
507
513
|
|
|
508
514
|
"""
|
|
509
515
|
|
|
@@ -548,7 +554,7 @@ class OpenFits:
|
|
|
548
554
|
return wave_array, flux_array, err_array, header_list, params_dict
|
|
549
555
|
|
|
550
556
|
@staticmethod
|
|
551
|
-
def osiris(fits_address, data_ext_list=0, hdr_ext_list=0,
|
|
557
|
+
def osiris(fits_address, data_ext_list=0, hdr_ext_list=0, **kwargs):
|
|
552
558
|
|
|
553
559
|
"""
|
|
554
560
|
|
|
@@ -593,7 +599,7 @@ class OpenFits:
|
|
|
593
599
|
return wave_array, flux_array, err_array, header_list, params_dict
|
|
594
600
|
|
|
595
601
|
@staticmethod
|
|
596
|
-
def sdss(fits_address, data_ext_list=(1, 2), hdr_ext_list=(0),
|
|
602
|
+
def sdss(fits_address, data_ext_list=(1, 2), hdr_ext_list=(0), **kwargs):
|
|
597
603
|
|
|
598
604
|
"""
|
|
599
605
|
|
|
@@ -645,7 +651,7 @@ class OpenFits:
|
|
|
645
651
|
return wave_array, flux_array, err_array, header_list, params_dict
|
|
646
652
|
|
|
647
653
|
@staticmethod
|
|
648
|
-
def manga(fits_address, data_ext_list=('WAVE', 'FLUX', 'IVAR'), hdr_ext_list=('FLUX'),
|
|
654
|
+
def manga(fits_address, data_ext_list=('WAVE', 'FLUX', 'IVAR'), hdr_ext_list=('FLUX'), **kwargs):
|
|
649
655
|
|
|
650
656
|
"""
|
|
651
657
|
|
|
@@ -692,7 +698,7 @@ class OpenFits:
|
|
|
692
698
|
return wave_array, flux_cube, err_cube, header_list, fits_params
|
|
693
699
|
|
|
694
700
|
@staticmethod
|
|
695
|
-
def muse(fits_address, data_ext_list=(1, 2), hdr_ext_list=1,
|
|
701
|
+
def muse(fits_address, data_ext_list=(1, 2), hdr_ext_list=1, **kwargs):
|
|
696
702
|
|
|
697
703
|
"""
|
|
698
704
|
|
|
@@ -737,7 +743,7 @@ class OpenFits:
|
|
|
737
743
|
return wave_array, flux_cube, err_cube, header_list, fits_params
|
|
738
744
|
|
|
739
745
|
@staticmethod
|
|
740
|
-
def megara(fits_address, data_ext_list=0, hdr_ext_list=(0, 1),
|
|
746
|
+
def megara(fits_address, data_ext_list=0, hdr_ext_list=(0, 1), **kwargs):
|
|
741
747
|
|
|
742
748
|
"""
|
|
743
749
|
|
|
@@ -781,7 +787,7 @@ class OpenFits:
|
|
|
781
787
|
return wave_array, flux_cube, err_cube, header_list, fits_params
|
|
782
788
|
|
|
783
789
|
@staticmethod
|
|
784
|
-
def miri(fits_address, data_ext_list=(1,2), hdr_ext_list=(1),
|
|
790
|
+
def miri(fits_address, data_ext_list=(1,2), hdr_ext_list=(1), **kwargs):
|
|
785
791
|
|
|
786
792
|
"""
|
|
787
793
|
|
lime/fitting/lines.py
CHANGED
|
@@ -608,7 +608,6 @@ class ProfileModelCompiler:
|
|
|
608
608
|
line.eqw = np.full(self.n_comps, np.nan)
|
|
609
609
|
line.eqw_err = np.full(self.n_comps, np.nan)
|
|
610
610
|
line.FWHM_p = np.full(self.n_comps, np.nan)
|
|
611
|
-
# line.sigma_thermal = np.full(self.n_comps, np.nan)
|
|
612
611
|
|
|
613
612
|
# Check for negative -0.0 # TODO this needs a better place # FIXME -0.0 error
|
|
614
613
|
if np.signbit(line.sigma_err[i]):
|
|
@@ -825,12 +824,6 @@ class LineFitting:
|
|
|
825
824
|
line.intg_flux = areasArray.mean()
|
|
826
825
|
line.intg_flux_err = areasArray.std()
|
|
827
826
|
|
|
828
|
-
# # Compute the integrated signal to noise # TODO is this an issue for absorptions
|
|
829
|
-
# amp_ref = line.peak_flux - line.cont
|
|
830
|
-
# if emission_check:
|
|
831
|
-
# if amp_ref < 0:
|
|
832
|
-
# amp_ref = line.peak_flux
|
|
833
|
-
|
|
834
827
|
# Compute SN_r
|
|
835
828
|
line.snr_line = signal_to_noise_rola(line.peak_flux - line.cont, line.cont_err, line.n_pixels)
|
|
836
829
|
line.snr_cont = line.cont/line.cont_err
|
|
@@ -842,20 +835,14 @@ class LineFitting:
|
|
|
842
835
|
else:
|
|
843
836
|
line._narrow_check = False
|
|
844
837
|
|
|
845
|
-
#
|
|
846
|
-
# idx_0 = compute_FWHM0(peakIdx, emis_flux, -1, cont_arr, emission_check)
|
|
847
|
-
# idx_f = compute_FWHM0(peakIdx, emis_flux, 1, cont_arr, emission_check)
|
|
848
|
-
#
|
|
849
|
-
# # Velocity calculations
|
|
850
|
-
# velocArray = c_KMpS * (emis_wave[idx_0:idx_f] - line.peak_wave) / line.peak_wave
|
|
851
|
-
# self.velocity_profile_calc(line, velocArray, emis_flux[idx_0:idx_f], cont_arr[idx_0:idx_f], emission_check)
|
|
838
|
+
# Velocity calculations
|
|
852
839
|
if (line.n_pixels >= min_array_dim) and (line._narrow_check is False):
|
|
853
840
|
self.velocity_profile_calc(line, peakIdx, emis_wave, emis_flux, cont_arr, emission_check, min_array_dim=min_array_dim)
|
|
854
841
|
|
|
855
842
|
# Pixel velocity # TODO we are not using this one
|
|
856
843
|
line.pixel_vel = c_KMpS * line.pixelWidth/line.peak_wave
|
|
857
844
|
|
|
858
|
-
# Equivalent width computation (it must be an 1d array to avoid conflict in blended lines)
|
|
845
|
+
# Equivalent width computation (it must be an 1d array to avoid conflict in blended lines)
|
|
859
846
|
lineContinuumMatrix = cont_arr + normalNoise
|
|
860
847
|
eqwMatrix = areasArray / lineContinuumMatrix.mean(axis=1)
|
|
861
848
|
|
lime/io.py
CHANGED
|
@@ -569,10 +569,13 @@ def results_to_log(line, log, norm_flux):
|
|
|
569
569
|
|
|
570
570
|
# Converting None entries to str (9 = group_label)
|
|
571
571
|
if j == 9:
|
|
572
|
+
|
|
572
573
|
if param_value is None:
|
|
573
574
|
param_value = 'none'
|
|
574
575
|
|
|
575
|
-
|
|
576
|
+
if line.sub_comps[i] is not None:
|
|
577
|
+
param_value = line.sub_comps[i].group_label
|
|
578
|
+
|
|
576
579
|
log.at[comp, param] = param_value
|
|
577
580
|
|
|
578
581
|
return
|
lime/lime.toml
CHANGED
lime/observations.py
CHANGED
|
@@ -411,7 +411,8 @@ class Spectrum:
|
|
|
411
411
|
return spec
|
|
412
412
|
|
|
413
413
|
@classmethod
|
|
414
|
-
def from_file(cls, file_address, instrument,
|
|
414
|
+
def from_file(cls, file_address, instrument, redshift=None, norm_flux=None, crop_waves=None, res_power=None,
|
|
415
|
+
units_wave=None, units_flux=None, pixel_mask=None, id_label=None, wcs=None, **kwargs):
|
|
415
416
|
|
|
416
417
|
"""
|
|
417
418
|
|
|
@@ -446,13 +447,19 @@ class Spectrum:
|
|
|
446
447
|
cls._fitsMgr = OpenFits(file_address, instrument, cls.__name__)
|
|
447
448
|
|
|
448
449
|
# Load the scientific data from the file
|
|
449
|
-
fits_args = cls._fitsMgr.parse_data_from_file(cls._fitsMgr.file_address,
|
|
450
|
+
fits_args = cls._fitsMgr.parse_data_from_file(cls._fitsMgr.file_address, pixel_mask, **kwargs)
|
|
450
451
|
|
|
451
|
-
# Update the
|
|
452
|
-
|
|
452
|
+
# Update the file parameters with the user parameters
|
|
453
|
+
input_args = dict(redshift=redshift, norm_flux=norm_flux, crop_waves=crop_waves, res_power=res_power,
|
|
454
|
+
units_wave=units_wave, units_flux=units_flux, id_label=id_label, wcs=wcs)
|
|
455
|
+
|
|
456
|
+
if cls._fitsMgr.spectrum_check:
|
|
457
|
+
input_args.pop('wcs')
|
|
458
|
+
|
|
459
|
+
input_args = {**fits_args, **{k: v for k, v in input_args.items() if v is not None}}
|
|
453
460
|
|
|
454
461
|
# Create the LiMe object
|
|
455
|
-
return cls(**
|
|
462
|
+
return cls(**input_args)
|
|
456
463
|
|
|
457
464
|
@classmethod
|
|
458
465
|
def from_survey(cls, target_id, survey, mask_flux_entries=None, **kwargs):
|
lime/plotting/plots.py
CHANGED
|
@@ -657,9 +657,10 @@ def redshift_permu_evaluation(spectrum, z_infered, obs_wave_arr, theo_wave_arr,
|
|
|
657
657
|
return
|
|
658
658
|
|
|
659
659
|
|
|
660
|
-
def bands_filling_plot(axis, x, y, z_corr, idcs_mask, label, exclude_continua=
|
|
660
|
+
def bands_filling_plot(axis, x, y, z_corr, idcs_mask, label, exclude_continua=True, color_dict=theme.colors, show_central=True):
|
|
661
661
|
|
|
662
662
|
# Security check for low selection
|
|
663
|
+
# TODO check this error crashing
|
|
663
664
|
if y[idcs_mask[2]:idcs_mask[3]].size > 1:
|
|
664
665
|
|
|
665
666
|
# Lower limit for the filled region
|
|
@@ -768,8 +769,8 @@ class Plotter:
|
|
|
768
769
|
def _line_matching_plot(self, axis, bands, x, y, z_corr, redshift):
|
|
769
770
|
|
|
770
771
|
# Open the bands file the bands
|
|
771
|
-
match_log =
|
|
772
|
-
|
|
772
|
+
match_log = check_file_dataframe(bands)
|
|
773
|
+
|
|
773
774
|
# Compute bands limits
|
|
774
775
|
w3 = match_log.w3.values * (1 + redshift)
|
|
775
776
|
w4 = match_log.w4.values * (1 + redshift)
|
|
@@ -1008,43 +1009,6 @@ class SpectrumFigures(Plotter):
|
|
|
1008
1009
|
in_ax.fill_between(wave_plot/z_corr, low_limit*z_corr, high_limit*z_corr, alpha=0.2,
|
|
1009
1010
|
color=theme.colors['fade_fg'])
|
|
1010
1011
|
|
|
1011
|
-
# # Include the detection bands
|
|
1012
|
-
# if detection_band is not None:
|
|
1013
|
-
#
|
|
1014
|
-
# detec_obj = getattr(self._spec.infer, detection_band)
|
|
1015
|
-
#
|
|
1016
|
-
# if detec_obj.confidence is not None:
|
|
1017
|
-
#
|
|
1018
|
-
# # Boundaries array for confidence intervals
|
|
1019
|
-
# bounds = np.array([0.0, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0])
|
|
1020
|
-
#
|
|
1021
|
-
# # Adjust color map to match lower detection limit to fg color
|
|
1022
|
-
# cmap = plt.get_cmap(theme.colors['mask_map'])
|
|
1023
|
-
# cmaplist = [cmap(i) for i in range(cmap.N)]
|
|
1024
|
-
# cmaplist[0] = theme.colors['fg']
|
|
1025
|
-
# cmap = colors.LinearSegmentedColormap.from_list('mcm', cmaplist, bounds.size-1)
|
|
1026
|
-
# norm = colors.BoundaryNorm(bounds * 100, cmap.N)
|
|
1027
|
-
#
|
|
1028
|
-
# # Iterate through the confidence intervals and plot the step spectrum
|
|
1029
|
-
# for i in range(1, len(bounds)):
|
|
1030
|
-
# if i > 1:
|
|
1031
|
-
# idcs = detec_obj(bounds[i-1]*100, confidence_max=bounds[i]*100)
|
|
1032
|
-
# wave_nan, flux_nan = np.full(wave_plot.size, np.nan), np.full(flux_plot.size, np.nan)
|
|
1033
|
-
# wave_nan[idcs], flux_nan[idcs] = wave_plot[idcs] / z_corr, flux_plot[idcs] * z_corr
|
|
1034
|
-
#
|
|
1035
|
-
# in_ax.step(wave_nan, flux_nan, label=label, where='mid', color=cmap(i-1))
|
|
1036
|
-
#
|
|
1037
|
-
# # Color bar
|
|
1038
|
-
# sm = cm.ScalarMappable(cmap=cmap, norm=norm)
|
|
1039
|
-
# sm.set_array([])
|
|
1040
|
-
# cbar = plt.colorbar(sm, ax=in_ax)
|
|
1041
|
-
# cbar.set_label('Detection confidence %', rotation=270, labelpad=35)
|
|
1042
|
-
#
|
|
1043
|
-
#
|
|
1044
|
-
# else:
|
|
1045
|
-
# _logger.warning(f'The line detection bands confidence has not been calculated. They are not included'
|
|
1046
|
-
# f' on plot.')
|
|
1047
|
-
|
|
1048
1012
|
# Show components
|
|
1049
1013
|
if show_categories and self._spec.infer.pred_arr is not None:
|
|
1050
1014
|
|
|
@@ -1536,7 +1536,7 @@ class CubeInspection:
|
|
|
1536
1536
|
self._ax0.set_ylim(self.axlim_dict['image_ylim'])
|
|
1537
1537
|
self._ax1.set_xlim(self.axlim_dict['spec_xlim'])
|
|
1538
1538
|
|
|
1539
|
-
if
|
|
1539
|
+
if self.maintain_y_zoom:
|
|
1540
1540
|
self._ax1.set_ylim(self.axlim_dict['spec_ylim'])
|
|
1541
1541
|
|
|
1542
1542
|
else:
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import numpy as np
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from lime.io import LiMe_Error
|
|
5
|
+
from lime.transitions import Line
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
_logger = logging.getLogger('LiMe')
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def pars_bands_conf(spec, bands, fit_conf, composite_lines, automatic_grouping=True):
|
|
12
|
+
|
|
13
|
+
# Use the input groups
|
|
14
|
+
if automatic_grouping is False:
|
|
15
|
+
|
|
16
|
+
# Get the the grouped lines
|
|
17
|
+
groups_dict = {} if fit_conf is False else {comp: group_label
|
|
18
|
+
for comp, group_label in fit_conf.items()
|
|
19
|
+
if comp.endswith(('_b', '_m'))}
|
|
20
|
+
|
|
21
|
+
# Limit the selection to the user lines
|
|
22
|
+
if composite_lines is not None:
|
|
23
|
+
groups_dict = {line: comps for line, comps in groups_dict.items() if line in composite_lines}
|
|
24
|
+
|
|
25
|
+
# Automatic group review
|
|
26
|
+
else:
|
|
27
|
+
|
|
28
|
+
# Check the input dataframe is sorted
|
|
29
|
+
if not np.all(np.diff(bands.wavelength) >= 0):
|
|
30
|
+
_logger.warning(f'The input bands table is not sorted. This can cause issues in the bands generation:'
|
|
31
|
+
f'\n{bands["wavelength"]}')
|
|
32
|
+
|
|
33
|
+
# Get list all the line groups and their lines
|
|
34
|
+
if fit_conf:
|
|
35
|
+
|
|
36
|
+
line_list, group_lines = [], []
|
|
37
|
+
group_names, group_blended_check = [], []
|
|
38
|
+
for comp, group_label in fit_conf.items():
|
|
39
|
+
if comp.endswith(('_b', '_m')):
|
|
40
|
+
|
|
41
|
+
# Homogeneous group
|
|
42
|
+
if '_m' not in group_label:
|
|
43
|
+
lines_i = group_label.split('+')
|
|
44
|
+
groups_i = [True] * (len(lines_i) - 1) if comp[-2:] == '_b' else [False] * (len(lines_i) - 1)
|
|
45
|
+
|
|
46
|
+
# Mixed group (merged child line in the blended parent group)
|
|
47
|
+
else:
|
|
48
|
+
lines_i, groups_i = [], []
|
|
49
|
+
for i, line in enumerate(group_label.split('+')):
|
|
50
|
+
if line[-2:] != '_m': # Single line
|
|
51
|
+
lines_i.append(line)
|
|
52
|
+
groups_i.append(True)
|
|
53
|
+
else: # Merged line
|
|
54
|
+
sub_group_label = fit_conf.get(line)
|
|
55
|
+
if sub_group_label:
|
|
56
|
+
items = sub_group_label.split('+')
|
|
57
|
+
lines_i += items
|
|
58
|
+
groups_i += [False] * len(items)
|
|
59
|
+
else:
|
|
60
|
+
raise LiMe_Error(f'The merged line: "{line}" in grouped line: "{comp}={group_label}" '
|
|
61
|
+
f'is not specified.\nPlease define a "{line}=LineA+LineB" '
|
|
62
|
+
f'in your configuration file.')
|
|
63
|
+
|
|
64
|
+
# Convert the sub_group_type to the relation
|
|
65
|
+
groups_i = np.array(groups_i)
|
|
66
|
+
groups_i = groups_i[:-1] != groups_i[1:]
|
|
67
|
+
|
|
68
|
+
# Add the group is all lines (sorted) in current wavelength range
|
|
69
|
+
idcs_i = bands.index.get_indexer(lines_i)
|
|
70
|
+
if np.all(idcs_i > -1):
|
|
71
|
+
group_names.append(comp)
|
|
72
|
+
group_lines.append(bands.loc[bands.index.isin(lines_i)].index.to_numpy())
|
|
73
|
+
group_blended_check.append(groups_i)
|
|
74
|
+
line_list += lines_i
|
|
75
|
+
|
|
76
|
+
# Sort the input lines using line banbs table
|
|
77
|
+
line_list = bands.loc[bands.index.isin(line_list)].index
|
|
78
|
+
sub_bands = bands.loc[line_list]
|
|
79
|
+
lambda_arr = sub_bands['wavelength'].to_numpy()
|
|
80
|
+
|
|
81
|
+
# Array to keep track of lines which have been assigned:
|
|
82
|
+
assigned_lines = np.zeros(line_list.size).astype(bool)
|
|
83
|
+
|
|
84
|
+
# Compare the observed line groups
|
|
85
|
+
groups_dict = {}
|
|
86
|
+
if line_list.size > 1:
|
|
87
|
+
|
|
88
|
+
# Get limits of the bands on the spectrum wavelength range
|
|
89
|
+
w3_arr = np.searchsorted(spec.wave_rest.data, bands.loc[line_list, 'w3'].to_numpy())
|
|
90
|
+
w4_arr = np.searchsorted(spec.wave_rest.data, bands.loc[line_list, 'w4'].to_numpy())
|
|
91
|
+
|
|
92
|
+
# Generate binary matrix with the line bands location
|
|
93
|
+
wave_matrix = np.zeros((lambda_arr.size, spec.wave_rest.data.size))
|
|
94
|
+
cols = np.arange(wave_matrix.shape[1])
|
|
95
|
+
wave_matrix[(cols >= w3_arr[:, None]) & (cols <= w4_arr[:, None])] = 1
|
|
96
|
+
|
|
97
|
+
# Compute the decision matrix with the common pixels
|
|
98
|
+
decision_matrix = wave_matrix @ wave_matrix.T
|
|
99
|
+
|
|
100
|
+
# pixels_width = wave_matrix.sum(axis=1)
|
|
101
|
+
# blended_matrix = decision_matrix < np.ceil(pixels_width/3)[:, None]
|
|
102
|
+
# math_dict = dict(zip(line_arr, np.arange(line_arr.size)))
|
|
103
|
+
|
|
104
|
+
# Loop through the input groups to confirm the best match
|
|
105
|
+
for i, group in enumerate(group_names):
|
|
106
|
+
|
|
107
|
+
# Diagnostic to establish the relation between the lines
|
|
108
|
+
threshold = 2
|
|
109
|
+
w3_arr = np.searchsorted(spec.wave_rest.data, bands.loc[group_lines[i], 'w3'].to_numpy())
|
|
110
|
+
w4_arr = np.searchsorted(spec.wave_rest.data, bands.loc[group_lines[i], 'w4'].to_numpy())
|
|
111
|
+
mu = (w3_arr + w4_arr) / 2
|
|
112
|
+
sigma = (w4_arr - w3_arr) / 6
|
|
113
|
+
delta_mu = np.diff(mu)
|
|
114
|
+
sigma_avg = np.sqrt((sigma[:-1] ** 2 + sigma[1:] ** 2) / 2)
|
|
115
|
+
R = delta_mu / sigma_avg
|
|
116
|
+
resolvable = R > threshold
|
|
117
|
+
|
|
118
|
+
match_group = True if np.all(resolvable == group_blended_check[i]) else False
|
|
119
|
+
|
|
120
|
+
# Before saving group check that there are no more lines grouped in the observation
|
|
121
|
+
if match_group:
|
|
122
|
+
idcs_i = sub_bands.index.get_indexer(group_lines[i])
|
|
123
|
+
if np.all(np.sum(decision_matrix[idcs_i, :] > 0, axis=1) == idcs_i.size):
|
|
124
|
+
groups_dict[group] = fit_conf[group]
|
|
125
|
+
assigned_lines[idcs_i] = True
|
|
126
|
+
|
|
127
|
+
# Invalid
|
|
128
|
+
else:
|
|
129
|
+
_logger.warning(f'The user requested automatic_grouping for the line transitions but the "fit_conf" is empty')
|
|
130
|
+
|
|
131
|
+
# Applyt the requested group changes
|
|
132
|
+
rename_dict, exclude_list= {}, []
|
|
133
|
+
group_dict, w3_dict, w4_dict = {}, {}, {}
|
|
134
|
+
for new_label, group_label in groups_dict.items():
|
|
135
|
+
|
|
136
|
+
component_list = np.unique([Line(x).core for x in group_lines[group_names.index(new_label)] if '_k-' not in x])
|
|
137
|
+
old_label = component_list[0]
|
|
138
|
+
|
|
139
|
+
# Only apply corrections if components are present
|
|
140
|
+
idcs_comps = bands.index.isin(component_list)
|
|
141
|
+
if np.sum(idcs_comps) == component_list.size:
|
|
142
|
+
|
|
143
|
+
# Save the modifications
|
|
144
|
+
rename_dict[old_label] = new_label
|
|
145
|
+
exclude_list += list(component_list)
|
|
146
|
+
w3_dict[new_label] = bands.loc[idcs_comps, 'w3'].min()
|
|
147
|
+
w4_dict[new_label] = bands.loc[idcs_comps, 'w4'].max()
|
|
148
|
+
group_dict[new_label] = group_label
|
|
149
|
+
|
|
150
|
+
# Check the line or the same group is already there
|
|
151
|
+
else:
|
|
152
|
+
low, high = spec.wave_rest.compressed()[[0, -1]]
|
|
153
|
+
check_arr = np.array([(low < Line(label).wavelength < high)[0] for label in component_list])
|
|
154
|
+
|
|
155
|
+
# Lines outside wavelength range
|
|
156
|
+
if np.all(~check_arr):
|
|
157
|
+
continue
|
|
158
|
+
|
|
159
|
+
# Check if lines outside range
|
|
160
|
+
else:
|
|
161
|
+
if 'group_label' in bands.columns:
|
|
162
|
+
if not np.any(groups_dict[new_label] == bands.group_label):
|
|
163
|
+
_logger.info(f'Line component "{old_label}" for configuration entry: '
|
|
164
|
+
f'"{new_label}={groups_dict[new_label]}" not found in lines table')
|
|
165
|
+
else:
|
|
166
|
+
_logger.info(f'Missing line(s) "{np.setxor1d(bands.loc[idcs_comps].index.to_numpy(), component_list)}" '
|
|
167
|
+
f'for configuration entry: '
|
|
168
|
+
f'"{new_label}={groups_dict[new_label]}" in reference lines table')
|
|
169
|
+
|
|
170
|
+
# Warn in case some of the bands dont match the database:
|
|
171
|
+
if not set(exclude_list).issubset(bands.index):
|
|
172
|
+
_logger.info(f' The following blended or merged lines were not found on the input lines database:\n'
|
|
173
|
+
f' - {list(set(exclude_list) - set(bands.index))}\n'
|
|
174
|
+
f' - It is recommended that the merged/blended components follow the reference transitions labels.\n')
|
|
175
|
+
|
|
176
|
+
# Change the latex labels
|
|
177
|
+
for old_label, new_label in rename_dict.items():
|
|
178
|
+
line = Line(new_label, band=bands, fit_conf=groups_dict, update_latex=True)
|
|
179
|
+
bands.loc[old_label, 'latex_label'] = line.latex_label[0] if line.merged_check else '+'.join(line.latex_label)
|
|
180
|
+
|
|
181
|
+
# Change the indexes
|
|
182
|
+
bands.rename(index=dict(rename_dict), inplace=True)
|
|
183
|
+
|
|
184
|
+
# Remove components columns
|
|
185
|
+
bands.drop(exclude_list, errors='ignore', inplace=True)
|
|
186
|
+
|
|
187
|
+
# Add the group_label values
|
|
188
|
+
if 'group_label' not in bands.columns:
|
|
189
|
+
bands['group_label'] = 'none'
|
|
190
|
+
bands['group_label'] = pd.Series(bands.index.map(group_dict), index=bands.index).fillna(bands['group_label'])
|
|
191
|
+
|
|
192
|
+
# Change velocity limits
|
|
193
|
+
bands['w3'] = pd.Series(bands.index.map(w3_dict), index=bands.index).fillna(bands['w3'])
|
|
194
|
+
bands['w4'] = pd.Series(bands.index.map(w4_dict), index=bands.index).fillna(bands['w4'])
|
|
195
|
+
|
|
196
|
+
return
|
|
197
|
+
|
|
198
|
+
# if np.all(idcs_i > -1):
|
|
199
|
+
|
|
200
|
+
# # Logic for single, merged and blended lines
|
|
201
|
+
# shared_pixels = decision_matrix[idcs_i[:-1], idcs_i[1:]]
|
|
202
|
+
# if np.any(shared_pixels > 0):
|
|
203
|
+
# match_group =False
|
|
204
|
+
# # line_pixels = np.max(pixels_width[idcs_i])
|
|
205
|
+
# # diag_arr = resolvable
|
|
206
|
+
# #
|
|
207
|
+
# # obs_type = ['_b'] if np.all(diag_arr) else ['_m'] if np.all(~diag_arr) else None
|
|
208
|
+
# else:
|
|
209
|
+
# match_group = False
|
|
210
|
+
|
|
211
|
+
# Compare observed group versus user group
|
|
212
|
+
|
|
213
|
+
# else:
|
|
214
|
+
#
|
|
215
|
+
# # Lines not assigned before:
|
|
216
|
+
# if np.all(assigned_lines[idcs_i] == False):
|
|
217
|
+
#
|
|
218
|
+
# # Group consists in blended merged lines: Assigned single merged
|
|
219
|
+
# if (group_name[-2:] == '_m') and np.any(diag_arr[:-1] & diag_arr[1:]):
|
|
220
|
+
# output_groups[group_name] = group_label
|
|
221
|
+
# assigned_lines[idcs_i] = True
|
|
222
|
+
# # Get groups of common entries
|
|
223
|
+
# from scipy.sparse import csr_matrix, csgraph
|
|
224
|
+
# _, auto_labels = csgraph.connected_components(csgraph=csr_matrix(decision_matrix > 1), directed=False)
|
|
225
|
+
# for labels, group in zip(line_arr, auto_labels):
|
|
226
|
+
# print(f"{labels} {group}")
|
lime/transitions.py
CHANGED
|
@@ -185,7 +185,7 @@ def air_to_vacuum_function(wave_array, units_wave='AA'):
|
|
|
185
185
|
return wave_array / (1 + 1e-6 * (287.6155 + 1.62887 * sigma2 + 0.01360 * np.square(sigma2)))
|
|
186
186
|
|
|
187
187
|
|
|
188
|
-
def check_units_from_wave(line, str_ion, str_wave, bands
|
|
188
|
+
def check_units_from_wave(line, str_ion, str_wave, bands):
|
|
189
189
|
|
|
190
190
|
# First the input database
|
|
191
191
|
if bands is not None:
|
|
@@ -202,16 +202,14 @@ def check_units_from_wave(line, str_ion, str_wave, bands, ref_bands=None):
|
|
|
202
202
|
|
|
203
203
|
# Convert to units
|
|
204
204
|
units = au.Unit(units) if units is not None else units
|
|
205
|
-
# units = None if (units is None or np.isnan(units)) else au.Unit(units)
|
|
206
205
|
|
|
207
206
|
else:
|
|
208
207
|
wave, units = None, None
|
|
209
208
|
|
|
210
209
|
# Second the reference database
|
|
211
210
|
if (units is None) or (wave is None):
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
units = pd_get(ref_bands, line, 'units_wave', nan_to_none=True)
|
|
211
|
+
wave = pd_get(_PARENT_BANDS, line, 'wavelength', nan_to_none=True)
|
|
212
|
+
units = pd_get(_PARENT_BANDS, line, 'units_wave', nan_to_none=True)
|
|
215
213
|
|
|
216
214
|
# Convert to units
|
|
217
215
|
units = au.Unit(units) if units is not None else units
|
|
@@ -229,10 +227,6 @@ def check_units_from_wave(line, str_ion, str_wave, bands, ref_bands=None):
|
|
|
229
227
|
units = au_unit.bases[0]
|
|
230
228
|
wave = au_unit.scale
|
|
231
229
|
|
|
232
|
-
# # Give preferences to the tabel values
|
|
233
|
-
# wave = wave_label if wave is None else wave
|
|
234
|
-
# units = units_label if units is None else units
|
|
235
|
-
|
|
236
230
|
return wave, units
|
|
237
231
|
|
|
238
232
|
|
|
@@ -407,7 +401,7 @@ def latex_from_label(label, particle=None, wave=None, units_wave=None, kinem=Non
|
|
|
407
401
|
#
|
|
408
402
|
|
|
409
403
|
|
|
410
|
-
def label_composition(line_list, bands=None, default_profile=None
|
|
404
|
+
def label_composition(line_list, bands=None, default_profile=None):
|
|
411
405
|
|
|
412
406
|
# Empty containers for the label componentes
|
|
413
407
|
n_comps = len(line_list)
|
|
@@ -436,7 +430,7 @@ def label_composition(line_list, bands=None, default_profile=None, ref_bands=Non
|
|
|
436
430
|
particle[i] = Particle.from_label(line_items[0])
|
|
437
431
|
|
|
438
432
|
# Wavelength properties
|
|
439
|
-
wavelength[i], units_wave[i] = check_units_from_wave(line, line_items[0], line_items[1], bands
|
|
433
|
+
wavelength[i], units_wave[i] = check_units_from_wave(line, line_items[0], line_items[1], bands)
|
|
440
434
|
|
|
441
435
|
# Split the optional components: "H1_1216A_t-rec_k-0_p-g" -> {'t': 'rec', 'k': '0', 'p': 'g'} # TODO better do that with optional_comps
|
|
442
436
|
comp_conf = {optC[0]: optC[2:] for optC in line_items[2:]}
|
|
@@ -765,25 +759,26 @@ class Particle:
|
|
|
765
759
|
|
|
766
760
|
class Line:
|
|
767
761
|
|
|
768
|
-
def __init__(self, label, band=None, fit_conf=None, profile=None,
|
|
769
|
-
update_latex=False, ref_bands=None, interpret=True):
|
|
762
|
+
def __init__(self, label, band=None, fit_conf=None, profile=None, update_latex=False):
|
|
770
763
|
|
|
771
|
-
#
|
|
764
|
+
# Core attributes
|
|
772
765
|
self.label = label
|
|
773
766
|
self.mask = None
|
|
774
767
|
self.latex_label = None,
|
|
775
768
|
self.group_label, self.list_comps = None, None
|
|
769
|
+
self.sub_comps = None
|
|
776
770
|
|
|
777
771
|
self.particle = None
|
|
778
772
|
self.wavelength, self.units_wave = None, None
|
|
779
773
|
self.blended_check, self.merged_check = False, False
|
|
780
774
|
|
|
775
|
+
# Transition components
|
|
781
776
|
self.kinem = None
|
|
782
|
-
self.profile_comp = profile
|
|
783
|
-
self.transition_comp = None
|
|
784
777
|
self.core = None
|
|
785
|
-
|
|
786
778
|
self._ref_idx = None
|
|
779
|
+
|
|
780
|
+
self.transition_comp = None
|
|
781
|
+
self.profile_comp = profile
|
|
787
782
|
self._p_type = None
|
|
788
783
|
self._p_shape = None
|
|
789
784
|
|
|
@@ -802,7 +797,7 @@ class Line:
|
|
|
802
797
|
self.alpha, self.beta = None, None
|
|
803
798
|
self.alpha_err, self.beta_err = None, None
|
|
804
799
|
self.frac, self.frac_err = None, None
|
|
805
|
-
self.z_line =
|
|
800
|
+
self.z_line = None
|
|
806
801
|
self.v_r, self.v_r_err = None, None
|
|
807
802
|
self.pixel_vel = None
|
|
808
803
|
self.sigma_vel, self.sigma_vel_err = None, None
|
|
@@ -822,71 +817,55 @@ class Line:
|
|
|
822
817
|
self.pixelWidth = None
|
|
823
818
|
|
|
824
819
|
# Extra checks
|
|
825
|
-
self._cont_from_adjacent = cont_from_bands
|
|
826
|
-
self._decimal_wave = False
|
|
820
|
+
# self._cont_from_adjacent = cont_from_bands
|
|
821
|
+
# self._decimal_wave = False
|
|
827
822
|
self._narrow_check = False
|
|
828
823
|
|
|
829
|
-
#
|
|
830
|
-
|
|
831
|
-
|
|
824
|
+
# Recover the line data from the input databases
|
|
825
|
+
self._get_containers_data(label,
|
|
826
|
+
_PARENT_BANDS if band is None else check_file_dataframe(band, copy_input=False),
|
|
827
|
+
fit_conf,
|
|
828
|
+
update_latex)
|
|
832
829
|
|
|
833
830
|
return
|
|
834
831
|
|
|
835
832
|
def __str__(self):
|
|
836
|
-
|
|
837
833
|
return self.label
|
|
838
834
|
|
|
839
835
|
def __repr__(self):
|
|
840
|
-
|
|
841
836
|
return self.label
|
|
842
837
|
|
|
843
|
-
def
|
|
838
|
+
def __eq__(self, var):
|
|
839
|
+
return self.label == var if isinstance(var, str) else False
|
|
844
840
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
841
|
+
def __hash__(self):
|
|
842
|
+
return hash(self.label)
|
|
843
|
+
|
|
844
|
+
def _get_containers_data(self, label, band=None, fit_conf=None, update_latex=False):
|
|
849
845
|
|
|
850
846
|
# Infer label from log if input line is a wavelength
|
|
851
847
|
self.label = check_line_in_log(label, band)
|
|
852
848
|
|
|
853
|
-
# Get
|
|
854
|
-
|
|
855
|
-
n_comps = len(comps_list)
|
|
856
|
-
if n_comps < 2:
|
|
857
|
-
raise LiMe_Error(f'The {self.label} the line label format is not recognized. '
|
|
858
|
-
f'Please use a "Particle_WavelengthUnits" format.')
|
|
859
|
-
|
|
860
|
-
# Check the modularity (only 2 comps) (case b-6)
|
|
861
|
-
modularity_comp = comps_list[-1] if (comps_list[-1] == 'b') or (comps_list[-1] == 'm') else None
|
|
862
|
-
self._modularity_component(modularity_comp, fit_conf, band)
|
|
849
|
+
# Get the transitions involved on the line
|
|
850
|
+
self.line_group_review(fit_conf, band)
|
|
863
851
|
|
|
864
852
|
# Review the components of the line
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
853
|
+
components = label_composition(self.list_comps,
|
|
854
|
+
band if isinstance(band, DataFrame) else None,
|
|
855
|
+
self.profile_comp)
|
|
856
|
+
self.particle, self.wavelength, self.units_wave, self.kinem, self.profile_comp, self.transition_comp = components
|
|
868
857
|
|
|
869
858
|
# Quick elements for the line profile
|
|
870
859
|
self._p_shape, self._p_type = label_profiling(self.profile_comp)
|
|
871
860
|
|
|
872
|
-
# Index of the line closest to the one in label
|
|
873
|
-
if self.blended_check or self.merged_check:
|
|
874
|
-
wave_label, _label_units = check_units_from_wave(None, None, comps_list[1], None)
|
|
875
|
-
self._ref_idx = argmin(self.wavelength - wave_label)
|
|
876
|
-
else:
|
|
877
|
-
self._ref_idx = 0
|
|
878
|
-
|
|
879
|
-
# Core component definition
|
|
880
|
-
self.core = f'{comps_list[0]}_{comps_list[1]}'
|
|
881
|
-
|
|
882
861
|
# Provide a bands from the log if possible
|
|
883
862
|
self.mask = label_mask_assigning(self.label, band, self.blended_check, self.merged_check, self.core)
|
|
884
863
|
|
|
885
864
|
# Check if there are masked pixels in the line
|
|
886
865
|
self.pixel_mask = 'no' if fit_conf is None else fit_conf.get(f'{self.label}_mask', 'no')
|
|
887
866
|
|
|
888
|
-
# Check
|
|
889
|
-
self.
|
|
867
|
+
# Check sub-line components
|
|
868
|
+
self.sub_transitions(fit_conf, band)
|
|
890
869
|
|
|
891
870
|
# Compute latex entry if necessary
|
|
892
871
|
self.latex_label = np.atleast_1d(self._review_science_notation(band if isinstance(band, DataFrame) else None,
|
|
@@ -898,13 +877,14 @@ class Line:
|
|
|
898
877
|
def from_log(cls, label, log=None, norm_flux=1):
|
|
899
878
|
|
|
900
879
|
# Confirm we are not introducing a blended line which has been blended
|
|
901
|
-
|
|
902
880
|
if label in log.index:
|
|
903
881
|
measured_check = True
|
|
882
|
+
|
|
904
883
|
elif (label[-2:] == '_b') and (label[:-2] in log.index):
|
|
905
884
|
_logger.warning(f'Blended line {label} not found in log, reading {label[:-2]}')
|
|
906
885
|
label = label[:-2]
|
|
907
886
|
measured_check = True
|
|
887
|
+
|
|
908
888
|
else:
|
|
909
889
|
_logger.warning(f'Input line {label} not found in log')
|
|
910
890
|
measured_check = False
|
|
@@ -932,7 +912,17 @@ class Line:
|
|
|
932
912
|
|
|
933
913
|
return inline
|
|
934
914
|
|
|
935
|
-
def
|
|
915
|
+
def line_group_review(self, fit_conf=None, bands_log=None):
|
|
916
|
+
|
|
917
|
+
# Establish the components
|
|
918
|
+
comps_list = self.label.split('_')
|
|
919
|
+
n_comps = len(comps_list)
|
|
920
|
+
if n_comps < 2:
|
|
921
|
+
raise LiMe_Error(f'The {self.label} the line label format is not recognized. '
|
|
922
|
+
f'Please use a "Particle_WavelengthUnits" format.')
|
|
923
|
+
|
|
924
|
+
# Check the line type
|
|
925
|
+
modularity_label = comps_list[-1] if (comps_list[-1] == 'b') or (comps_list[-1] == 'm') else None
|
|
936
926
|
|
|
937
927
|
# Not a single line
|
|
938
928
|
if modularity_label is not None:
|
|
@@ -951,10 +941,8 @@ class Line:
|
|
|
951
941
|
group_label_cfg = None if fit_conf is None else fit_conf.get(self.label, None)
|
|
952
942
|
group_label_frame = None if not isinstance(bands_log, pd.DataFrame) else pd_get(bands_log, self.label,
|
|
953
943
|
column='group_label', transform='none')
|
|
954
|
-
|
|
955
|
-
self.group_label = group_label_cfg if group_label_cfg is not None else group_label_frame
|
|
956
|
-
|
|
957
944
|
# Confirm blended or merged
|
|
945
|
+
self.group_label = group_label_cfg if group_label_cfg is not None else group_label_frame
|
|
958
946
|
self.blended_check = True if (self.group_label is not None) and (self.merged_check is False) else False
|
|
959
947
|
|
|
960
948
|
# Recover the profile components
|
|
@@ -982,6 +970,15 @@ class Line:
|
|
|
982
970
|
else:
|
|
983
971
|
self.list_comps = [self.label]
|
|
984
972
|
|
|
973
|
+
# Core component definition
|
|
974
|
+
self.core = f'{comps_list[0]}_{comps_list[1]}'
|
|
975
|
+
|
|
976
|
+
# Index of core component
|
|
977
|
+
if self.blended_check or self.merged_check:
|
|
978
|
+
self._ref_idx = self.list_comps.index(self.core) if self.core in self.list_comps else 0
|
|
979
|
+
else:
|
|
980
|
+
self._ref_idx = 0
|
|
981
|
+
|
|
985
982
|
return
|
|
986
983
|
|
|
987
984
|
def _review_science_notation(self, bands, update_latex=False, decimals=None):
|
|
@@ -1074,6 +1071,16 @@ class Line:
|
|
|
1074
1071
|
else:
|
|
1075
1072
|
return idcs_bands
|
|
1076
1073
|
|
|
1074
|
+
def sub_transitions(self, fit_cfg, bands):
|
|
1075
|
+
|
|
1076
|
+
self.sub_comps = [None] * len(self.list_comps)
|
|
1077
|
+
if self.blended_check and fit_cfg:
|
|
1078
|
+
for i, sub_stransition in enumerate(self.list_comps):
|
|
1079
|
+
if sub_stransition[-2:] == '_m':
|
|
1080
|
+
self.sub_comps[i] = Line(sub_stransition, bands, fit_cfg)
|
|
1081
|
+
|
|
1082
|
+
return
|
|
1083
|
+
|
|
1077
1084
|
# def index_bands_orig(self, wavelength_array, redshift, merge_continua=True, just_band_edges=False):
|
|
1078
1085
|
#
|
|
1079
1086
|
# if self.mask is None:
|
lime/workflow.py
CHANGED
|
@@ -10,10 +10,10 @@ from lmfit.models import PolynomialModel
|
|
|
10
10
|
from lime.fitting.lines import LineFitting, signal_to_noise_rola, sigma_corrections, k_gFWHM, velocity_to_wavelength_band, profiles_computation, linear_continuum_computation
|
|
11
11
|
from lime.tools import ProgressBar, join_fits_files, extract_wcs_header, pd_get, unit_conversion
|
|
12
12
|
from lime.transitions import Line, air_to_vacuum_function, label_decomposition
|
|
13
|
+
from lime.retrieve.line_bands import pars_bands_conf
|
|
13
14
|
from lime.io import check_file_dataframe, check_file_array_mask, log_to_HDU, results_to_log, load_frame, LiMe_Error, check_fit_conf, _PARENT_BANDS
|
|
14
15
|
from lime.fitting.redshift import RedshiftFitting
|
|
15
16
|
from lime import __version__
|
|
16
|
-
from scipy.sparse import csr_matrix, csgraph
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
|
|
@@ -341,296 +341,6 @@ def res_power_approx(wavelength_arr):
|
|
|
341
341
|
return wavelength_arr/delta_lambda
|
|
342
342
|
|
|
343
343
|
|
|
344
|
-
def get_merged_blended_lines(spec, bands, in_cfg, composite_lines):
|
|
345
|
-
|
|
346
|
-
# Get lines on the list
|
|
347
|
-
comps_dict = {} if in_cfg is False else {comp: group_label
|
|
348
|
-
for comp, group_label in in_cfg.items()
|
|
349
|
-
if comp.endswith(('_b', '_m'))}
|
|
350
|
-
|
|
351
|
-
# Limit the selection to the user lines
|
|
352
|
-
if composite_lines is not None:
|
|
353
|
-
comps_dict = {line: comps for line, comps in comps_dict.items() if line in composite_lines}
|
|
354
|
-
|
|
355
|
-
# # Determine the grouped lines
|
|
356
|
-
# key_cfg = f'{default_cfg_prefix}_line_fitting'
|
|
357
|
-
# default_dict = {} if key_cfg not in in_cfg else {comp: group_label
|
|
358
|
-
# for comp, group_label in in_cfg[key_cfg].items()
|
|
359
|
-
# if comp.endswith(('_b', '_m'))}
|
|
360
|
-
#
|
|
361
|
-
# key_cfg = f'{obj_cfg_prefix}_line_fitting'
|
|
362
|
-
# obj_dict = {} if key_cfg not in in_cfg else{comp: group_label
|
|
363
|
-
# for comp, group_label in in_cfg[key_cfg].items()
|
|
364
|
-
# if comp.endswith(('_b', '_m'))}
|
|
365
|
-
#
|
|
366
|
-
# if len(default_dict) == 0 and len(obj_dict) == 0:
|
|
367
|
-
# output_dict = fit_conf.copy()
|
|
368
|
-
# else:
|
|
369
|
-
# output_dict = {**default_dict, **obj_dict}
|
|
370
|
-
|
|
371
|
-
# b_m_arr = np.array(list(output_dict.keys()))
|
|
372
|
-
# core_arr = np.array([s[:-2] for s in b_m_arr])
|
|
373
|
-
# unique_elements, counts = np.unique(core_arr, return_counts=True)
|
|
374
|
-
# repeated_lines = unique_elements[counts > 1]
|
|
375
|
-
#
|
|
376
|
-
# # Check each case individually
|
|
377
|
-
# for line in repeated_lines:
|
|
378
|
-
# line_blended, line_merged = line + '_b', line + '_m'
|
|
379
|
-
# default_b, default_m = line_blended in default_dict, line_merged in default_dict
|
|
380
|
-
# obj_b, obj_m = line_blended in obj_dict, line_merged in obj_dict
|
|
381
|
-
#
|
|
382
|
-
# # Object configuration has priority
|
|
383
|
-
# if not (obj_b == obj_m):
|
|
384
|
-
# output_dict.pop(line_blended if obj_b else line_merged)
|
|
385
|
-
#
|
|
386
|
-
# # Try default configuration
|
|
387
|
-
# elif not (default_b == default_m):
|
|
388
|
-
# output_dict.pop(line_blended if default_b else line_merged)
|
|
389
|
-
#
|
|
390
|
-
# # Solve the kinematics
|
|
391
|
-
# else:
|
|
392
|
-
#
|
|
393
|
-
# # Get components
|
|
394
|
-
# comps = output_dict[line_blended].split('+')
|
|
395
|
-
#
|
|
396
|
-
# # Check if more than one component is on the bands
|
|
397
|
-
# df_comps = bands.loc[bands.index.isin(comps)]
|
|
398
|
-
# if df_comps.index.size > 1:
|
|
399
|
-
#
|
|
400
|
-
# # Set minimum number of pixels for the model solution in the bands
|
|
401
|
-
# central_band = bands.loc[bands.index.isin(comps), 'w3':'w4'].to_numpy() * (1 + spec.redshift)
|
|
402
|
-
# idcs_central = np.searchsorted(spec.wave, (central_band[:, 0].min(), central_band[:, 1].max()))
|
|
403
|
-
# blended_check = idcs_central[1] - idcs_central[0] > (3 * len(comps))
|
|
404
|
-
#
|
|
405
|
-
# # Print warning
|
|
406
|
-
# _logger.info(f'The input configuration has merged and blended entries for {line}. '
|
|
407
|
-
# f'Automatic assignment as {"blended" if blended_check else "Merged"} ({line_blended if blended_check else line_blended}'
|
|
408
|
-
# f'={output_dict[line_blended if blended_check else line_blended]})')
|
|
409
|
-
# output_dict.pop(line_blended if blended_check else line_blended)
|
|
410
|
-
|
|
411
|
-
# # Get candidate lines for grouping
|
|
412
|
-
# line_arr = [item for v in output_dict.values() for item in v.split('+')]
|
|
413
|
-
# line_arr = bands.loc[bands.index.isin(line_arr)].index
|
|
414
|
-
# lambda_arr = bands.loc[line_arr, 'wavelength'].to_numpy()
|
|
415
|
-
#
|
|
416
|
-
# # Generate the line - wavelength matrix with the line pixels width
|
|
417
|
-
# wave_matrix = np.zeros((lambda_arr.size, spec.wave_rest.data.size))
|
|
418
|
-
# w3_arr = np.searchsorted(spec.wave_rest.data, bands.loc[line_arr, 'w3'].to_numpy())
|
|
419
|
-
# w4_arr = np.searchsorted(spec.wave_rest.data, bands.loc[line_arr, 'w4'].to_numpy())
|
|
420
|
-
# cols = np.arange(wave_matrix.shape[1])
|
|
421
|
-
# wave_matrix[(cols >= w3_arr[:, None]) & (cols <= w4_arr[:, None])] = 1
|
|
422
|
-
# pixels_width = wave_matrix.sum(axis=1)
|
|
423
|
-
#
|
|
424
|
-
# # Get the decision matrix with the matching intervals
|
|
425
|
-
# decision_matrix = wave_matrix @ wave_matrix.T
|
|
426
|
-
# blended_matrix = decision_matrix < np.ceil(pixels_width/3)[:, None]
|
|
427
|
-
# math_dict = dict(zip(line_arr, np.arange(line_arr.size)))
|
|
428
|
-
#
|
|
429
|
-
# results_dict = {}
|
|
430
|
-
# for label, group_label in output_dict.items():
|
|
431
|
-
# list_group = group_label.split('+')
|
|
432
|
-
# if all(key in math_dict for key in list_group):
|
|
433
|
-
# blended_group = True if label[-1] == 'b' else False
|
|
434
|
-
# relations = np.array([blended_matrix[math_dict[i], math_dict[j]] for i, j in list(combinations(list_group, 2))])
|
|
435
|
-
# if np.all(relations == blended_group):
|
|
436
|
-
# print(f'Passess: {label}={group_label}')
|
|
437
|
-
# results_dict[label] = group_label
|
|
438
|
-
|
|
439
|
-
return comps_dict
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
# upper_triangle < (np.ceil(pixels_width/3)[:, None]=
|
|
446
|
-
#
|
|
447
|
-
#
|
|
448
|
-
# np.fill_diagonal(decision_matrix, 0) # optional
|
|
449
|
-
#
|
|
450
|
-
# # Step 2: Extract the upper triangle (excluding diagonal)
|
|
451
|
-
# upper_triangle = np.ma.masked_array(np.triu(decision_matrix, k=1), mask=np.tril(np.ones_like(decision_matrix), k=0).astype(bool)).astype(int)
|
|
452
|
-
#
|
|
453
|
-
# # Step 3: Find (i, j) pairs with >1 shared steps
|
|
454
|
-
# rows_i, rows_j = np.where(upper_triangle > 1)
|
|
455
|
-
# edges = list(zip(line_arr[rows_i], line_arr[rows_j]))
|
|
456
|
-
#
|
|
457
|
-
# matrix < thresholds[:, None]
|
|
458
|
-
#
|
|
459
|
-
# # Step 3: Check if all values in each column satisfy the condition
|
|
460
|
-
# idcs_type = upper_triangle < np.ceil(pixels_width/3)[:, None]
|
|
461
|
-
# merged_idcs = np.all(idcs_type, axis=0)
|
|
462
|
-
# blended_idcs = np.all(~idcs_type, axis=0)
|
|
463
|
-
# #
|
|
464
|
-
# math_dict = dict(zip(line_arr, np.arange(line_arr.size)))
|
|
465
|
-
# for row in rows_j:
|
|
466
|
-
# print(line_arr[row])
|
|
467
|
-
#
|
|
468
|
-
# for label, group_label in output_dict.keys():
|
|
469
|
-
# list_group = group_label.split('+')
|
|
470
|
-
# if len(list_group) == 2:
|
|
471
|
-
# x_label, y_label = math_dict.get(list_group[0]), math_dict.get(list_group[1])
|
|
472
|
-
# if (x_label is not None) and (y_label is not None):
|
|
473
|
-
#
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
# print(w3_arr)
|
|
477
|
-
# print(w4_arr)
|
|
478
|
-
#
|
|
479
|
-
# wave_matrix[w3_arr:w4_arr, :]
|
|
480
|
-
# # box_pixels =
|
|
481
|
-
# #
|
|
482
|
-
# # print(idcs_lines)
|
|
483
|
-
# lambda_arr = bands.index.isin(line_arr)
|
|
484
|
-
# wave_arr = spec.wave.data
|
|
485
|
-
|
|
486
|
-
# Generate matrices array
|
|
487
|
-
|
|
488
|
-
# b_m_arr = np.array(list(output_dict.keys()))
|
|
489
|
-
# core_arr = np.array([s[:-2] for s in b_m_arr])
|
|
490
|
-
# unique_elements, counts = np.unique(core_arr, return_counts=True)
|
|
491
|
-
# repeated_lines = unique_elements[counts > 1]
|
|
492
|
-
#
|
|
493
|
-
# # Check each case individually
|
|
494
|
-
# for line in repeated_lines:
|
|
495
|
-
# line_blended, line_merged = line + '_b', line + '_m'
|
|
496
|
-
# default_b, default_m = line_blended in default_dict, line_merged in default_dict
|
|
497
|
-
# obj_b, obj_m = line_blended in obj_dict, line_merged in obj_dict
|
|
498
|
-
#
|
|
499
|
-
# # Object configuration has priority
|
|
500
|
-
# if not (obj_b == obj_m):
|
|
501
|
-
# output_dict.pop(line_blended if obj_b else line_merged)
|
|
502
|
-
#
|
|
503
|
-
# # Try default configuration
|
|
504
|
-
# elif not (default_b == default_m):
|
|
505
|
-
# output_dict.pop(line_blended if default_b else line_merged)
|
|
506
|
-
#
|
|
507
|
-
# # Solve the kinematics
|
|
508
|
-
# else:
|
|
509
|
-
#
|
|
510
|
-
# # Get components
|
|
511
|
-
# comps = output_dict[line_blended].split('+')
|
|
512
|
-
#
|
|
513
|
-
# # Check if more than one component is on the bands
|
|
514
|
-
# df_comps = bands.loc[bands.index.isin(comps)]
|
|
515
|
-
# if df_comps.index.size > 1:
|
|
516
|
-
#
|
|
517
|
-
# # Set minimum number of pixels for the model solution in the bands
|
|
518
|
-
# central_band = bands.loc[bands.index.isin(comps), 'w3':'w4'].to_numpy() * (1 + spec.redshift)
|
|
519
|
-
# idcs_central = np.searchsorted(spec.wave, (central_band[:, 0].min(), central_band[:, 1].max()))
|
|
520
|
-
# blended_check = idcs_central[1] - idcs_central[0] > (3 * len(comps))
|
|
521
|
-
#
|
|
522
|
-
# # Print warning
|
|
523
|
-
# _logger.info(f'The input configuration has merged and blended entries for {line}. '
|
|
524
|
-
# f'Automatic assignment as {"blended" if blended_check else "Merged"} ({line_blended if blended_check else line_blended}'
|
|
525
|
-
# f'={output_dict[line_blended if blended_check else line_blended]})')
|
|
526
|
-
# output_dict.pop(line_blended if blended_check else line_blended)
|
|
527
|
-
#
|
|
528
|
-
#
|
|
529
|
-
# return output_dict
|
|
530
|
-
|
|
531
|
-
def pars_bands_conf(spec, bands, ref_bands, fit_conf, composite_lines, automatic_grouping=False):
|
|
532
|
-
|
|
533
|
-
# Get the the grouped lines
|
|
534
|
-
comps_dict = {} if fit_conf is False else {comp: group_label
|
|
535
|
-
for comp, group_label in fit_conf.items()
|
|
536
|
-
if comp.endswith(('_b', '_m'))}
|
|
537
|
-
|
|
538
|
-
# Limit the selection to the user lines
|
|
539
|
-
if composite_lines is not None:
|
|
540
|
-
comps_dict = {line: comps for line, comps in comps_dict.items() if line in composite_lines}
|
|
541
|
-
|
|
542
|
-
if automatic_grouping:
|
|
543
|
-
|
|
544
|
-
# Get candidate lines for grouping
|
|
545
|
-
line_arr = [item for v in comps_dict.values() for item in v.split('+')]
|
|
546
|
-
line_arr = bands.loc[bands.index.isin(line_arr)].index
|
|
547
|
-
lambda_arr = bands.loc[line_arr, 'wavelength'].to_numpy()
|
|
548
|
-
|
|
549
|
-
# Generate the line - wavelength matrix with the line pixels width
|
|
550
|
-
wave_matrix = np.zeros((lambda_arr.size, spec.wave_rest.data.size))
|
|
551
|
-
w3_arr = np.searchsorted(spec.wave_rest.data, bands.loc[line_arr, 'w3'].to_numpy())
|
|
552
|
-
w4_arr = np.searchsorted(spec.wave_rest.data, bands.loc[line_arr, 'w4'].to_numpy())
|
|
553
|
-
cols = np.arange(wave_matrix.shape[1])
|
|
554
|
-
wave_matrix[(cols >= w3_arr[:, None]) & (cols <= w4_arr[:, None])] = 1
|
|
555
|
-
pixels_width = wave_matrix.sum(axis=1)
|
|
556
|
-
|
|
557
|
-
# Get the decision matrix with the matching intervals
|
|
558
|
-
decision_matrix = wave_matrix @ wave_matrix.T
|
|
559
|
-
blended_matrix = decision_matrix < np.ceil(pixels_width/3)[:, None]
|
|
560
|
-
math_dict = dict(zip(line_arr, np.arange(line_arr.size)))
|
|
561
|
-
|
|
562
|
-
# Get groups of common entries
|
|
563
|
-
_, auto_labels = csgraph.connected_components(csgraph=csr_matrix(decision_matrix > 1), directed=False)
|
|
564
|
-
for labels, group in zip(line_arr, auto_labels):
|
|
565
|
-
print(f"{labels} {group}")
|
|
566
|
-
|
|
567
|
-
# Loop through the lines on the list and review which changes are necessary
|
|
568
|
-
rename_dict, exclude_list= {}, []
|
|
569
|
-
group_dict, w3_dict, w4_dict = {}, {}, {}
|
|
570
|
-
for new_label, group_label in comps_dict.items():
|
|
571
|
-
|
|
572
|
-
component_list = np.unique([Line(x).core for x in group_label.split('+') if '_k-' not in x])
|
|
573
|
-
old_label = component_list[0]
|
|
574
|
-
|
|
575
|
-
# Only apply corrections if components are present
|
|
576
|
-
idcs_comps = bands.index.isin(component_list)
|
|
577
|
-
if np.sum(idcs_comps) == component_list.size:
|
|
578
|
-
|
|
579
|
-
# Save the modifications
|
|
580
|
-
rename_dict[old_label] = new_label
|
|
581
|
-
exclude_list += list(component_list)
|
|
582
|
-
w3_dict[new_label] = bands.loc[idcs_comps, 'w3'].min()
|
|
583
|
-
w4_dict[new_label] = bands.loc[idcs_comps, 'w4'].max()
|
|
584
|
-
group_dict[new_label] = group_label
|
|
585
|
-
|
|
586
|
-
# Check the line or the same group is already there
|
|
587
|
-
else:
|
|
588
|
-
low, high = spec.wave_rest.compressed()[[0, -1]]
|
|
589
|
-
check_arr = np.array([(low < Line(label).wavelength < high)[0] for label in component_list])
|
|
590
|
-
|
|
591
|
-
# Lines outside wavelength range
|
|
592
|
-
if np.all(~check_arr):
|
|
593
|
-
continue
|
|
594
|
-
|
|
595
|
-
# Check if lines outside range
|
|
596
|
-
else:
|
|
597
|
-
if 'group_label' in bands.columns:
|
|
598
|
-
if not np.any(comps_dict[new_label] == bands.group_label):
|
|
599
|
-
_logger.info(f'Line component "{old_label}" for configuration entry: '
|
|
600
|
-
f'"{new_label}={comps_dict[new_label]}" not found in lines table')
|
|
601
|
-
else:
|
|
602
|
-
_logger.info(f'Missing line(s) "{np.setxor1d(bands.loc[idcs_comps].index.to_numpy(), component_list)}" '
|
|
603
|
-
f'for configuration entry: '
|
|
604
|
-
f'"{new_label}={comps_dict[new_label]}" in reference lines table')
|
|
605
|
-
|
|
606
|
-
# Warn in case some of the bands dont match the database:
|
|
607
|
-
if not set(exclude_list).issubset(bands.index):
|
|
608
|
-
_logger.info(f' The following blended or merged lines were not found on the input lines database:\n'
|
|
609
|
-
f' - {list(set(exclude_list) - set(bands.index))}\n'
|
|
610
|
-
f' - It is recommended that the merged/blended components follow the reference transitions labels.\n')
|
|
611
|
-
|
|
612
|
-
# Change the latex labels
|
|
613
|
-
for old_label, new_label in rename_dict.items():
|
|
614
|
-
line = Line(new_label, band=bands, fit_conf=comps_dict, update_latex=True)
|
|
615
|
-
bands.loc[old_label, 'latex_label'] = line.latex_label[0] if line.merged_check else '+'.join(line.latex_label)
|
|
616
|
-
|
|
617
|
-
# Change the indexes
|
|
618
|
-
bands.rename(index=dict(rename_dict), inplace=True)
|
|
619
|
-
|
|
620
|
-
# Remove components columns
|
|
621
|
-
bands.drop(exclude_list, errors='ignore', inplace=True)
|
|
622
|
-
|
|
623
|
-
# Add the group_label values
|
|
624
|
-
if 'group_label' not in bands.columns:
|
|
625
|
-
bands['group_label'] = 'none'
|
|
626
|
-
bands['group_label'] = pd.Series(bands.index.map(group_dict), index=bands.index).fillna(bands['group_label'])
|
|
627
|
-
|
|
628
|
-
# Change velocity limits
|
|
629
|
-
bands['w3'] = pd.Series(bands.index.map(w3_dict), index=bands.index).fillna(bands['w3'])
|
|
630
|
-
bands['w4'] = pd.Series(bands.index.map(w4_dict), index=bands.index).fillna(bands['w4'])
|
|
631
|
-
|
|
632
|
-
return
|
|
633
|
-
|
|
634
344
|
|
|
635
345
|
class SpecRetriever:
|
|
636
346
|
|
|
@@ -641,7 +351,7 @@ class SpecRetriever:
|
|
|
641
351
|
return
|
|
642
352
|
|
|
643
353
|
def line_bands(self, band_vsigma=70, n_sigma=4, adjust_central_band=True, instrumental_correction=True, components_detection=False,
|
|
644
|
-
composite_lines=None, fit_cfg=None, default_cfg_prefix='default', obj_cfg_prefix=None, update_default=True,
|
|
354
|
+
composite_lines=None, automatic_grouping=False, fit_cfg=None, default_cfg_prefix='default', obj_cfg_prefix=None, update_default=True,
|
|
645
355
|
line_list=None, particle_list=None, decimals=None, vacuum_waves=False, ref_bands=None, update_labels=False,
|
|
646
356
|
update_latex=False, vacuum_label=False):
|
|
647
357
|
|
|
@@ -685,10 +395,10 @@ class SpecRetriever:
|
|
|
685
395
|
bands['w3'] = (lambda_obs - delta_lambda) / (1 + self._spec.redshift)
|
|
686
396
|
bands['w4'] = (lambda_obs + delta_lambda) / (1 + self._spec.redshift)
|
|
687
397
|
|
|
688
|
-
# Combine the blended/merged lines
|
|
398
|
+
# Combine the blended/merged lines in the bands table
|
|
689
399
|
if fit_cfg is not None:
|
|
690
400
|
in_cfg = check_fit_conf(fit_cfg, default_cfg_prefix, obj_cfg_prefix, update_default)
|
|
691
|
-
pars_bands_conf(self._spec, bands,
|
|
401
|
+
pars_bands_conf(self._spec, bands, in_cfg, composite_lines, automatic_grouping)
|
|
692
402
|
|
|
693
403
|
# Filter the table to match the line detections
|
|
694
404
|
if components_detection:
|
|
@@ -725,7 +435,7 @@ class SpecRetriever:
|
|
|
725
435
|
frame = self._spec.frame if ref_frame is None else ref_frame
|
|
726
436
|
|
|
727
437
|
# By default report complete spectrum
|
|
728
|
-
idcs = (0,
|
|
438
|
+
idcs = (0, None)
|
|
729
439
|
|
|
730
440
|
# If a line is provided get indexes for the bands limits
|
|
731
441
|
line_measured = False
|
|
@@ -838,8 +548,7 @@ class SpecTreatment(LineFitting, RedshiftFitting):
|
|
|
838
548
|
self._n_lines = 0
|
|
839
549
|
|
|
840
550
|
def bands(self, label, bands=None, fit_cfg=None, min_method='least_squares', profile='g-emi', cont_from_bands=True,
|
|
841
|
-
err_from_bands=None, temp=10000.0, default_cfg_prefix='default', obj_cfg_prefix=None, update_default=True
|
|
842
|
-
ref_bands=None):
|
|
551
|
+
err_from_bands=None, temp=10000.0, default_cfg_prefix='default', obj_cfg_prefix=None, update_default=True):
|
|
843
552
|
|
|
844
553
|
"""
|
|
845
554
|
|
|
@@ -911,7 +620,7 @@ class SpecTreatment(LineFitting, RedshiftFitting):
|
|
|
911
620
|
cont_from_bands = True if cont_from_bands is None else cont_from_bands
|
|
912
621
|
|
|
913
622
|
# Interpret the input line
|
|
914
|
-
self.line = Line(label, bands, input_conf, profile, cont_from_bands
|
|
623
|
+
self.line = Line(label, bands, input_conf, profile, cont_from_bands)
|
|
915
624
|
|
|
916
625
|
# Check the line selection is valid
|
|
917
626
|
idcs_selection = review_bands(self._spec, self.line, user_cont_from_bands=cont_from_bands, user_err_from_bands=err_from_bands)
|
|
@@ -940,7 +649,7 @@ class SpecTreatment(LineFitting, RedshiftFitting):
|
|
|
940
649
|
err_arr= pixel_err_arr[idcs_fitting],
|
|
941
650
|
user_conf=input_conf, fit_method=min_method)
|
|
942
651
|
|
|
943
|
-
# Instrumental and thermal corrections for the lines
|
|
652
|
+
# Instrumental and thermal corrections for the lines
|
|
944
653
|
sigma_corrections(self.line, idcs_line, self._spec.wave[idcs_line], self._spec.res_power, temp)
|
|
945
654
|
|
|
946
655
|
# Recalculate the SNR with the profile parameters
|
|
@@ -1081,7 +790,7 @@ class SpecTreatment(LineFitting, RedshiftFitting):
|
|
|
1081
790
|
# Fit the lines
|
|
1082
791
|
self.bands(line, bands, input_conf, min_method, profile,
|
|
1083
792
|
cont_from_bands=cont_from_bands, err_from_bands=err_from_bands,
|
|
1084
|
-
temp=temp, obj_cfg_prefix=None, default_cfg_prefix=None
|
|
793
|
+
temp=temp, obj_cfg_prefix=None, default_cfg_prefix=None)
|
|
1085
794
|
|
|
1086
795
|
if plot_fit:
|
|
1087
796
|
self._spec.plot.bands()
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
lime/__init__.py,sha256=i7iYJDoAYCsApb35OG33Y0repT6FpgLCsFMTk0Nu0rM,1279
|
|
2
2
|
lime/changelog.txt,sha256=e02y8w_romtBvZLt7wrDxfL0Kry5ccTUkaajX_XwHbs,9657
|
|
3
|
-
lime/io.py,sha256=
|
|
4
|
-
lime/lime.toml,sha256=
|
|
5
|
-
lime/observations.py,sha256=
|
|
3
|
+
lime/io.py,sha256=J3oGfyznx-dqZCIY2tlTWBmuQzQEEJiBgU9Jpu-Sc9E,32778
|
|
4
|
+
lime/lime.toml,sha256=oIJIPuAkwCzbGRKwY9gknhQRFHCyIcibg6BsC0yZd64,52
|
|
5
|
+
lime/observations.py,sha256=BjzcfGi0VbzWUHw3DpME4AK3hxWaqC4fjt9bT1o_oxk,65018
|
|
6
6
|
lime/tools.py,sha256=5E7_YeXeLrzFo-2h5EAI8J-cPaK4i6g6OJ1uL2jXJ7o,34136
|
|
7
|
-
lime/transitions.py,sha256
|
|
8
|
-
lime/workflow.py,sha256=
|
|
7
|
+
lime/transitions.py,sha256=9zxgUIgRRQIq1LFwiDSFYYdnMAppH-tENL6W2RIrw6Q,45639
|
|
8
|
+
lime/workflow.py,sha256=7FqULLns2KKAlAf8AFQ_iEjMjts3k-Y3L1PLwVHubvQ,51784
|
|
9
9
|
lime/archives/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
lime/archives/read_fits.py,sha256=
|
|
10
|
+
lime/archives/read_fits.py,sha256=EifjLTsklZcrUAtCtuind5KWvDtEK_wMw_-5HA1P7l8,37928
|
|
11
11
|
lime/archives/tables.py,sha256=sn3dINNorARuhEA_NsUKnhz8pT5d9u_sNBNKgv3EtuA,14242
|
|
12
12
|
lime/fitting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
lime/fitting/lines.py,sha256=
|
|
13
|
+
lime/fitting/lines.py,sha256=4WVw_auqLCCzftoxMJzhxYWJVqC1umcURWRq8kbScR8,40423
|
|
14
14
|
lime/fitting/redshift.py,sha256=JBYQlESr63PrF3gRYVT-QLQr2yMi9YZKaeNxI8gFvgY,11639
|
|
15
15
|
lime/inference/detection.py,sha256=m_Yz-53RGEvQQa6rgS_-nU2DwiRG45yuZIuneAvs0Dc,425
|
|
16
16
|
lime/inference/intensity_threshold.py,sha256=9LqSjJQajfrM4SOHSqJWnverKFnrdrjnV472w56T79U,5047
|
|
17
17
|
lime/plotting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
18
|
lime/plotting/bokeh_plots.py,sha256=xJlFS90NW-kQLSBDrfYd3tkjixyHK0DUs1vm5ExmjOQ,23444
|
|
19
19
|
lime/plotting/format.py,sha256=KM2UjhfJ7j2iEOIRTn8JfpLNmSRSlUFTHqB5EKxTq80,7296
|
|
20
|
-
lime/plotting/plots.py,sha256=
|
|
21
|
-
lime/plotting/plots_interactive.py,sha256=
|
|
20
|
+
lime/plotting/plots.py,sha256=hWyFL82U0UaTe6nspkhsEzMJqrZmz-Myck55wXvlPKE,85352
|
|
21
|
+
lime/plotting/plots_interactive.py,sha256=9qj369eRBGI53qAvqAToUb4t1KqpSO4R_ZeGhovhwgg,73353
|
|
22
22
|
lime/plotting/theme_lime.toml,sha256=moyNfRDx0x0Gma3azW_DNfLQoKd1qnBRiX0DAkioBbs,3396
|
|
23
23
|
lime/plotting/utils.py,sha256=tPBXCvMlg7_onLWN9O2I7FoAurzkfF0Qe-JVYSLb1Xs,2069
|
|
24
24
|
lime/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -27,9 +27,10 @@ lime/resources/lines_database_v2.0.0.txt,sha256=grhl32eDMtHHnXOw-LVmSCPbYjqUgccJ
|
|
|
27
27
|
lime/resources/logo.py,sha256=buuJuwCjw0JFFtqvvIBpjb-LCuFgBwRFqnVOqCmSam8,3296
|
|
28
28
|
lime/resources/types_params.txt,sha256=HgK-rr_cHnjNR3oLJomdYt6UvKwBn-FMWt40MkCR0wM,10111
|
|
29
29
|
lime/retrieve/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
|
+
lime/retrieve/line_bands.py,sha256=QwcU5A2_4987q4JgIFF3p89r7pwQVlSlD4fSTZWwBpc,10595
|
|
30
31
|
lime/retrieve/peaks.py,sha256=zERD2-GO-AtNrx8xwGqNbml0pB0nTCH4Oro-9fr69GU,8713
|
|
31
|
-
lime_stable-2.0.
|
|
32
|
-
lime_stable-2.0.
|
|
33
|
-
lime_stable-2.0.
|
|
34
|
-
lime_stable-2.0.
|
|
35
|
-
lime_stable-2.0.
|
|
32
|
+
lime_stable-2.0.dev8.dist-info/licenses/LICENSE.rst,sha256=B_kw459IXvKujLR27bhVUwXmTq9AM72DdCA1xGgBMKI,35608
|
|
33
|
+
lime_stable-2.0.dev8.dist-info/METADATA,sha256=cJ-MeAUOkn4CEF6tIqp8Ihn2fldgXMwssvI-Gcy3jII,3931
|
|
34
|
+
lime_stable-2.0.dev8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
35
|
+
lime_stable-2.0.dev8.dist-info/top_level.txt,sha256=F6pWR5Cgjf9EkXNBZlUSKFKcPG8vPzM08QwYFfwpsZc,5
|
|
36
|
+
lime_stable-2.0.dev8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|