def __init__(self):

        # Declare Hydrogen and Helium collisional lines for the analysis
        self.Hydrogen_Lines = ["Hdelta_6_2", "Hgamma_5_2", "Hbeta_4_2", "Halpha_3_2"]
        self.Hydrogen_Labels = ["6_2", "5_2", "4_2", "3_2"]
        self.Hydrogen_Wavelengths = [4101.742, 4340.471, 4862.683, 6562.819]

        self.Helium_Lines = ["He1_3889", "He1_4026.0", "He1_4471.0", "He1_5876.0", "He1_6678.0", "He1_7065.0"]
        self.Helium_Labels = ["3889.0", "4026.0", "4471.0", "5876.0", "6678.0", "7065.0"]
        self.Helium_Wavelengths = [3889.0, 4026.0, 4471.0, 5876.0, 6678.0, 7065.0]

        # Define indexes and labels to speed up the code
        self.HBeta_label = "4_2"
        self.HBeta_Index = self.Hydrogen_Lines.index("Hbeta_4_2")
        self.nHydrogen = range(len(self.Hydrogen_Lines))
        self.nHelium = range(len(self.Helium_Lines))

        # THIS TRICK IS NECCESARY SO THAT WE DO NOT INCLUDE THE HBETA LINE IN THE CALCULATION
        self.nHydrogen.remove(self.HBeta_Index)
        Valid_H_Lines = list(self.Hydrogen_Wavelengths)
        del Valid_H_Lines[self.HBeta_Index]

        # Declare pyneb Hydrogen and Helium atoms to calculate emissivities
        self.H1 = RecAtom("H", 1)
        self.He1 = RecAtom("He", 1)
        self.H_emissivity_Vector = zeros(len(self.nHydrogen))  # Array to store the emissivities for each of the labels
        self.He_emissivity_Vector = zeros(
            len(self.Helium_Labels)
        )  # Array to store the emissivities for each of the labels

        # Import collisional coefficients table
        self.H_CollCoeff_Matrix = self.Import_Coll_Coeff_Table("H")
        self.He_CollCoeff_Matrix = self.Import_Coll_Coeff_Table("He")
        self.H_CRratio_Vector = zeros(len(self.nHydrogen))  # Array to store the C/R for each of the HydrogenLines
        self.He_CRratio_Vector = zeros(len(self.Helium_Labels))  # Array to store the C/R for each of the HydrogenLines

        # Import Optical depth function for He lines
        self.He_OpticalDepth_Matrix = self.Import_OpticalDepth_Coeff_Table("He")
        self.f_Hetau_vector = zeros(len(self.Helium_Labels))

        # Calculate f_lambda in advance law configuration (from Cardelli, Clayton and Mathis law)
        self.R_v = 3.1
        self.a_coeffs = array([1.0, 0.17699, -0.50447, -0.02427, 0.72085, 0.01979, -0.77530, 0.32999])
        self.b_coeffs = array([0.0, 1.41338, 2.28305, 1.07233, -5.38434, -0.62251, 5.30260, -2.09002])

        self.f_H_vector = self.get_flambda_vector(array(Valid_H_Lines))
        self.f_He_vector = self.get_flambda_vector(array(self.Helium_Wavelengths))

        # Extra
        self.EmptyRowFormat = "nan"
    def __init__(self):
        
        #Import Dazer_Files Class to import data from lines_logs
        Txt_Files_Manager.__init__(self)
        
        #Declare Hydrogen and Helium collisional lines for the analysis
        #self.posHydrogen_Ions      = ['Hdelta_6_2',    'Hgamma_5_2',   'Hbeta_4_2',    'Halpha_3_2']
        self.posHydrogen_Lines      = ['H1_4102A',      'H1_4340A',     'H1_4861A',     'H1_6563A']
        self.Hydrogen_Wavelengths   = [4101.742,        4340.471,       4862.683,        6562.819]
        
        self.posHelium_Lines        = ['H1_3889A',  'He1_4026A',    'He1_4387A',    'He1_4471A',    'He1_4686A',    'He1_4714A',    'He1_4922A',   'He1_5876A',    'He1_6678A',   'He1_7065A',    'He1_7281A',      'He1_10830A']     
        self.Helium_Wavelengths     = [3889.0,        4026.0,         4387.0,         4471.0,         4686.0,         4714.0,         4922.0,         5876.0,         6678.0,         7065.0,         7281.0,         10830.0]
        
        self.Cand_Hydrogen_Lines    = []
        self.Cand_Helium_Lines      = []
        
        self.nHydrogen              = None
        self.nHelium                = None
    
        #Define indexes and labels to speed up the code
        self.H13889A_label          = 'H1_3889A'          
        self.HBeta_label            = 'H1_4861A'
        self.He3889_label           = 'He1_3889A'
        self.He3889blended_label    = 'He1_3889A_blended'
        self.He3889_check           = None
        
        #Declare pyneb Hydrogen and Helium atoms to calculate emissivities
        self.H1                     = RecAtom('H', 1)
        self.He1                    = RecAtom('He', 1) 
        
        #Import collisional coefficients table
        self.Coef_Kalpha_dict       = self.Import_Coll_Coeff_Table(self.posHydrogen_Lines, None)

        #Import Optical depth function
        self.Coef_ftau_dict         = self.Import_OpticalDepth_Coeff_Table(self.posHelium_Lines) 
               
        #Declare dictionaries to store the data
        #WARNING: In this analysis flambda is mantained constant
        self.Flux_dict              = OrderedDict()
        self.Error_dict             = OrderedDict()
        self.Wave_dict              = OrderedDict()
        self.PynebCode_dict         = OrderedDict()
        self.EqW_dict               = OrderedDict()
        self.EqWerror_dict          = OrderedDict()
        self.hlambda_dict           = OrderedDict()
        self.flambda_dict           = self.get_flambda_dict(self.posHydrogen_Lines + self.posHelium_Lines, self.Hydrogen_Wavelengths + self.Helium_Wavelengths)
        
        #Extra
        self.EmptyRowFormat         = 'nan'            
Exemple #3
0
    return TotalWave, TotalInt

Pv                                      = plotMan.myPickle()
CatalogueFolder, DataType, Log_Format   = DataToTreat()              #First batch process for untreated spectra
Pattern                                 = '_' + DataType + '.fits'                
Emission_DataLog_Suffix                 = '_' + DataType + '_LinesLog_v3.txt'   

#Find and organize files from terminal command or .py file
FilesList = Pv.FindAndOrganize(Pattern, CatalogueFolder, CheckComputer=True)

# Generate figures
Pv.FigFormat_One(ColorConf='Night1')

Coefficients = []

H1 = RecAtom('H', 1)

# Loop through files
for m in range(len(FilesList)):     
    for j in range(len(FilesList[m])):

        CodeName, FileName, FileFolder = Pv.FileAnalyzer(FilesList[m][j])
        SetLogFile(CodeName + '_log.txt', FileFolder, Pv.ComputerRoot + 'Dropbox/Astrophysics/Data/WHT_HII_Galaxies/WHT_Log_Format.txt')

        if DataType == 'WHT':

            Blue_Filename   = 'obj' + CodeName + '_Blue_t_z_EBV.fits'
            Red_FileName    = 'obj' + CodeName +  '_Red_t_tell_z_EBV.fits'
            
            Wave_Total, Int_Total, ExtraData_Comb    = Pv.File2Data(FileFolder, FileName)
            Wave_Blue, Int_Blue, ExtraData_Blue = Pv.File2Data(FileFolder, Blue_Filename)
class HeAbundance_InferenceMethods(Dazer_Files):
    
    def __init__(self):
        
        #Import Dazer_Files Class to import data from lines_logs
        Dazer_Files.__init__(self)
        
        #Declare Hydrogen and Helium collisional lines for the analysis
        self.posHydrogen_Lines      = ['Hdelta_6_2',    'Hgamma_5_2',   'Hbeta_4_2',    'Halpha_3_2']
        self.Hydrogen_Wavelengths   = [4101.742,        4340.471,       4862.683,        6562.819]
        
        self.posHelium_Lines        = ['He1_3889A',  'He1_4026A',    'He1_4387A',    'He1_4471A',    'He1_4686A',    'He1_4714A',    'He1_4922A',   'He1_5876A',    'He1_6678A',   'He1_7065A',    'He1_7281A',      'He1_10380A']     
        self.Helium_Wavelengths     = [3889.0,        4026.0,         4387.0,         4471.0,         4686.0,         4714.0,         4922.0,         5876.0,         6678.0,         7065.0,         7281.0,         10380.0]
        
        self.Cand_Hydrogen_Lines    = []
        self.Cand_Helium_Lines      = []
        
        self.nHydrogen              = None
        self.nHelium                = None
    
        #Define indexes and labels to speed up the code               
        self.HBeta_label            = 'Hbeta_4_2'
                
        #Declare pyneb Hydrogen and Helium atoms to calculate emissivities
        self.H1                     = RecAtom('H', 1)
        self.He1                    = RecAtom('He', 1) 
        
        #Import collisional coefficients table
        self.Coef_Kalpha_dict       = self.Import_Coll_Coeff_Table(self.posHydrogen_Lines, None)

        #Import Optical depth function
        self.Coef_ftau_dict         = self.Import_OpticalDepth_Coeff_Table(self.posHelium_Lines) 
               
        #Declare dictionaries to store the data
        #WARNING: In this analysis flambda is mantained constant
        self.Flux_dict              = OrderedDict()
        self.Error_dict             = OrderedDict()
        self.Wave_dict              = OrderedDict()
        self.PynebCode_dict         = OrderedDict()
        self.EqW_dict               = OrderedDict()
        self.EqWerror_dict          = OrderedDict()
        self.hlambda_dict           = OrderedDict()
        self.flambda_dict           = self.get_flambda_dict(self.posHydrogen_Lines + self.posHelium_Lines, self.Hydrogen_Wavelengths + self.Helium_Wavelengths)
        
        #Extra
        self.EmptyRowFormat         = 'nan'            
            
    def Import_TableData(self, Address, Columns):
        
        Imported_Array  = genfromtxt(Address, dtype=float, usecols = Columns, skiprows = 2).T
        Datarray = Imported_Array[:,~isnan(Imported_Array).all(0)]
                
        return Datarray
     
    def Import_Coll_Coeff_Table(self, HydrogenLines, HeliumLines):
        
        data_dict = OrderedDict()
                
        for i in range(len(HydrogenLines)):
            
            Line            = HydrogenLines[i]
            Data_Columns    = [0 + 3*i, 1 + 3*i, 2 + 3*i]
            data_dict[Line] = self.Import_TableData(self.Hydrogen_CollCoeff_TableAddress, Data_Columns)
        
        #We ignore since the emissivities from PFM already have the collisional contribution accounted
#         for j in range(len(HeliumLines)):
#             
#             Line            = HeliumLines[i]
#             Data_Columns    = [0 + 3*j, 1 + 3*j, 2 + 3*j]
#             data_dict[Line] = self.Import_TableData(self.Helium_CollCoeff_TableAddress, Data_Columns)
            
        return data_dict
     
    def Import_OpticalDepth_Coeff_Table(self, HeliumLines):
        
        data_dict = OrderedDict()

        for i in range(len(HeliumLines)):
            
            Line            = HeliumLines[i]
            data_dict[Line] = loadtxt(self.Helium_OpticalDepth_TableAddress, dtype = float, skiprows = 2, usecols = (i,))
            
        return data_dict
    
    def Import_Synthetic_Fluxes(self, Model = 'Model2'):

        self.SyntheticData_dict = OrderedDict()

        if Model == 'Model1':
#             self.SyntheticData_dict['He_Flux']      = array([ 0.0891384,    0.01283333,     0.03187135, 0.09890274, 0.02582588, 0.02366021])   
#             self.SyntheticData_dict['He_Flux']      = array([ 0.0891384,    0.01283333,     0.03187135, 0.09890274, 0.02582588, 0.02366021])
            
            self.SyntheticData_dict['H_Flux']       = array([ 0.24685935,   0.45526236,     1.0,            2.96988502])
            self.SyntheticData_dict['H_wave']       = array([4101.742,      4340.471,      4862.683,       6562.819])
            self.SyntheticData_dict['H_labels']     = ['Hdelta_6_2',    'Hgamma_5_2',   'Hbeta_4_2',    'Halpha_3_2']
            self.SyntheticData_dict['H_Eqw']        = [50.0,            50.0,           250,             300.0]
            self.SyntheticData_dict['H_EqwErr']     = [1.0,             1.0,            12.5,            14]
            self.SyntheticData_dict['H_hlambda']    = [1.0,             1.0,            1.0,             1.0]
            self.SyntheticData_dict['H_error']      = self.SyntheticData_dict['H_Flux'] * 0.01
            
            self.SyntheticData_dict['He_Flux']      = array([ 0.08951096,    0.01290066,     0.03201484, 0.09931435, 0.02594518, 0.02377085])   
            self.SyntheticData_dict['He_wave']      = array([ 3889.0,       4026.0,         4471.0,        5876.0,     6678.0,     7065.0])
            self.SyntheticData_dict['He_labels']    =       ['He1_3889A',   'He1_4026A',   'He1_4471A',   'He1_5876A','He1_6678A','He1_7065A']
            self.SyntheticData_dict['He_Eqw']       = [10.0,                10.0,           10.0,           10.0,        10.0,          10.0]
            self.SyntheticData_dict['He_EqwErr']    = [1.0,                 1.0,            1.0,            1.0,         1.0,           1.0]
            self.SyntheticData_dict['He_hlambda']   = [1.0,                 1.0,            1.0,            1.0,         1.0,           1.0] 
            self.SyntheticData_dict['He_error']     = self.SyntheticData_dict['He_Flux'] * 0.02
                        
            self.SyntheticData_dict['TOIII']        = 19000
            self.SyntheticData_dict['y_plus']       = 0.08
            self.SyntheticData_dict['n_e']          = 100.0
            self.SyntheticData_dict['a_He']         = 1.0
            self.SyntheticData_dict['tau']          = 0.2
            self.SyntheticData_dict['Te_0']         = 18000.0
            self.SyntheticData_dict['cHbeta']       = 0.1
            self.SyntheticData_dict['a_H']          = 1.0
            self.SyntheticData_dict['xi']           = 1.0

        if Model == 'Model2':
            
            #These are the ones from the version 0
            #self.SyntheticData_dict['H_Flux']       = array([ 0.24585991,  0.45343263,  2.95803687])
            #self.SyntheticData_dict['He_Flux']      = array([ 0.10059744,  0.01684244,  0.03908421,  0.12673761,  0.03538569,  0.04145339])
            #These are the ones from the version 1
            self.SyntheticData_dict['H_Flux']       = array([0.24625485, 0.454443,      1,              2.98352834])
            self.SyntheticData_dict['H_wave']       = array([4101.742,   4340.471,      4862.683,       6562.819])
            self.SyntheticData_dict['H_labels']     = ['Hdelta_6_2',    'Hgamma_5_2',   'Hbeta_4_2',    'Halpha_3_2']
            self.SyntheticData_dict['H_Eqw']        = [50.0,            50.0,           250,             300.0]
            self.SyntheticData_dict['H_EqwErr']     = [1.0,             1.0,            12.5,            14]
            self.SyntheticData_dict['H_hlambda']    = [1.0,             1.0,            1.0,             1.0]
            self.SyntheticData_dict['H_error']      = self.SyntheticData_dict['H_Flux'] * 0.01
            
            self.SyntheticData_dict['He_Flux']      = array([0.10100783,    0.01691781,     0.03924855,     0.12725256,  0.03553524,    0.04162797])
            self.SyntheticData_dict['He_wave']      = array([ 3889.0,       4026.0,         4471.0,         5876.0,      6678.0,        7065.0])
            self.SyntheticData_dict['He_labels']    = ['He1_3889A',         'He1_4026A',   'He1_4471A',   'He1_5876A',  'He1_6678A',    'He1_7065A']
            self.SyntheticData_dict['He_Eqw']       = [10.0,                10.0,           10.0,           10.0,        10.0,          10.0]
            self.SyntheticData_dict['He_EqwErr']    = [1.0,                 1.0,            1.0,            1.0,         1.0,           1.0]
            self.SyntheticData_dict['He_hlambda']   = [1.0,                 1.0,            1.0,            1.0,         1.0,           1.0] 
            self.SyntheticData_dict['He_error']     = self.SyntheticData_dict['He_Flux'] * 0.02

            self.SyntheticData_dict['TOIII']        = 17000
            self.SyntheticData_dict['y_plus']       = 0.085
            self.SyntheticData_dict['n_e']          = 500.0
            self.SyntheticData_dict['a_He']         = 0.5
            self.SyntheticData_dict['tau']          = 1.0
            self.SyntheticData_dict['Te_0']         = 16000.0
            self.SyntheticData_dict['cHbeta']       = 0.1
            self.SyntheticData_dict['a_H']          = 1.0
            self.SyntheticData_dict['xi']           = 1.0
                                   
        return
    
    def Check_EmissionLinesObserved(self, Data_Dict):
        
        #Empty the lists of candidate lines for Hydrogen and Helium
        del self.Cand_Hydrogen_Lines[:]
        del self.Cand_Helium_Lines[:]
                
        #Loop through the hydrogen lines to store the properties of those we can use to perform the analysis
        Obs_HydrogenLabels          = Data_Dict['H_labels']
        for i in range(len(self.posHydrogen_Lines)):
            Line_Label                      = self.posHydrogen_Lines[i]
            if Line_Label in Obs_HydrogenLabels:
                Line_Index                      = Obs_HydrogenLabels.index(Line_Label)
                self.Flux_dict[Line_Label]      = Data_Dict['H_Flux'][Line_Index]   
                self.Error_dict[Line_Label]     = Data_Dict['H_error'][Line_Index]
                self.Wave_dict[Line_Label]      = Data_Dict['H_wave'][Line_Index]
                self.EqW_dict[Line_Label]       = Data_Dict['H_Eqw'][Line_Index]
                self.EqWerror_dict[Line_Label]  = Data_Dict['H_EqwErr'][Line_Index]
                self.hlambda_dict[Line_Label]   = Data_Dict['H_hlambda'][Line_Index]
                self.PynebCode_dict[Line_Label] = Line_Label[Line_Label.find('_')+1:len(Line_Label)]
                self.Cand_Hydrogen_Lines.append(Line_Label)
                
        #Loop through the helium lines to store the properties of those we can use to perform the analysis
        Obs_HeliumLabels                        = Data_Dict['He_labels']
        for i in range(len(self.posHelium_Lines)):
            Line_Label                          = self.posHelium_Lines[i]
            if Line_Label in Obs_HeliumLabels:
                Line_Index                      = Obs_HeliumLabels.index(Line_Label)
                self.Flux_dict[Line_Label]      = Data_Dict['He_Flux'][Line_Index]   
                self.Error_dict[Line_Label]     = Data_Dict['He_error'][Line_Index]
                self.Wave_dict[Line_Label]      = Data_Dict['He_wave'][Line_Index]
                self.EqW_dict[Line_Label]       = Data_Dict['He_Eqw'][Line_Index]
                self.EqWerror_dict[Line_Label]  = Data_Dict['He_EqwErr'][Line_Index]
                self.hlambda_dict[Line_Label]   = Data_Dict['He_hlambda'][Line_Index]
                self.PynebCode_dict[Line_Label] = Line_Label[Line_Label.find('_')+1:-1]+'.0'
                self.Cand_Helium_Lines.append(Line_Label)
        
        #Since the Hbeta line is not used for the fitting we remove it from the candidates lines list. However, its properties are still stored in the dictionaries
        self.Cand_Hydrogen_Lines.remove(self.HBeta_label)
        
        #Define number of lines variables to speed up the calculation
        self.nHydrogen              = len(self.Cand_Hydrogen_Lines)
        self.nHelium                = len(self.Cand_Helium_Lines)
        
        self.nHydrogen_range        = range(self.nHydrogen)
        self.nHelium_range          = range(self.nHelium)
                
        #Oxygen temperature prior
        self.TOIIIprior             = Data_Dict['TOIII']
        self.TOIIIprior_sigma       = self.TOIIIprior * 0.2
        
    def Preload_Data(self, Hbeta_Normalized = True):

        #Define the vectors where we store the physical parameters
        self.Flux_H_vector                          = zeros(self.nHydrogen)
        self.Error_H_vector                         = zeros(self.nHydrogen)
        self.Emissivity_H_vector                    = zeros(self.nHydrogen)
        self.Kalpha_vector                          = zeros(self.nHydrogen)
        self.flambda_H_vector                       = zeros(self.nHydrogen)
        #self.Eqw_H_vector                         = zeros(self.nHydrogen)
        #self.EqwError_H_vector                    = zeros(self.nHydrogen)
        self.hlambda_H_vector                       = ones(self.nHydrogen)

        self.Flux_He_vector                         = zeros(self.nHelium)
        self.Error_He_vector                        = zeros(self.nHelium)
        self.Emissivity_He_vector                   = zeros(self.nHelium)
        self.ftau_He_vector                         = zeros(self.nHelium)
        self.flambda_He_vector                      = zeros(self.nHelium)
        #self.Eqw_He_vector                        = zeros(self.nHelium)
        #self.EqwError_He_vector                   = zeros(self.nHelium)
        self.hlambda_He_vector                      = ones(self.nHelium)
      
        #Define HBeta values in advance
        self.Hbeta_Flux                             = self.Flux_dict[self.HBeta_label]
        self.Hbeta_error                            = self.Error_dict[self.HBeta_label]
        self.Hbeta_EW                               = self.EqW_dict[self.HBeta_label]
        self.Hbeta_EWerror                          = self.EqWerror_dict[self.HBeta_label]      
        self.hbeta_hlambda                          = self.hlambda_dict[self.HBeta_label]
      
        #Calculate in advance observed physical parameters vectors for Hydrogen lines
        for i in range(self.nHydrogen):
            Line_Label                              = self.Cand_Hydrogen_Lines[i]        
            self.Flux_H_vector[i]                   = self.Flux_dict[Line_Label]
            self.Error_H_vector[i]                  = self.Error_dict[Line_Label]
            self.hlambda_H_vector[i]                = self.hlambda_dict[Line_Label]
            self.flambda_H_vector[i]                = self.flambda_dict[Line_Label]

        for i in range(self.nHelium):
            Line_Label                              = self.Cand_Helium_Lines[i]
            self.Flux_He_vector[i]                  = self.Flux_dict[Line_Label]
            self.Error_He_vector[i]                 = self.Error_dict[Line_Label]
            self.flambda_He_vector[i]               = self.flambda_dict[Line_Label]
            self.hlambda_He_vector[i]               = self.hlambda_dict[Line_Label]             

        #Combine Hydrogen and Helium values into a single vector
        if Hbeta_Normalized: 
            self.H_He_Obs_Flux                      = concatenate([self.Flux_H_vector, self.Flux_He_vector])
            self.H_He_Obs_Error                     = concatenate([self.Error_H_vector, self.Error_He_vector])

        else:
            self.H_He_Obs_Flux                      = concatenate([self.Flux_H_vector, self.Flux_He_vector])    / self.Hbeta_Flux
            self.H_He_Obs_Error                     = concatenate([self.Error_H_vector, self.Error_He_vector])  
        
        #Dictionary with the vectors
        self.Data_Dict = {'Hbeta_Kalpha'    : None, 
                     'Hbeta_emis'           : None,
                     'Emissivity_H_vector'  : None,
                     'Kalpha_vector'        : None,
                     'Emissivity_He_vector' : None,
                     'ftau_He_vector'       : None,
                     'T_4'                  : None} 
        
    def Calculate_Parameters_Vectors(self, T_e, n_e, tau):    
        
        #Calculate in advance the T_4 parameter
        T_4 = T_e / 10000.0
        
        #Calculate the hbeta parameters
        self.Data_Dict['Hbeta_Kalpha']              = self.Kalpha_Ratio_H(T_4 = T_4, H_label=self.HBeta_label)
        self.Data_Dict['Hbeta_emis']                = self.H1.getEmissivity(T_e, n_e, label = self.PynebCode_dict[self.HBeta_label])

        #Calculate physical parameters for Hydrogen lines
        for i in self.nHydrogen_range:
            self.Emissivity_H_vector[i]             = self.H1.getEmissivity(T_e, n_e, label = self.PynebCode_dict[self.Cand_Hydrogen_Lines[i]])
            self.Kalpha_vector[i]                   = self.Kalpha_Ratio_H(T_4 = T_4, H_label=self.Cand_Hydrogen_Lines[i])
            
        #Calculate physical parameters for Helium lines
        for i in self.nHelium_range:
            self.Emissivity_He_vector[i]            = self.He1.getEmissivity(T_e, n_e, label = self.PynebCode_dict[self.Cand_Helium_Lines[i]])
            self.ftau_He_vector[i]                  = self.OpticalDepth_He(tau = tau, T_4 = T_4, n_e = n_e, He_label = self.Cand_Helium_Lines[i])

# #         self.Data_Dict = {'Hbeta_Kalpha'         : self.Hbeta_Kalpha, 
# #                      'Hbeta_emis'           : self.Hbeta_emis,
# #                      'Emissivity_H_vector'  : self.Emissivity_H_vector,
# #                      'Kalpha_vector'        : self.Kalpha_vector,
# #                      'Emissivity_He_vector' : self.Emissivity_He_vector,
# #                      'ftau_He_vector'       : self.ftau_He_vector} 
#        
#         self.Data_Dict['Emissivity_H_vector']   = self.Emissivity_H_vector
#         self.Data_Dict['Kalpha_vector']         = self.Kalpha_vector     
#         self.Data_Dict['Emissivity_He_vector']  = self.Emissivity_He_vector
#         self.Data_Dict['ftau_He_vector']        = self.ftau_He_vector
        
        return self.Data_Dict
    
    def Calculate_H_Parameters_Vectors(self, T_e, n_e, tau):    
        
        #Calculate in advance the T_4 parameter
        self.Data_Dict['T_4'] = T_e / 10000.0
        
        #Calculate the hbeta parameters
        self.Data_Dict['Hbeta_Kalpha']              = self.Kalpha_Ratio_H(T_4 = self.Data_Dict['T_4'], H_label=self.HBeta_label)
        self.Data_Dict['Hbeta_emis']                = self.H1.getEmissivity(T_e, n_e, label = self.PynebCode_dict[self.HBeta_label])

        #Calculate physical parameters for Hydrogen lines
        for i in self.nHydrogen_range:
            self.Emissivity_H_vector[i]             = self.H1.getEmissivity(T_e, n_e, label = self.PynebCode_dict[self.Cand_Hydrogen_Lines[i]])
            self.Kalpha_vector[i]                   = self.Kalpha_Ratio_H(T_4 = self.Data_Dict['T_4'], H_label=self.Cand_Hydrogen_Lines[i])
        
        self.Data_Dict['Emissivity_H_vector']       = self.Emissivity_H_vector
        self.Data_Dict['Kalpha_vector']             = self.Kalpha_vector
                
        return self.Data_Dict    
    
    def Calculate_He_Parameters_Vectors(self, T_e, n_e, tau):
    
        #Calculate physical parameters for Helium lines
        for i in self.nHelium_range:
            self.Emissivity_He_vector[i]            = self.He1.getEmissivity(T_e, n_e, label = self.PynebCode_dict[self.Cand_Helium_Lines[i]])
            self.ftau_He_vector[i]                  = self.OpticalDepth_He(tau = tau, T_4 = self.Data_Dict['T_4'], n_e = n_e, He_label = self.Cand_Helium_Lines[i])    
        
        self.Data_Dict['Emissivity_He_vector']      = self.Emissivity_He_vector
        self.Data_Dict['ftau_He_vector']            = self.ftau_He_vector
        
        return self.Data_Dict

    def H_Flux_theo(self, xi, cHbeta, a_H, data_dict):
                
        #Calculate the emissivities for each of the lines for the given temperature and density
        Emissivities_module = data_dict['Emissivity_H_vector'] / data_dict['Hbeta_emis'] 
        
        #Calculate the Collisional excitation fraction
        CR_Module           = (1.0 + 0.0001* xi *data_dict['Kalpha_vector']) / (1.0 + 0.0001* xi * data_dict['Hbeta_Kalpha'] )
        
        #Calculate the reddening component
        f_module            = power(10, -1 * self.flambda_H_vector * cHbeta)
        
        #Calculate the Hbeta normalization module
        EW_Hbeta_module     = (self.Hbeta_EW + a_H) / self.Hbeta_EW
        
        #Calculate stellar absorption module
        a_H_module          = (a_H * self.hlambda_H_vector) / (self.Hbeta_EW * self.hbeta_hlambda)
        
        #Calculate theoretical Hydrogen flux for each emission line
        H_Flux              = Emissivities_module * CR_Module * f_module * EW_Hbeta_module - a_H_module
             
        return H_Flux

    def He_Flux_theo_nof(self, xi, cHbeta, a_H, a_He, y_plus, data_dict):
                      
        #Calculate the emissivities for each of the lines for the given temperature and density
        Emissivities_module = data_dict['Emissivity_He_vector'] / data_dict['Hbeta_emis']
        
        #Calculate the collisional excitation fraction
        CR_Module           = 1 / (1.0 + 0.0001* xi * data_dict['Hbeta_Kalpha'])

        #Calculate the reddening component
        f_module            = power(10, -1 * self.flambda_He_vector * cHbeta)

        #Calculate the Hbeta normalization module
        EW_Hbeta_module     = (self.Hbeta_EW + a_H) / self.Hbeta_EW
        
        #Calculate stellar absorption module
        a_He_module         = (a_He * self.hlambda_He_vector) / (self.Hbeta_EW * self.hbeta_hlambda)
             
        #Calculate theoretical Hydrogen flux for each emission line
        He_Flux             = y_plus * Emissivities_module * data_dict['ftau_He_vector'] * CR_Module * f_module * EW_Hbeta_module - a_He_module

        return He_Flux
               
    def get_flambda_dict(self, lines_labels, lines_wavelengths, R_v=3.1):
    
        x_true          = 1.0 / (array(lines_wavelengths) / 10000.0)
        y               = x_true - 1.82
    
        y_coeffs        = array([ones(len(y)), y, power(y, 2), power(y, 3), power(y, 4), power(y, 5), power(y, 6), power(y, 7)])
        a_coeffs        = array([1, 0.17699,    -0.50447,   -0.02427,   0.72085,    0.01979,    -0.77530,   0.32999])
        b_coeffs        = array([0, 1.41338,    2.28305,   1.07233,   -5.38434,    -0.62251,    5.30260,   -2.09002])
        
        a_x             = dot(a_coeffs,y_coeffs)
        b_x             = dot(b_coeffs,y_coeffs)
        
        X_x             = a_x + b_x / R_v
        
        y_beta          = (1 / (4862.683 / 10000)) - 1.82
        y_beta_coeffs   = array([1, y_beta, power(y_beta, 2), power(y_beta, 3), power(y_beta, 4), power(y_beta, 5), power(y_beta, 6), power(y_beta, 7)])
        
        X_x_beta        = dot(a_coeffs,y_beta_coeffs) + dot(b_coeffs,y_beta_coeffs) / R_v
    
        f               = X_x / X_x_beta - 1
        
        return dict(zip(lines_labels , f))
         
    def Kalpha_Ratio_H(self, T_4, H_label):
                
        K_alpha_Ratio   = sum(self.Coef_Kalpha_dict[H_label][0] * exp(self.Coef_Kalpha_dict[H_label][1] / T_4) * power(T_4, self.Coef_Kalpha_dict[H_label][2]))
        
        return K_alpha_Ratio
    
    def OpticalDepth_He(self, tau, T_4, n_e, He_label):
                        
        f_tau   = 1 + (tau/2) * (self.Coef_ftau_dict[He_label][0] + (self.Coef_ftau_dict[He_label][1] + self.Coef_ftau_dict[He_label][2]*n_e + self.Coef_ftau_dict[He_label][3]*n_e*n_e) * T_4)

        return f_tau       
class HeAbundance_InferenceMethods(Txt_Files_Manager):
    
    def __init__(self):
        
        #Import Dazer_Files Class to import data from lines_logs
        Txt_Files_Manager.__init__(self)
        
        #Declare Hydrogen and Helium collisional lines for the analysis
        #self.posHydrogen_Ions      = ['Hdelta_6_2',    'Hgamma_5_2',   'Hbeta_4_2',    'Halpha_3_2']
        self.posHydrogen_Lines      = ['H1_4102A',      'H1_4340A',     'H1_4861A',     'H1_6563A']
        self.Hydrogen_Wavelengths   = [4101.742,        4340.471,       4862.683,        6562.819]
        
        self.posHelium_Lines        = ['He1_3889A',  'He1_4026A',    'He1_4387A',    'He1_4471A',    'He1_4686A',    'He1_4714A',    'He1_4922A',   'He1_5876A',    'He1_6678A',   'He1_7065A',    'He1_7281A',      'He1_10830A']     
        self.Helium_Wavelengths     = [3889.0,        4026.0,         4387.0,         4471.0,         4686.0,         4714.0,         4922.0,         5876.0,         6678.0,         7065.0,         7281.0,         10830.0]
        
        self.Cand_Hydrogen_Lines    = []
        self.Cand_Helium_Lines      = []
        
        self.nHydrogen              = None
        self.nHelium                = None
    
        #Define indexes and labels to speed up the code               
        self.HBeta_label            = 'H1_4861A'
        self.He3889_label           = 'He1_3889A'
        self.He3889blended_label    = 'He1_3889A_blended'
        self.He3889_check           = None
        
        #Declare pyneb Hydrogen and Helium atoms to calculate emissivities
        self.H1                     = RecAtom('H', 1)
        self.He1                    = RecAtom('He', 1) 
        
        #Import collisional coefficients table
        self.Coef_Kalpha_dict       = self.Import_Coll_Coeff_Table(self.posHydrogen_Lines, None)

        #Import Optical depth function
        self.Coef_ftau_dict         = self.Import_OpticalDepth_Coeff_Table(self.posHelium_Lines) 
               
        #Declare dictionaries to store the data
        #WARNING: In this analysis flambda is mantained constant
        self.Flux_dict              = OrderedDict()
        self.Error_dict             = OrderedDict()
        self.Wave_dict              = OrderedDict()
        self.PynebCode_dict         = OrderedDict()
        self.EqW_dict               = OrderedDict()
        self.EqWerror_dict          = OrderedDict()
        self.hlambda_dict           = OrderedDict()
        self.flambda_dict           = self.get_flambda_dict(self.posHydrogen_Lines + self.posHelium_Lines, self.Hydrogen_Wavelengths + self.Helium_Wavelengths)
        
        #Extra
        self.EmptyRowFormat         = 'nan'            
            
    def Import_TableData(self, Address, Columns):
        
        Imported_Array  = genfromtxt(Address, dtype=float, usecols = Columns, skiprows = 2).T
        Datarray = Imported_Array[:,~isnan(Imported_Array).all(0)]
                
        return Datarray
     
    def Import_Coll_Coeff_Table(self, HydrogenLines, HeliumLines):
        
        data_dict = OrderedDict()
                
        for i in range(len(HydrogenLines)):
            
            Line            = HydrogenLines[i]
            Data_Columns    = [0 + 3*i, 1 + 3*i, 2 + 3*i]
            data_dict[Line] = self.Import_TableData(self.Hydrogen_CollCoeff_TableAddress, Data_Columns)
                    
        return data_dict
     
    def Import_OpticalDepth_Coeff_Table(self, HeliumLines):
        
        data_dict = OrderedDict()

        for i in range(len(HeliumLines)):
            
            Line            = HeliumLines[i]
            data_dict[Line] = loadtxt(self.Helium_OpticalDepth_TableAddress, dtype = float, skiprows = 2, usecols = (i,))
            
        return data_dict
    
    def Import_Synthetic_Fluxes(self, Model = 'Model2'):

        self.SyntheticData_dict = OrderedDict()

        if Model == 'Model1':
            #self.SyntheticData_dict['He_Flux']      = array([ 0.0891384,    0.01283333,     0.03187135, 0.09890274, 0.02582588, 0.02366021])   
            #self.SyntheticData_dict['He_Flux']      = array([ 0.0891384,    0.01283333,     0.03187135, 0.09890274, 0.02582588, 0.02366021])
            self.SyntheticData_dict['H_Flux']       = array([ 0.24685935,   0.45526236,     1.0,            2.96988502])
            self.SyntheticData_dict['H_wave']       = array([4101.742,      4340.471,      4862.683,       6562.819])
            self.SyntheticData_dict['H_Ions']       = ['Hdelta_6_2',    'Hgamma_5_2',   'Hbeta_4_2',    'Halpha_3_2']
            self.SyntheticData_dict['H_labels']     = ['H1_4102A',      'H1_4340A',     'H1_4861A',     'H1_6563A']
            self.SyntheticData_dict['H_Eqw']        = [50.0,            50.0,           250,             300.0]
            self.SyntheticData_dict['H_EqwErr']     = [1.0,             1.0,            12.5,            14]
            self.SyntheticData_dict['H_hlambda']    = [1.0,             1.0,            1.0,             1.0]
            self.SyntheticData_dict['H_error']      = self.SyntheticData_dict['H_Flux'] * 0.01
            
            self.SyntheticData_dict['He_Flux']      = array([ 0.08951096,    0.01290066,     0.03201484, 0.09931435, 0.02594518, 0.02377085])   
            self.SyntheticData_dict['He_wave']      = array([ 3889.0,       4026.0,         4471.0,        5876.0,     6678.0,     7065.0])
            self.SyntheticData_dict['He_labels']    =       ['He1_3889A',   'He1_4026A',   'He1_4471A',   'He1_5876A','He1_6678A', 'He1_7065A']
            self.SyntheticData_dict['He_Eqw']       = [10.0,                10.0,           10.0,           10.0,        10.0,          10.0]
            self.SyntheticData_dict['He_EqwErr']    = [1.0,                 1.0,            1.0,            1.0,         1.0,           1.0]
            self.SyntheticData_dict['He_hlambda']   = [1.0,                 1.0,            1.0,            1.0,         1.0,           1.0] 
            self.SyntheticData_dict['He_error']     = self.SyntheticData_dict['He_Flux'] * 0.02
                        
            self.SyntheticData_dict['TOIII']        = 19000
            self.SyntheticData_dict['y_plus']       = 0.08
            self.SyntheticData_dict['n_e']          = 100.0
            self.SyntheticData_dict['a_He']         = 1.0
            self.SyntheticData_dict['tau']          = 0.2
            self.SyntheticData_dict['Te_0']         = 18000.0
            self.SyntheticData_dict['cHbeta']       = 0.1
            self.SyntheticData_dict['a_H']          = 1.0
            self.SyntheticData_dict['xi']           = 1.0

        if Model == 'Model2':
            
            #These are the ones from the version 0
            #self.SyntheticData_dict['H_Flux']       = array([ 0.24585991,  0.45343263,  2.95803687])
            #self.SyntheticData_dict['He_Flux']      = array([ 0.10059744,  0.01684244,  0.03908421,  0.12673761,  0.03538569,  0.04145339])
            #These are the ones from the version 1
            #self.SyntheticData_dict['H_Flux']       = array([0.24625485, 0.454443,      1,              2.98352834])
            #self.SyntheticData_dict['He_Flux']      = array([0.10100783,    0.01691781,     0.03924855,     0.12725256,  0.03553524,    0.04162797])
            
            self.SyntheticData_dict['H_Flux']       = array([0.24666367, 0.45494969,    1,              2.97990939])
            self.SyntheticData_dict['H_wave']       = array([4101.742,   4340.471,      4862.683,       6562.819])
            self.SyntheticData_dict['H_Ions']       = ['Hdelta_6_2',    'Hgamma_5_2',   'Hbeta_4_2',    'Halpha_3_2']
            self.SyntheticData_dict['H_labels']     = ['H1_4102A',      'H1_4340A',     'H1_4861A',     'H1_6563A']
            self.SyntheticData_dict['H_Eqw']        = [50.0,            50.0,           250,             300.0]
            self.SyntheticData_dict['H_EqwErr']     = [1.0,             1.0,            12.5,            14]
            self.SyntheticData_dict['H_hlambda']    = [1.0,             1.0,            1.0,             1.0]
            self.SyntheticData_dict['H_error']      = self.SyntheticData_dict['H_Flux'] * 0.01

            self.SyntheticData_dict['He_Flux']      = array([0.10121858,    0.01695164,     0.03928185,     0.12712208,  0.03548869,    0.0415693])
            self.SyntheticData_dict['He_wave']      = array([ 3889.0,       4026.0,         4471.0,         5876.0,      6678.0,        7065.0])
            self.SyntheticData_dict['He_labels']    = ['He1_3889A',         'He1_4026A',   'He1_4471A',   'He1_5876A',  'He1_6678A',    'He1_7065A']
            self.SyntheticData_dict['He_Eqw']       = [10.0,                10.0,           10.0,           10.0,        10.0,          10.0]
            self.SyntheticData_dict['He_EqwErr']    = [1.0,                 1.0,            1.0,            1.0,         1.0,           1.0]
            self.SyntheticData_dict['He_hlambda']   = [1.0,                 1.0,            1.0,            1.0,         1.0,           1.0] 
            self.SyntheticData_dict['He_error']     = self.SyntheticData_dict['He_Flux'] * 0.02

            self.SyntheticData_dict['TOIII']        = 17000
            self.SyntheticData_dict['y_plus']       = 0.085
            self.SyntheticData_dict['n_e']          = 500.0
            self.SyntheticData_dict['a_He']         = 0.5
            self.SyntheticData_dict['tau']          = 1.0
            self.SyntheticData_dict['Te_0']         = 16000.0
            self.SyntheticData_dict['cHbeta']       = 0.1
            self.SyntheticData_dict['a_H']          = 1.0
            self.SyntheticData_dict['xi']           = 1.0
                 
        if Model == 'Model3':
                 
            self.SyntheticData_dict['H_Flux']       = array([0.24666367, 0.45494969,    1,              2.97990939])
            self.SyntheticData_dict['H_wave']       = array([4101.742,   4340.471,      4862.683,       6562.819])
            self.SyntheticData_dict['H_Ions']       = ['Hdelta_6_2',    'Hgamma_5_2',   'Hbeta_4_2',    'Halpha_3_2']
            self.SyntheticData_dict['H_labels']     = ['H1_4102A',      'H1_4340A',     'H1_4861A',     'H1_6563A']
            self.SyntheticData_dict['H_Eqw']        = [50.0,            50.0,           250,             300.0]
            self.SyntheticData_dict['H_EqwErr']     = [1.0,             1.0,            12.5,            14]
            self.SyntheticData_dict['H_hlambda']    = [1.0,             1.0,            1.0,             1.0]
            self.SyntheticData_dict['H_error']      = self.SyntheticData_dict['H_Flux'] * 0.01

            self.SyntheticData_dict['He_Flux']      = array([0.10121858,    0.01695164,     0.03928185,     0.12712208,  0.03548869,    0.0415693,      0.76218916])
            self.SyntheticData_dict['He_wave']      = array([ 3889.0,       4026.0,         4471.0,         5876.0,      6678.0,        7065.0,         10830.0])
            self.SyntheticData_dict['He_labels']    = ['He1_3889A',         'He1_4026A',   'He1_4471A',   'He1_5876A',  'He1_6678A',    'He1_7065A',    'He1_10830A']
            self.SyntheticData_dict['He_Eqw']       = [10.0,                10.0,           10.0,           10.0,        10.0,          10.0,           10.0]
            self.SyntheticData_dict['He_EqwErr']    = [1.0,                 1.0,            1.0,            1.0,         1.0,           1.0,            1.0]
            self.SyntheticData_dict['He_hlambda']   = [1.0,                 1.0,            1.0,            1.0,         1.0,           1.0,            1.0] 
            self.SyntheticData_dict['He_error']     = self.SyntheticData_dict['He_Flux'] * 0.02

            self.SyntheticData_dict['TOIII']        = 17000
            self.SyntheticData_dict['y_plus']       = 0.085
            self.SyntheticData_dict['n_e']          = 500.0
            self.SyntheticData_dict['a_He']         = 0.5
            self.SyntheticData_dict['tau']          = 1.0
            self.SyntheticData_dict['Te_0']         = 16000.0
            self.SyntheticData_dict['cHbeta']       = 0.1
            self.SyntheticData_dict['a_H']          = 1.0
            self.SyntheticData_dict['xi']           = 1.0  
  
                                   
        return
    
    def Calculate_Synthetic_Fluxes(self, model):
        
        self.Import_Synthetic_Fluxes(Model = model)
        
        self.Check_EmissionLinesObserved(self.SyntheticData_dict)
        
        self.Preload_Data(Hbeta_Normalized=True, Deblend_Check=False)
        
        Hydrogen_Dict   = self.Calculate_H_Parameters_Vectors(self.SyntheticData_dict['Te_0'], self.SyntheticData_dict['n_e'], self.SyntheticData_dict['tau'])
        Helium_Dict     = self.Calculate_He_Parameters_Vectors(self.SyntheticData_dict['Te_0'], self.SyntheticData_dict['n_e'], self.SyntheticData_dict['tau'])
    
    
    
    
        H_Flux          = self.H_Flux_theo(self.SyntheticData_dict['xi'], self.SyntheticData_dict['cHbeta'], self.SyntheticData_dict['a_H'], Hydrogen_Dict)
        He_Flux         = self.He_Flux_theo_nof(self.SyntheticData_dict['xi'], self.SyntheticData_dict['cHbeta'], self.SyntheticData_dict['a_H'], self.SyntheticData_dict['a_He'], self.SyntheticData_dict['y_plus'], Helium_Dict)
    
        print 'Hydrogen fluxes', H_Flux
        print 'Helium fluxes', He_Flux
    
        return
    
    def Import_Object_Data(self, Filefolder, CodeName, Lineslog_Extension):
        
        self.ObjectData_dict = OrderedDict()
            
        String_Columns      = [self.Labels_ColumnHeader, self.Ion_ColumnHeader]
        Float_Columns       = [self.Wavelength_ColumnHeader, self.GaussianFlux_ColumnHeader, self.GaussianError_ColumnHeader, self.Line_Continuum_ColumnHeader, self.EqW_ColumnHeader, self.EqW_error_ColumnHeader]
        
        Lineslog_Address    = Filefolder + CodeName + Lineslog_Extension
        
        Labels, Ions                                                = self.get_ColumnData(String_Columns, Lineslog_Address, HeaderSize = 2, StringIndexes = True, datatype = str, unpack_check = True) 
        Wavelengths, Fluxes, Fluxes_error, h_lambda, Eqw, Eqw_error = self.get_ColumnData(Float_Columns, Lineslog_Address, HeaderSize = 2, StringIndexes = True, unpack_check = True)

        self.ObjectData_dict['H_labels']        = list(Labels)
        self.ObjectData_dict['H_Ions']          = list(Ions)
        self.ObjectData_dict['H_Flux']          = Fluxes
        self.ObjectData_dict['H_error']         = Fluxes_error
        self.ObjectData_dict['H_wave']          = Wavelengths
        self.ObjectData_dict['H_Eqw']           = Eqw
        self.ObjectData_dict['H_EqwErr']        = Eqw_error
        self.ObjectData_dict['H_hlambda']        = h_lambda
        
        self.ObjectData_dict['He_labels']       = list(Labels)
        self.ObjectData_dict['He_Ions']         = list(Ions)
        self.ObjectData_dict['He_Flux']         = Fluxes
        self.ObjectData_dict['He_error']        = Fluxes_error
        self.ObjectData_dict['He_wave']         = Wavelengths
        self.ObjectData_dict['He_Eqw']          = Eqw
        self.ObjectData_dict['He_EqwErr']       = Eqw_error
        self.ObjectData_dict['He_hlambda']      = h_lambda
        
        #TOIII calculated from TSIII, if not we use TOIII, if not we use 17000
        TOIII_from_TSIII                        = self.GetParameter_ObjLog(CodeName, Filefolder, Parameter = 'TOIII_approx_TSIII', Assumption = 'float')
        TOIII                                   = self.GetParameter_ObjLog(CodeName, Filefolder, Parameter = 'TOIII', Assumption = 'float')
        
        if TOIII_from_TSIII != None:
            self.ObjectData_dict['TOIII']   = TOIII_from_TSIII
        elif TOIII != None:
            self.ObjectData_dict['TOIII']   = TOIII
        else: 
            self.ObjectData_dict['TOIII']   = 15000.0
        
        #nSII density to be used in the priors definition. If it could not be calculated the output value is 100
        self.ObjectData_dict['nSII']        = self.GetParameter_ObjLog(CodeName, Filefolder, Parameter = 'nSII', Assumption = 'Min_Den')
        
        self.ObjectData_dict['cHbeta_obs']  = self.GetParameter_ObjLog(CodeName, Filefolder, Parameter = 'cHBeta', Assumption = 'cHbeta_min')
        
        return
    
    def Check_EmissionLinesObserved(self, Data_Dict):
        
        #Empty the lists of candidate lines for Hydrogen and Helium
        del self.Cand_Hydrogen_Lines[:]
        del self.Cand_Helium_Lines[:]
                
        #Loop through the hydrogen lines to store the properties of those we can use to perform the analysis
        Obs_HydrogenLabels                                  = Data_Dict['H_labels']
        
        for i in range(len(self.posHydrogen_Lines)):
            Line_Label                                      = self.posHydrogen_Lines[i]
            if Line_Label in Obs_HydrogenLabels:
                Line_Index                                  = Obs_HydrogenLabels.index(Line_Label)
                self.Flux_dict[Line_Label]                  = Data_Dict['H_Flux'][Line_Index]   
                self.Error_dict[Line_Label]                 = Data_Dict['H_error'][Line_Index]
                self.Wave_dict[Line_Label]                  = Data_Dict['H_wave'][Line_Index]
                self.EqW_dict[Line_Label]                   = Data_Dict['H_Eqw'][Line_Index]
                self.EqWerror_dict[Line_Label]              = Data_Dict['H_EqwErr'][Line_Index]
                self.hlambda_dict[Line_Label]               = Data_Dict['H_hlambda'][Line_Index]
                self.PynebCode_dict[Line_Label]             = Data_Dict['H_Ions'][Line_Index][Data_Dict['H_Ions'][Line_Index].find('_')+1:len(Data_Dict['H_Ions'][Line_Index])]
                self.Cand_Hydrogen_Lines.append(Line_Label)
                                
        #Loop through the helium lines to store the properties of those we can use to perform the analysis
        Obs_HeliumLabels                                    = Data_Dict['He_labels']
        for i in range(len(self.posHelium_Lines)):
            Line_Label                                      = self.posHelium_Lines[i]
            if Line_Label in Obs_HeliumLabels:
                Line_Index                                  = Obs_HeliumLabels.index(Line_Label)
                self.Flux_dict[Line_Label]                  = Data_Dict['He_Flux'][Line_Index]   
                self.Error_dict[Line_Label]                 = Data_Dict['He_error'][Line_Index]
                self.Wave_dict[Line_Label]                  = Data_Dict['He_wave'][Line_Index]
                self.EqW_dict[Line_Label]                   = Data_Dict['He_Eqw'][Line_Index]
                self.EqWerror_dict[Line_Label]              = Data_Dict['He_EqwErr'][Line_Index]
                self.hlambda_dict[Line_Label]               = Data_Dict['He_hlambda'][Line_Index]
                self.PynebCode_dict[Line_Label]             = Line_Label[Line_Label.find('_')+1:-1]+'.0'
                self.Cand_Helium_Lines.append(Line_Label)
        
        print 'Hydrogen lines'
        print self.Cand_Hydrogen_Lines
        print 'Helium lines'
        print self.Cand_Helium_Lines
        
        #Since the Hbeta line is not used for the fitting we remove it from the candidates lines list. However, its properties are still stored in the dictionaries
        self.Cand_Hydrogen_Lines.remove(self.HBeta_label)
        
        #Since the He_3889A line is blended we add new key He_3889A_blended which will be store the observed, blended, value
        if self.He3889_label in self.Cand_Helium_Lines:
            self.Flux_dict[self.He3889blended_label]        = self.Flux_dict[self.He3889_label]
            self.He3889_check = True
        else:
            self.He3889_check = False
        
        #Define number of lines variables to speed up the calculation
        self.nHydrogen                                      = len(self.Cand_Hydrogen_Lines)
        self.nHelium                                        = len(self.Cand_Helium_Lines)
        
        self.nHydrogen_range                                = range(self.nHydrogen)
        self.nHelium_range                                  = range(self.nHelium)
                
        #Oxygen temperature prior
        self.TOIIIprior                                     = Data_Dict['TOIII']
        self.TOIIIprior_sigma                               = self.TOIIIprior * 0.2
        
    def Preload_Data(self, Hbeta_Normalized = True, Deblend_Check = True):

        #Define the vectors where we store the physical parameters
        self.Flux_H_vector                          = zeros(self.nHydrogen)
        self.Error_H_vector                         = zeros(self.nHydrogen)
        self.Emissivity_H_vector                    = zeros(self.nHydrogen)
        self.Kalpha_vector                          = zeros(self.nHydrogen)
        self.flambda_H_vector                       = zeros(self.nHydrogen)
        #self.Eqw_H_vector                          = zeros(self.nHydrogen)
        #self.EqwError_H_vector                     = zeros(self.nHydrogen)
        self.hlambda_H_vector                       = ones(self.nHydrogen)

        self.Flux_He_vector                         = zeros(self.nHelium)
        self.Error_He_vector                        = zeros(self.nHelium)
        self.Emissivity_He_vector                   = zeros(self.nHelium)
        self.ftau_He_vector                         = zeros(self.nHelium)
        self.flambda_He_vector                      = zeros(self.nHelium)
        #self.Eqw_He_vector                         = zeros(self.nHelium)
        #self.EqwError_He_vector                    = zeros(self.nHelium)
        self.hlambda_He_vector                      = ones(self.nHelium)
      
        #Define HBeta values in advance
        self.Hbeta_Flux                             = self.Flux_dict[self.HBeta_label]
        self.Hbeta_error                            = self.Error_dict[self.HBeta_label]
        self.Hbeta_EW                               = self.EqW_dict[self.HBeta_label]
        self.Hbeta_EWerror                          = self.EqWerror_dict[self.HBeta_label]      
        self.hbeta_hlambda                          = self.hlambda_dict[self.HBeta_label]
      
        #Calculate in advance observed physical parameters vectors for Hydrogen lines
        for i in range(self.nHydrogen):
            Line_Label                              = self.Cand_Hydrogen_Lines[i]        
            self.Flux_H_vector[i]                   = self.Flux_dict[Line_Label]
            self.Error_H_vector[i]                  = self.Error_dict[Line_Label]
            self.hlambda_H_vector[i]                = self.hlambda_dict[Line_Label]
            self.flambda_H_vector[i]                = self.flambda_dict[Line_Label]

        for i in range(self.nHelium):
            Line_Label                              = self.Cand_Helium_Lines[i]
            self.Flux_He_vector[i]                  = self.Flux_dict[Line_Label]
            self.Error_He_vector[i]                 = self.Error_dict[Line_Label]
            self.flambda_He_vector[i]               = self.flambda_dict[Line_Label]
            self.hlambda_He_vector[i]               = self.hlambda_dict[Line_Label]             

        #Combine Hydrogen and Helium values into a single vector
        if Hbeta_Normalized: 
            self.H_He_Obs_Flux                      = concatenate([self.Flux_H_vector, self.Flux_He_vector])
            self.H_He_Obs_Error                     = concatenate([self.Error_H_vector, self.Error_He_vector])

        else:
            self.H_He_Obs_Flux                      = concatenate([self.Flux_H_vector, self.Flux_He_vector])    / self.Hbeta_Flux
            self.H_He_Obs_Error                     = concatenate([self.Error_H_vector, self.Error_He_vector])  / self.Hbeta_Flux
        
        #Getting the index for the He1_3889A line in advance
        if (self.He3889_label in self.Cand_Helium_Lines) and (Deblend_Check == True):
            self.He3889_index = where(self.H_He_Obs_Flux == self.Flux_dict[self.He3889blended_label] / self.Hbeta_Flux)[0][0]
            self.Deblend_He3889A_line(a_H = 1.0, T_4 = self.ObjectData_dict['TOIII'] / 10000, cHbeta = self.ObjectData_dict['cHbeta_obs'])
        
        #Dictionary with the vectors
        self.Data_Dict = {'Hbeta_Kalpha'    : None, 
                     'Hbeta_emis'           : None,
                     'Emissivity_H_vector'  : None,
                     'Kalpha_vector'        : None,
                     'Emissivity_He_vector' : None,
                     'ftau_He_vector'       : None,
                     'T_4'                  : None} 
        
    def Calculate_H_Parameters_Vectors(self, T_e, n_e, tau):    
        
        #Calculate in advance the T_4 parameter
        self.Data_Dict['T_4'] = T_e / 10000.0
        
        #Calculate the hbeta parameters
        self.Data_Dict['Hbeta_Kalpha']              = self.Kalpha_Ratio_H(T_4 = self.Data_Dict['T_4'], H_label=self.HBeta_label)
        self.Data_Dict['Hbeta_emis']                = self.H1.getEmissivity(T_e, n_e, label = self.PynebCode_dict[self.HBeta_label])

        #Calculate physical parameters for Hydrogen lines
        for i in self.nHydrogen_range:
            self.Emissivity_H_vector[i]             = self.H1.getEmissivity(T_e, n_e, label = self.PynebCode_dict[self.Cand_Hydrogen_Lines[i]])
            self.Kalpha_vector[i]                   = self.Kalpha_Ratio_H(T_4 = self.Data_Dict['T_4'], H_label=self.Cand_Hydrogen_Lines[i])
        
        self.Data_Dict['Emissivity_H_vector']       = self.Emissivity_H_vector
        self.Data_Dict['Kalpha_vector']             = self.Kalpha_vector
                
        return self.Data_Dict    
    
    def Calculate_He_Parameters_Vectors(self, T_e, n_e, tau):
    
        #Calculate physical parameters for Helium lines
        for i in self.nHelium_range:
            self.Emissivity_He_vector[i]            = self.He1.getEmissivity(T_e, n_e, label = self.PynebCode_dict[self.Cand_Helium_Lines[i]])
            self.ftau_He_vector[i]                  = self.OpticalDepth_He(tau = tau, T_4 = self.Data_Dict['T_4'], n_e = n_e, He_label = self.Cand_Helium_Lines[i])    
        
        self.Data_Dict['Emissivity_He_vector']      = self.Emissivity_He_vector
        self.Data_Dict['ftau_He_vector']            = self.ftau_He_vector
        
        return self.Data_Dict

    def H_Flux_theo(self, xi, cHbeta, a_H, data_dict):
                
        #Calculate the emissivities for each of the lines for the given temperature and density
        Emissivities_module = data_dict['Emissivity_H_vector'] / data_dict['Hbeta_emis'] 
                
        #Calculate the Collisional excitation fraction
        CR_Module           = (1.0 + 0.0001* xi *data_dict['Kalpha_vector']) / (1.0 + 0.0001* xi * data_dict['Hbeta_Kalpha'] )
                
        #Calculate the reddening component
        f_module            = power(10, -1 * self.flambda_H_vector * cHbeta)
          
        #Calculate the Hbeta normalization module
        EW_Hbeta_module     = (self.Hbeta_EW + a_H) / self.Hbeta_EW
        
        #Calculate stellar absorption module
        a_H_module          = (a_H * self.hlambda_H_vector) / (self.Hbeta_EW * self.hbeta_hlambda)
        
        #Calculate theoretical Hydrogen flux for each emission line
        H_Flux              = Emissivities_module * CR_Module * f_module * EW_Hbeta_module - a_H_module
                     
        return H_Flux

    def He_Flux_theo_nof(self, xi, cHbeta, a_H, a_He, y_plus, data_dict):
                      
        #Calculate the emissivities for each of the lines for the given temperature and density
        Emissivities_module = data_dict['Emissivity_He_vector'] / data_dict['Hbeta_emis']
                
        #Calculate the collisional excitation fraction
        CR_Module           = 1 / (1.0 + 0.0001* xi * data_dict['Hbeta_Kalpha'])

        #Calculate the reddening component
        f_module            = power(10, -1 * self.flambda_He_vector * cHbeta)

        #Calculate the Hbeta normalization module
        EW_Hbeta_module     = (self.Hbeta_EW + a_H) / self.Hbeta_EW
        
        #Calculate stellar absorption module
        a_He_module         = (a_He * self.hlambda_He_vector) / (self.Hbeta_EW * self.hbeta_hlambda)
             
        #Calculate theoretical Hydrogen flux for each emission line
        He_Flux             = y_plus * Emissivities_module * data_dict['ftau_He_vector'] * CR_Module * f_module * EW_Hbeta_module - a_He_module

#         if self.He3889_check:
#             self.Deblend_He3889A_line(a_H, data_dict['T_4'], cHbeta)

        return He_Flux
               
    def get_flambda_dict(self, lines_labels, lines_wavelengths, R_v=3.2):
    
        x_true          = 1.0 / (array(lines_wavelengths) / 10000.0)
        y               = x_true - 1.82
    
        y_coeffs        = array([ones(len(y)), y, power(y, 2), power(y, 3), power(y, 4), power(y, 5), power(y, 6), power(y, 7)])
        a_coeffs        = array([1, 0.17699,    -0.50447,   -0.02427,   0.72085,    0.01979,    -0.77530,   0.32999])
        b_coeffs        = array([0, 1.41338,    2.28305,   1.07233,   -5.38434,    -0.62251,    5.30260,   -2.09002])
        
        a_x             = dot(a_coeffs,y_coeffs)
        b_x             = dot(b_coeffs,y_coeffs)
        
        X_x             = a_x + b_x / R_v
        
        y_beta          = (1 / (4862.683 / 10000)) - 1.82
        y_beta_coeffs   = array([1, y_beta, power(y_beta, 2), power(y_beta, 3), power(y_beta, 4), power(y_beta, 5), power(y_beta, 6), power(y_beta, 7)])
        
        X_x_beta        = dot(a_coeffs,y_beta_coeffs) + dot(b_coeffs,y_beta_coeffs) / R_v
    
        f               = X_x / X_x_beta - 1
        
        return dict(zip(lines_labels , f))
         
    def Kalpha_Ratio_H(self, T_4, H_label):
                
        K_alpha_Ratio   = sum(self.Coef_Kalpha_dict[H_label][0] * exp(self.Coef_Kalpha_dict[H_label][1] / T_4) * power(T_4, self.Coef_Kalpha_dict[H_label][2]))
        
        return K_alpha_Ratio
    
    def OpticalDepth_He(self, tau, T_4, n_e, He_label):
                        
        f_tau   = 1 + (tau/2) * (self.Coef_ftau_dict[He_label][0] + (self.Coef_ftau_dict[He_label][1] + self.Coef_ftau_dict[He_label][2]*n_e + self.Coef_ftau_dict[He_label][3]*n_e*n_e) * T_4)

        return f_tau
    
    def Deblend_He3889A_line(self, a_H, T_4, cHbeta):
        
        self.H_He_Obs_Flux[self.He3889_index] = (self.Flux_dict[self.He3889blended_label] / self.Flux_dict[self.HBeta_label]) * ((self.EqW_dict[self.He3889_label] + a_H) / self.EqW_dict[self.He3889_label]) - (0.104 * power(T_4, 0.046)) * (power(10 ,-self.flambda_dict[self.He3889_label] * cHbeta))  
        
        return self.H_He_Obs_Flux     
class He_Inference_Abundance:
    def __init__(self):

        # Declare Hydrogen and Helium collisional lines for the analysis
        self.Hydrogen_Lines = ["Hdelta_6_2", "Hgamma_5_2", "Hbeta_4_2", "Halpha_3_2"]
        self.Hydrogen_Labels = ["6_2", "5_2", "4_2", "3_2"]
        self.Hydrogen_Wavelengths = [4101.742, 4340.471, 4862.683, 6562.819]

        self.Helium_Lines = ["He1_3889", "He1_4026.0", "He1_4471.0", "He1_5876.0", "He1_6678.0", "He1_7065.0"]
        self.Helium_Labels = ["3889.0", "4026.0", "4471.0", "5876.0", "6678.0", "7065.0"]
        self.Helium_Wavelengths = [3889.0, 4026.0, 4471.0, 5876.0, 6678.0, 7065.0]

        # Define indexes and labels to speed up the code
        self.HBeta_label = "4_2"
        self.HBeta_Index = self.Hydrogen_Lines.index("Hbeta_4_2")
        self.nHydrogen = range(len(self.Hydrogen_Lines))
        self.nHelium = range(len(self.Helium_Lines))

        # THIS TRICK IS NECCESARY SO THAT WE DO NOT INCLUDE THE HBETA LINE IN THE CALCULATION
        self.nHydrogen.remove(self.HBeta_Index)
        Valid_H_Lines = list(self.Hydrogen_Wavelengths)
        del Valid_H_Lines[self.HBeta_Index]

        # Declare pyneb Hydrogen and Helium atoms to calculate emissivities
        self.H1 = RecAtom("H", 1)
        self.He1 = RecAtom("He", 1)
        self.H_emissivity_Vector = zeros(len(self.nHydrogen))  # Array to store the emissivities for each of the labels
        self.He_emissivity_Vector = zeros(
            len(self.Helium_Labels)
        )  # Array to store the emissivities for each of the labels

        # Import collisional coefficients table
        self.H_CollCoeff_Matrix = self.Import_Coll_Coeff_Table("H")
        self.He_CollCoeff_Matrix = self.Import_Coll_Coeff_Table("He")
        self.H_CRratio_Vector = zeros(len(self.nHydrogen))  # Array to store the C/R for each of the HydrogenLines
        self.He_CRratio_Vector = zeros(len(self.Helium_Labels))  # Array to store the C/R for each of the HydrogenLines

        # Import Optical depth function for He lines
        self.He_OpticalDepth_Matrix = self.Import_OpticalDepth_Coeff_Table("He")
        self.f_Hetau_vector = zeros(len(self.Helium_Labels))

        # Calculate f_lambda in advance law configuration (from Cardelli, Clayton and Mathis law)
        self.R_v = 3.1
        self.a_coeffs = array([1.0, 0.17699, -0.50447, -0.02427, 0.72085, 0.01979, -0.77530, 0.32999])
        self.b_coeffs = array([0.0, 1.41338, 2.28305, 1.07233, -5.38434, -0.62251, 5.30260, -2.09002])

        self.f_H_vector = self.get_flambda_vector(array(Valid_H_Lines))
        self.f_He_vector = self.get_flambda_vector(array(self.Helium_Wavelengths))

        # Extra
        self.EmptyRowFormat = "nan"

    def Import_TableData(self, Address, Columns):

        Imported_Array = genfromtxt(Address, dtype=float, usecols=Columns, skiprows=2).T
        Datarray = Imported_Array[:, ~isnan(Imported_Array).all(0)]

        return Datarray

    def Import_Coll_Coeff_Table(self, Atom):

        if Atom == "H":
            # Default Hydrogen table address
            Hydrogen_CollCoeff_TableAddress = (
                "/home/vital/Workspace/Dazer/Astro_Libraries/Neutral_Hydrogen_Collisional_Correction_coef.txt"
            )

            # Empty container for the coefficient matrix
            H_Matrix = [0] * len(self.Hydrogen_Labels)

            # The Columns are stored from lower to higher wavelength values in the for of coefficients a, b, c
            for i in range(len(self.Hydrogen_Labels)):

                Data_Columns = [0 + 3 * i, 1 + 3 * i, 2 + 3 * i]

                H_Matrix[i] = self.Import_TableData(Hydrogen_CollCoeff_TableAddress, Data_Columns)

            return H_Matrix

        if Atom == "He":
            # Default Helium table address
            Helium_CollCoeff_TableAddress = (
                "/home/vital/Workspace/Dazer/Astro_Libraries/Neutral_Helium_Collisional_Correction_coef.txt"
            )

            # Empty container for the coefficient matrix
            He_Matrix = [0] * len(self.Helium_Labels)

            # The Columns are stored from lower to higher wavelength values in the for of coefficients a, b, c
            for i in range(len(self.Helium_Labels)):

                Data_Columns = [0 + 3 * i, 1 + 3 * i, 2 + 3 * i]

                He_Matrix[i] = self.Import_TableData(Helium_CollCoeff_TableAddress, Data_Columns)

            return He_Matrix

    def Import_OpticalDepth_Coeff_Table(self, Atom):

        if Atom == "He":
            # Default Helium table address
            Helium_OpticalDepth_TableAddress = (
                "/home/vital/Workspace/Dazer/Astro_Libraries/Helium_OpticalDepthFunction_Coefficients.txt"
            )

            # Empty container for the coefficient matrix
            He_Matrix_f_tauCoeffs = [0] * len(self.Helium_Labels)

            for i in range(len(self.Helium_Labels)):
                He_Matrix_f_tauCoeffs[i] = loadtxt(
                    Helium_OpticalDepth_TableAddress, dtype=float, skiprows=2, usecols=(i,)
                )

            return He_Matrix_f_tauCoeffs

    def Import_Synthetic_Fluxes(self, case="case1"):
        # Old ones
        #        H_Flux_0    = array([0.24585991, 0.45343263, 2.95803687])
        #        He_Flux_0   = array([ 0.08913865,  0.01283334,  0.0318714,   0.09890309,  0.02582589,  0.02366051])
        if case == "case1":

            H_Flux_0 = array([0.24585991, 0.45343263, 2.95803687])
            He_Flux_0 = array([0.0891384, 0.01283333, 0.03187135, 0.09890274, 0.02582588, 0.02366021])

        if case == "case2":

            H_Flux_0 = array([0.24585991, 0.45343263, 2.95803687])
            He_Flux_0 = array([0.10059744, 0.01684244, 0.03908421, 0.12673761, 0.03538569, 0.04145339])

        return H_Flux_0, He_Flux_0

    def H_Flux_theo(self, T_e, n_e, xi, cHbeta, a_H, h_Hlambda, a_Hbeta, h_Hbeta, EW_Hbeta):

        # Calculate the emissivities for each of the lines for the given temperature and density
        self.get_H_EmissivityVector(T_e, n_e)
        E_Hbeta = self.H1.getEmissivity(T_e, n_e, label=self.HBeta_label)
        Emissivities_module = self.H_emissivity_Vector / E_Hbeta

        # Calculate the Collisional excitation fraction
        self.get_H_CRratio_Vector(T_e)
        CR_Hbeta = self.H_Kalpha_Ratio(self.HBeta_Index, T_e)
        CR_Module = (1.0 + 0.0001 * xi * self.H_CRratio_Vector) / (1.0 + 0.0001 * xi * CR_Hbeta)

        # Calculate the reddening component
        f_module = power(10, -1 * self.f_H_vector * cHbeta)

        # Calculate the Hbeta normalization module
        EW_Hbeta_module = (EW_Hbeta + a_H) / EW_Hbeta

        # Calculate stellar absorption module
        a_H_module = (a_H * h_Hlambda) / (EW_Hbeta * h_Hbeta)

        # Calculate theoretical Hydrogen flux for each emission line
        H_Flux = Emissivities_module * CR_Module * f_module * EW_Hbeta_module - a_H_module

        #         print 'Emissivity ratio',   self.H_emissivity_Vector[-1] / E_Hbeta
        #         print 'C_R_Module',         CR_Module[-1]
        #         print 'H_CRratio_Vector',   self.H_CRratio_Vector
        #         print 'CR_Hbeta',           CR_Hbeta
        #         print 'f_lambda', self.f_H_vector
        #         print 'f_lambda module',    f_module
        return H_Flux

    def He_Flux_theo(self, T_e, n_e, xi, cHbeta, a_H, a_He, h_Helambda, a_Hbeta, h_Hbeta, EW_Hbeta, y_plus, tau):

        # Calculate the optical depth correction factor
        self.get_He_ftau_vector(T_e, n_e, tau)

        # Calculate the emissivities for each of the lines for the given temperature and density
        self.get_He_Emissivity_Vector(T_e, n_e)
        E_Hbeta = self.H1.getEmissivity(T_e, n_e, label=self.HBeta_label)
        Emissivities_module = self.He_emissivity_Vector / E_Hbeta

        # Calculate the collisional excitation fraction
        self.get_He_CRratio_Vector(T_e, n_e)
        CR_Hbeta = self.H_Kalpha_Ratio(self.HBeta_Index, T_e)
        CR_Module = (1.0 + 0.0001 * xi * self.He_CRratio_Vector) / (1.0 + 0.0001 * xi * CR_Hbeta)

        # Calculate the reddening component
        f_module = power(10, -1 * self.f_He_vector * cHbeta)

        # Calculate the Hbeta normalization module
        EW_Hbeta_module = (EW_Hbeta + a_H) / EW_Hbeta

        # Calculate stellar absorption module
        a_H_module = (a_He * h_Helambda) / (EW_Hbeta * h_Hbeta)

        He_Flux = (
            y_plus * self.f_Hetau_vector * Emissivities_module * CR_Module * f_module * EW_Hbeta_module - a_H_module
        )

        return He_Flux

    def He_Flux_theo_nof(self, T_e, n_e, xi, cHbeta, a_He, h_Helambda, a_Hbeta, h_Hbeta, EW_Hbeta, y_plus, tau):

        # Calculate the optical depth correction factor
        self.get_He_ftau_vector(T_e, n_e, tau)

        # Calculate the emissivities for each of the lines for the given temperature and density
        self.get_He_Emissivity_Vector(T_e, n_e)
        E_Hbeta = self.H1.getEmissivity(T_e, n_e, label=self.HBeta_label)
        Emissivities_module = self.He_emissivity_Vector / E_Hbeta

        # Calculate the collisional excitation fraction
        CR_Hbeta = self.H_Kalpha_Ratio(self.HBeta_Index, T_e)
        CR_Module = 1 / (1.0 + 0.0001 * xi * CR_Hbeta)

        # Calculate the reddening component
        f_module = power(10, -1 * self.f_He_vector * cHbeta)

        # Calculate the Hbeta normalization module
        EW_Hbeta_module = (EW_Hbeta + a_Hbeta) / EW_Hbeta

        # Calculate stellar absorption module
        a_H_module = (a_He * h_Helambda) / (EW_Hbeta * h_Hbeta)

        He_Flux = (
            y_plus * self.f_Hetau_vector * Emissivities_module * CR_Module * f_module * EW_Hbeta_module - a_H_module
        )

        return He_Flux

    def get_H_EmissivityVector(self, T_e, n_e):
        # WARNING: SHOULD WE CREATE ANOTHER LIST TO IMPROVE THIS?
        for i in range(len(self.nHydrogen)):
            self.H_emissivity_Vector[i] = self.H1.getEmissivity(T_e, n_e, label=self.Hydrogen_Labels[self.nHydrogen[i]])

    def get_He_Emissivity_Vector(self, T_e, n_e):
        for i in self.nHelium:
            self.He_emissivity_Vector[i] = self.He1.getEmissivity(T_e, n_e, label=self.Helium_Labels[i])

    def get_H_CRratio_Vector(self, T_e):

        T_4 = T_e / 10000.0

        # WARNING: SHOULD WE CREATE ANOTHER LIST TO IMPROVE THIS?
        for i in range(len(self.nHydrogen)):

            self.nHydrogen[i]
            self.H_CRratio_Vector[i] = sum(
                self.H_CollCoeff_Matrix[self.nHydrogen[i]][0]
                * exp(self.H_CollCoeff_Matrix[self.nHydrogen[i]][1] / T_4)
                * power(T_4, self.H_CollCoeff_Matrix[self.nHydrogen[i]][2])
            )

    def get_He_CRratio_Vector(self, T_e, n_e):

        T_4 = T_e / 10000.0
        for i in self.nHelium:
            self.He_CRratio_Vector[i] = (
                1
                / (1 + (3552 * power(T_4, -0.55) / n_e))
                * sum(
                    self.He_CollCoeff_Matrix[i][0]
                    * power(T_4, self.He_CollCoeff_Matrix[i][1])
                    * exp(self.He_CollCoeff_Matrix[i][2] / T_4)
                )
            )

    def get_He_ftau_vector(self, T_e, n_e, tau):

        T_4 = T_e / 10000.0

        for i in self.nHelium:
            self.f_Hetau_vector[i] = 1 + (tau / 2) * (
                self.He_OpticalDepth_Matrix[i][0]
                + (
                    self.He_OpticalDepth_Matrix[i][1]
                    + self.He_OpticalDepth_Matrix[i][2] * n_e
                    + self.He_OpticalDepth_Matrix[i][3] * n_e * n_e
                )
                * T_4
            )

    def get_flambda_vector(self, wavelengths, R_v=3.1):

        x_true = 1.0 / (wavelengths / 10000.0)
        y = x_true - 1.82

        y_coeffs = array(
            [ones(len(y)), y, power(y, 2), power(y, 3), power(y, 4), power(y, 5), power(y, 6), power(y, 7)]
        )
        a_coeffs = array([1, 0.17699, -0.50447, -0.02427, 0.72085, 0.01979, -0.77530, 0.32999])
        b_coeffs = array([0, 1.41338, 2.28305, 1.07233, -5.38434, -0.62251, 5.30260, -2.09002])

        a_x = dot(a_coeffs, y_coeffs)
        b_x = dot(b_coeffs, y_coeffs)

        X_x = a_x + b_x / R_v

        y_beta = (1 / (4862.683 / 10000)) - 1.82
        y_beta_coeffs = array(
            [
                1,
                y_beta,
                power(y_beta, 2),
                power(y_beta, 3),
                power(y_beta, 4),
                power(y_beta, 5),
                power(y_beta, 6),
                power(y_beta, 7),
            ]
        )

        X_x_beta = dot(a_coeffs, y_beta_coeffs) + dot(b_coeffs, y_beta_coeffs) / R_v

        f = X_x / X_x_beta - 1

        return f

    def Hydrogen_Emissivity(self, T_e, n_e, H_label):
        # The hydrogen labels have the format : Halpha => '3_2'
        return self.H1.getEmissivity(T_e, n_e, label=H_label)

    def Helium_Emissivity(self, T_e, n_e, He_label):
        # The Helium labels have the format : He1_5876 => '5876.0'
        return self.He1.getEmissivity(tem=T_e, den=n_e, label=He_label)

    def H_Kalpha_Ratio(self, line_label, T_e):

        Coeff_Table = self.H_CollCoeff_Matrix[line_label]
        T_4 = T_e / 10000.0

        K_alpha_Ratio = sum(Coeff_Table[0] * exp(Coeff_Table[1] / T_4) * power(T_4, Coeff_Table[2]))

        return K_alpha_Ratio

    def He_CR_ratio(self, line_label, T_e, n_e):

        Coeff_Table = self.He_CollCoeff_Matrix[line_label]
        T_4 = T_e / 10000.0

        # WARNING THE ORDER OF THE COEFFIENTS ITS DIFFERENT IN THE PAPERS OF AVER 2011 AND PORTER 2004
        CR_Ratio = (
            1.0
            / (1.0 + (3552.0 * power(T_4, -0.55) / n_e))
            * sum(Coeff_Table[0] * power(T_4, Coeff_Table[1]) * exp(Coeff_Table[2] / T_4))
        )

        return CR_Ratio

    def f_value(self, wave):
        # Based on Cardelli

        x_true = 1.0 / (wave / 10000.0)
        y = x_true - 1.82

        y_coeffs = array(
            [ones(len(y)), y, power(y, 2), power(y, 3), power(y, 4), power(y, 5), power(y, 6), power(y, 7)]
        )

        a_x = dot(self.a_coeffs, y_coeffs)
        b_x = dot(self.b_coeffs, y_coeffs)

        f = a_x + b_x / self.R_v

        return f

    def He_OpticalDepth(self, tau, T_e, n_e, He_label):

        T_4 = T_e / 10000.0

        Coeff_Table = self.He_OpticalDepth_Matrix[He_label]

        f_tau = 1 + (tau / 2) * (
            Coeff_Table[0] + (Coeff_Table[1] + Coeff_Table[2] * n_e + Coeff_Table[3] * n_e * n_e) * T_4
        )

        return f_tau

    def Example_SyntheticParameters(self):

        y_plus = 0.08  # He+/H+
        n_e = 100.0  # cm^-3
        a_He = 1.0  # Angstroms...
        tau = 0.2
        Te_0 = 18000.0  # K
        cHbeta = 0.1  #
        a_H = 1.0  # Angstroms
        xi = 1.0  # Angstroms
        EW_Hbeta = 250  # Angstroms
        err_Flux_H = 0.01  # Emission Line flux percentage
        err_Flux_He = 0.02  # Emission Line flux percentage

        return y_plus, n_e, a_He, tau, Te_0, cHbeta, a_H, xi, EW_Hbeta, err_Flux_H, err_Flux_He

    def Example_SyntheticParameters2(self):

        y_plus = 0.085  # He+/H+
        n_e = 500.0  # cm^-3
        a_He = 0.5  # Angstroms...
        tau = 1.0
        Te_0 = 16000.0  # K
        cHbeta = 0.1  #
        a_H = 1.0  # Angstroms
        xi = 1.0  # Angstroms
        EW_Hbeta = 250  # Angstroms
        err_Flux_H = 0.01  # Emission Line flux percentage
        err_Flux_He = 0.02  # Emission Line flux percentage

        return y_plus, n_e, a_He, tau, Te_0, cHbeta, a_H, xi, EW_Hbeta, err_Flux_H, err_Flux_He
 def load_atom(self):
     
     #atomicData.setDataFile('h_i_rec_SH95.hdf5', 'H1', 'rec')
     self.H1_atom            =  RecAtom('H', 1)
          
     return
class ReddeningLaws(Dazer_Files):

    def __init__(self):
        
        Dazer_Files.__init__(self)
                
        self.R_v = 3.2
        self.SpectraEdges_Limit = 200 
     
#         self.Flux_Header        = 'FluxGauss'
#         self.FluxError_Header   = 'ErrorEL_MCMC'        
#         self.Wavelength_Header  = 'TheoWavelength'
     
        self.Reddening_Force    = None

        #List of hydrogen recombination lines in our EmissionLines coordinates log. WARNING: We have removed the very blended ones
        self.RecombRatios_Ions =  array(['HBal_20_2', 'HBal_19_2','HBal_18_2', 'HBal_17_2', 'HBal_16_2','HBal_15_2','HBal_12_2','HBal_11_2',
                             'HBal_9_2','Hdelta_6_2','Hgamma_5_2','Hbeta_4_2','Halpha_3_2','HPas_20_3','HPas19_3','HPas_18_3','HPas_17_3','HPas_16_3','HPas_15_3','HPas_14_3',
                             'HPas13_3','HPas12_3','HPas_11_3','HPas_10_3','HPas_9_3','HPas_8_3','HPas_7_3'])

    def load_atom(self):
        
        #atomicData.setDataFile('h_i_rec_SH95.hdf5', 'H1', 'rec')
        self.H1_atom            =  RecAtom('H', 1)
             
        return

    def RecombinationCoefficients(self, FileFolder, CodeName, DataLogExtension, lineslog_frame, Mode = 'all'):
            
        #Load electron temperature and density (if not available it will use Te = 10000K and ne = 100cm^-3)                        
        T_e = self.GetParameter_ObjLog(CodeName, FileFolder, 'TSIII', Assumption = 'Min_Temp')
        n_e = self.GetParameter_ObjLog(CodeName, FileFolder, 'nSII', Assumption = 'Min_Den')
        
        #Get the Hidrogen recombination lines that we have observed in this object
        Obs_Hindx   = lineslog_frame.index[in1d(lineslog_frame['Ion'], self.RecombRatios_Ions)]   
                    
        #Determine Hbeta properties         
        Hbeta_Emis  = self.H1_atom.getEmissivity(tem = T_e, den = n_e, label = '4_2')        
        
        #Calculate recombination coefficients and reddening curve values
        Obs_H_Emis  = zeros(len(Obs_Hindx))
        Obs_Ions    = lineslog_frame.loc[Obs_Hindx, 'Ion'].values
        
        for i in range(len(Obs_Ions)):
            TransitionCode = Obs_Ions[i][Obs_Ions[i].find('_')+1:len(Obs_Ions[i])]
            Obs_H_Emis[i]  = self.H1_atom.getEmissivity(tem = T_e, den = n_e, label = TransitionCode)        

        Theo_RecomRatio = Obs_H_Emis / Hbeta_Emis #Is this an uarray en condiciones
        
        lineslog_frame.loc[Obs_Hindx,'line_Emissivity']         = Obs_H_Emis
        lineslog_frame.loc[Obs_Hindx,'line_TheoRecombRatio']    = Theo_RecomRatio

        #Get spectrum edges
        if Mode != 'all':
            Wmin            = self.GetParameter_ObjLog(CodeName, FileFolder, 'WHT_Wmin_Blue',   Assumption='float')
            Wmax            = self.GetParameter_ObjLog(CodeName, FileFolder, 'WHT_Wmax_Red',    Assumption='float')
            Lambda_Match    = self.GetParameter_ObjLog(CodeName, FileFolder, 'Spectra_Meet',    Assumption='MatchingSpectra')
        
        #-----------All coefficients--------------------------

        if Mode == 'all':

            x_total, y_total = self.compute_allpoints(lineslog_frame, Obs_Hindx)
                        
            return x_total, y_total, list(Obs_Ions)

        #-----------Points close to spectrum edges are excluded --------------------------

        if Mode == 'boundary':

            x_inboundary, y_inboundary, Obs_Ions_inBoundary, x_outboundary, y_outboundary, Obs_Ions_outBoundary = self.compute_inBoundaryPoints(lineslog_frame, Obs_Hindx, Wmin, Wmax)

            return x_inboundary, y_inboundary, list(Obs_Ions_inBoundary), x_outboundary, y_outboundary, list(Obs_Ions_outBoundary)


        #-----------Blue spectrum coefficients --------------------------

        elif Mode == 'Blue':
            
            x_Blue, y_Blue, Obs_Blue_Ions, Blue_Normalizing_Ion = self.compute_BluePoints(lineslog_frame, Wmin, Wmax, Lambda_Match)
                        
            return x_Blue, y_Blue, Obs_Blue_Ions, Blue_Normalizing_Ion
            
        #-----------Red spectrum coefficients --------------------------

        elif Mode == 'Red':
            
            x_total_Red, y_total_Red, Obs_Red_Ions, Red_Normalizing_Ion     = self.compute_RedPoints(lineslog_frame,  Wmin, Wmax, Lambda_Match)
            
            return x_total_Red, y_total_Red, Obs_Red_Ions, Red_Normalizing_Ion

    def compare_RecombCoeffs(self, obj_data, lineslog_frame, spectral_limit = 200):
        
        #Load electron temperature and density (if not available it will use Te = 10000K and ne = 100cm^-3)                        
        T_e = obj_data.TeSIII if ~isnan(obj_data.TeSIII) else 10000.0
        n_e = obj_data.neSII if ~isnan(obj_data.neSII) else 100.0
                
        #Get the Hidrogen recombination lines that we have observed in this object
        Obs_Hindx = lineslog_frame.Ion.isin(self.RecombRatios_Ions)
                            
        #Calculate recombination coefficients and reddening curve values
        Obs_H_Emis  = empty(len(Obs_Hindx))
        Obs_Ions    = lineslog_frame.loc[Obs_Hindx, 'Ion'].values
        for i in range(len(Obs_Ions)):
            TransitionCode = Obs_Ions[i][Obs_Ions[i].find('_')+1:len(Obs_Ions[i])]
            Obs_H_Emis[i]  = self.H1_atom.getEmissivity(tem = T_e, den = n_e, label = TransitionCode)        
        
        #Normalize by Hbeta (this new constant is necessary to avoid a zero sigma)
        Hbeta_Emis = self.H1_atom.getEmissivity(tem = T_e, den = n_e, label = '4_2')        
        Fbeta_flux = ufloat(lineslog_frame.loc['H1_4861A']['line_Flux'].nominal_value, lineslog_frame.loc['H1_4861A']['line_Flux'].std_dev)
        
        #Load theoretical and observational recombination ratios to data frame
        lineslog_frame.loc[Obs_Hindx,'line_Emissivity'] = Obs_H_Emis
        lineslog_frame.loc[Obs_Hindx,'line_TheoRecombRatio'] = Obs_H_Emis / Hbeta_Emis
        lineslog_frame.loc[Obs_Hindx,'line_ObsRecombRatio'] = lineslog_frame.loc[Obs_Hindx, 'line_Flux'].values / Fbeta_flux
        
        #Get indeces of emissions in each arm
        ObsBlue_Hindx = Obs_Hindx & (lineslog_frame.lambda_theo < obj_data.join_wavelength)
        ObsRed_Hindx = Obs_Hindx & (lineslog_frame.lambda_theo > obj_data.join_wavelength)
      
        #Recalculate red arm coefficients so they are normalized by red arm line (the most intense)
        if (ObsRed_Hindx.sum()) > 0: #Can only work if there is at least one line
            idx_Redmax = lineslog_frame.loc[ObsRed_Hindx]['flux_intg'].idxmax()  #We do not use line_flux because it is a ufloat and it does not work with idxmax 
            H_Redmax_flux = lineslog_frame.loc[idx_Redmax,'line_Flux']
            H_Redmax_emis = lineslog_frame.loc[idx_Redmax,'line_Emissivity']
            Flux_Redmax = ufloat(H_Redmax_flux.nominal_value * Hbeta_Emis / H_Redmax_emis, H_Redmax_flux.std_dev * Hbeta_Emis / H_Redmax_emis)
            lineslog_frame.loc[ObsRed_Hindx,'line_ObsRecombRatio'] = lineslog_frame.loc[ObsRed_Hindx, 'line_Flux'].values / Flux_Redmax
                    
        #Load x axis values: (f_lambda - f_Hbeta) and y axis values: log(F/Fbeta)_theo - log(F/Fbeta)_obs to dataframe
        lineslog_frame.loc[Obs_Hindx,'x axis values'] = lineslog_frame.loc[Obs_Hindx, 'line_f'].values - lineslog_frame.loc['H1_4861A']['line_f']
        lineslog_frame.loc[Obs_Hindx,'y axis values'] = unum_log10(lineslog_frame.loc[Obs_Hindx,'line_TheoRecombRatio'].values) - unum_log10(lineslog_frame.loc[Obs_Hindx,'line_ObsRecombRatio'].values)
            
        #Compute all the possible configuration of points and store them
        output_dict = {}
        
        #--- All points:
        output_dict['all_x'] = lineslog_frame.loc[Obs_Hindx,'x axis values'].values
        output_dict['all_y'] = lineslog_frame.loc[Obs_Hindx,'y axis values'].values
        output_dict['all_ions'] = list(lineslog_frame.loc[Obs_Hindx,'Ion'].values)
        
        #--- By arm
        output_dict['blue_x'] = lineslog_frame.loc[ObsBlue_Hindx,'x axis values'].values
        output_dict['blue_y'] = lineslog_frame.loc[ObsBlue_Hindx,'y axis values'].values
        output_dict['blue_ions'] = list(lineslog_frame.loc[ObsBlue_Hindx,'Ion'].values)        
        output_dict['red_x'] = lineslog_frame.loc[ObsRed_Hindx,'x axis values'].values
        output_dict['red_y'] = lineslog_frame.loc[ObsRed_Hindx,'y axis values'].values
        output_dict['red_ions'] = list(lineslog_frame.loc[ObsRed_Hindx,'Ion'].values)
        
        #--- Inside limits
        if obj_data.h_gamma_valid == 'yes':
            in_idcs = Obs_Hindx
        elif obj_data.h_gamma_valid == 'no':
            wave_idx = ((lineslog_frame.lambda_theo > (obj_data.Wmin_Blue + spectral_limit)) & (lineslog_frame.lambda_theo < (obj_data.join_wavelength - spectral_limit))) \
                    | ((lineslog_frame.lambda_theo > (obj_data.join_wavelength + spectral_limit)) & (lineslog_frame.lambda_theo < (obj_data.Wmax_Red - spectral_limit)))
            in_idcs = Obs_Hindx & wave_idx
           
        output_dict['in_x'] = lineslog_frame.loc[in_idcs,'x axis values'].values
        output_dict['in_y'] = lineslog_frame.loc[in_idcs,'y axis values'].values
        output_dict['in_ions'] = list(lineslog_frame.loc[in_idcs,'Ion'].values)

        #--- Outside limis
        if obj_data.h_gamma_valid == 'no':
            wave_idx = (lineslog_frame.lambda_theo < (obj_data.Wmin_Blue + spectral_limit)) | (lineslog_frame.lambda_theo > (obj_data.Wmax_Red - spectral_limit))
            out_idcs = Obs_Hindx & wave_idx
            output_dict['out_x'] = lineslog_frame.loc[out_idcs,'x axis values'].values
            output_dict['out_y'] = lineslog_frame.loc[out_idcs,'y axis values'].values
            output_dict['out_ions'] = list(lineslog_frame.loc[out_idcs,'Ion'].values)
        else:
            output_dict['out_x'] = None
            output_dict['out_y'] = None
            output_dict['out_ions'] = None
           
        return output_dict

    def compute_allpoints(self, lineslog_frame, Obs_indeces):
        
        #Generating the unumpy array for the error propagation
        Theo_RecomRatio = lineslog_frame.loc[Obs_indeces, 'line_TheoRecombRatio'].values            
        Obs_RecombRatio = lineslog_frame.loc[Obs_indeces, 'line_Flux'].values / lineslog_frame.loc['H1_4861A']['line_Flux'] 
         
        #Generate x_true and y axis arrays for the plot
        x_total = lineslog_frame.loc[Obs_indeces, 'line_f'].values - lineslog_frame.loc['H1_4861A']['line_f']
        y_total = unum_log10(Theo_RecomRatio) - unum_log10(Obs_RecombRatio)
        
        return x_total, y_total

    def compute_inBoundaryPoints(self,  lineslog_frame, Obs_indeces, Wmin, Wmax):
        
        #Generating the unumpy array for the error propagation
        Theo_RecomRatio = lineslog_frame.loc[Obs_indeces, 'line_TheoRecombRatio'].values  
        Obs_RecombRatio = lineslog_frame.loc[Obs_indeces, 'line_Flux'].values / lineslog_frame.loc['H1_4861A']['line_Flux'] 
                
        #Generate x_true and y axis arrays for the plot
        x_total         = lineslog_frame.loc[Obs_indeces, 'line_f'].values - lineslog_frame.loc['H1_4861A']['line_f']
        y_total         = unum_log10(Theo_RecomRatio) - unum_log10(Obs_RecombRatio)

        Obs_Ions        = lineslog_frame.loc[Obs_indeces, 'Ion'].values
        Obs_Wavelength  = lineslog_frame.loc[Obs_indeces, 'TheoWavelength'].values

        #Emission lines outside the edges
        Obs_InBoundary_Indx                             = where((Obs_Wavelength > (Wmin + self.SpectraEdges_Limit)) & (Obs_Wavelength < (Wmax - self.SpectraEdges_Limit)))[0]
        x_inboundary                                    = x_total[Obs_InBoundary_Indx]
        y_inboundary                                    = y_total[Obs_InBoundary_Indx]
        Obs_Ions_inBoundary                             = Obs_Ions[Obs_InBoundary_Indx]

        #Emission lines inside the edges
        Obs_OutBoundary_Indx                            = where((Obs_Wavelength < (Wmin + self.SpectraEdges_Limit)) | (Obs_Wavelength > (Wmax - self.SpectraEdges_Limit)))[0]
        x_outboundary                                   = x_total[Obs_OutBoundary_Indx]
        y_outboundary                                   = y_total[Obs_OutBoundary_Indx]
        Obs_Ions_outBoundary                            = Obs_Ions[Obs_OutBoundary_Indx]
        
        return x_inboundary, y_inboundary, Obs_Ions_inBoundary, x_outboundary, y_outboundary, Obs_Ions_outBoundary

    def compute_BluePoints(self, lineslog_frame, Wmin, Wmax, Lambda_Match):
        
        #Wavelength limits for the blue lines
        Blue_limit      = Wmin + self.SpectraEdges_Limit
        Red_limit       = Lambda_Match - self.SpectraEdges_Limit
        BlueH_indx      = lineslog_frame.index[in1d(lineslog_frame['Ion'], self.RecombRatios_Ions) & (lineslog_frame['TheoWavelength'] > Blue_limit) & (lineslog_frame['TheoWavelength'] < Red_limit)]   
                                  
        Obs_Blue_Ions   = lineslog_frame.loc[BlueH_indx, 'Ion'].values
        
        #Check in case we do not have enough emission lines
        if len(Obs_Blue_Ions) >= 2:

            #Declare normalizing emission (Blue spectra always HBeta)
            N_line_flux = lineslog_frame.loc['H1_4861A']['line_Flux'] 
            N_line_f    = lineslog_frame.loc['H1_4861A']['line_f']
            N_line_Ion  = lineslog_frame.loc['H1_4861A']['Ion']
            
            #Calculate theoretical and observational ratios
            Desplacement_constant   = ufloat(N_line_flux.nominal_value, N_line_flux.std_dev)      #This is not completelety mathematically correct but avoids a zero sigma
            Theo_RecomRatio = lineslog_frame.loc[BlueH_indx, 'line_TheoRecombRatio'].values            
            Obs_RecombRatio = lineslog_frame.loc[BlueH_indx, 'line_Flux'].values / Desplacement_constant

            #Generate x_true and y axis arrays for the plot
            x_Blue         = lineslog_frame.loc[BlueH_indx, 'line_f'].values - N_line_f
            y_Blue         = unum_log10(Theo_RecomRatio) - unum_log10(Obs_RecombRatio)
                            
            return x_Blue, y_Blue, list(Obs_Blue_Ions), N_line_Ion
        
        else:
            
            return None, None, None, None

    def compute_RedPoints(self, lineslog_frame, Wmin, Wmax, Lambda_Match):
                   
        #Wavelength limits for the red lines
        Blue_limit      = Wmax - self.SpectraEdges_Limit
        Red_limit       = Lambda_Match + self.SpectraEdges_Limit
        RedH_indx       = lineslog_frame.index[in1d(lineslog_frame['Ion'], self.RecombRatios_Ions) & (lineslog_frame['TheoWavelength'] > Red_limit) & (lineslog_frame['TheoWavelength'] < Blue_limit)]   
                                  
        Obs_Red_Ions    = lineslog_frame.loc[RedH_indx, 'Ion'].values   
        
        #Check in case we do not have enough emission lines
        if len(Obs_Red_Ions) >= 2:
            
            #Declare normalizing emission (Blue spectra always HBeta)
            Hbeta_line_f        = lineslog_frame.loc['H1_4861A']['line_f']
            Hbeta_line_Emis     = lineslog_frame.loc['H1_4861A']['line_Emissivity']            
                           
            #Declare normalizing emission (in red spectra is the strongest emission )
            N_line_idx          = lineslog_frame.loc[RedH_indx]['Flux_Int'].idxmax()  #We do not use line_flux because it is a ufloat and it does not work with idxmax        
            N_line_flux         = lineslog_frame.loc[N_line_idx]['line_Flux'] 
            N_line_Ion          = lineslog_frame.loc[N_line_idx]['Ion']            
            N_line_Emis         = lineslog_frame.loc[N_line_idx]['line_Emissivity']            
                        
            #Determine theoretical intensity line ratios          
            Desplacement_constant   = ufloat(N_line_flux.nominal_value * Hbeta_line_Emis / N_line_Emis, N_line_flux.std_dev * Hbeta_line_Emis / N_line_Emis)
            Theo_RecomRatio_Red     = lineslog_frame.loc[RedH_indx, 'line_TheoRecombRatio'].values  
            Obs_RecombRatio_Red     = lineslog_frame.loc[RedH_indx, 'line_Flux'].values / Desplacement_constant
                        
            #Generate x_true and y axis arrays for the plot
            x_Red               = lineslog_frame.loc[RedH_indx, 'line_f'].values - Hbeta_line_f
            y_Red               = unum_log10(Theo_RecomRatio_Red) - unum_log10(Obs_RecombRatio_Red)

            return x_Red, y_Red, list(Obs_Red_Ions), N_line_Ion
        
        #Case we only have one red emission line... observation (most likely Halpha)
        else:
            
            return None, None, None, None
    
    def derreddening_line(self, CodeName, FileFolder, EmissionLine_label, EmissionLine_Wave, LinesLog_suffix, cHbeta):
        
        EmLine_Flux             = self.GetParameter_LineLog(CodeName, FileFolder, EmissionLine_label, 'FluxGauss', LinesLog_suffix)
        EmLine_Flux_derred      = None
    
        if cHbeta > 0:
            f_wave              = self.Reddening_f(array([EmissionLine_Wave]), 3.2)
            f_Hbeta             = self.Reddening_f(array([4861.333]), 3.2)
            
            Power_Coeff         = cHbeta * (1 + f_wave - f_Hbeta)
            
            EmLine_Flux_derred  = EmLine_Flux * power(10, Power_Coeff)
        
        else:
            EmLine_Flux_derred  = EmLine_Flux
    
            
        return EmLine_Flux_derred
    
    def getLinesFlux_dered(self, Lines_List, cHbeta, Mode = 'Auto'):
        #WARNING THE DICT WILL NOT BE CORRECTED FOR REDDENING IF ONE OF THE LINES IS NONE... DOES THIS AFFECT ME?
        Lines_dict, Wavelength_Vector   = self.getEmLine_dict(Lines_List, Mode = Mode)
                
        if (None not in Lines_dict.values()):
            if (cHbeta > 0.0) and (self.Reddening_Force == True):
                Fluxes_lines        = array(Lines_dict.values())
                f_lines             = self.Reddening_f(Wavelength_Vector,   3.2,  'Cardelli1989')
                Flux_derred         = Fluxes_lines * unum_pow(10,  f_lines * cHbeta)
                Dered_Lines_Dict    = OrderedDict(zip(Lines_dict.keys(), Flux_derred))
            
                return Dered_Lines_Dict
                
        return Lines_dict

    def derreddening_continuum(self, Spectrum_WavelengthRange, Spectrum_Flux, cHbeta):
        
        if (cHbeta != None) and (cHbeta > 0):
            f_wave              = self.Reddening_f(Spectrum_WavelengthRange, 3.2)
            f_Hbeta             = self.Reddening_f(array([4862.683]), 3.2)
            
            Power_Coeff         = cHbeta * (1 + f_wave - f_Hbeta)
            
            Int_spectrum        = Spectrum_Flux * power(10, Power_Coeff)
        
        else:
            print '- WARNING: c(Hbeta) is less than zero'
            Int_spectrum  = Spectrum_Flux
                       
        return Int_spectrum

    def reddening_continuum(self, Spectrum_WavelengthRange, Spectrum_Int, cHbeta):
        
        if (cHbeta != None) and (cHbeta > 0):
            f_wave              = self.Reddening_f(Spectrum_WavelengthRange, 3.2)
            f_Hbeta             = self.Reddening_f(array([4862.683]), 3.2)
            
            Power_Coeff         = cHbeta * (1 + f_wave - f_Hbeta)
            
            Spectrum_flux       = Spectrum_Int * power(10, -Power_Coeff)
        
        else:
            print '- WARNING: c(Hbeta) is less than zero'
            Spectrum_flux        = Spectrum_Int
                       
        return Spectrum_flux
 
    def Reddening_f(self, wave, R_v = 3.2, curve_parametrization = 'Miller&Mathews1972'):
                
        if curve_parametrization == 'Miller&Mathews1972':

            if isinstance(wave, ndarray):
                y           = 1.0/(wave/10000.0) 
                y_beta      = 1.0/(4862.683/10000.0)
                
                ind_low     = where(y <= 2.29)[0]
                ind_high    = where(y >  2.29)[0]
                
                dm_lam_low  = 0.74 * y[ind_low]  - 0.34 + 0.341 * R_v - 1.014
                dm_lam_high = 0.43 * y[ind_high] + 0.37 + 0.341 * R_v - 1.014
                dm_beta     = 0.74 * y_beta      - 0.34 + 0.341 * R_v - 1.014
                
                dm_lam = concatenate((dm_lam_low, dm_lam_high))
                
                f = dm_lam/dm_beta - 1
                
            else:
                
                y           = 1.0/(wave/10000.0) 
                y_beta      = 1.0/(4862.683/10000.0)
                
                if y <= 2.29:
                    dm_lam  = 0.74 * y  - 0.34 + 0.341 * R_v - 1.014
                else:
                    dm_lam = 0.43 * y + 0.37 + 0.341 * R_v - 1.014
        
                dm_beta     = 0.74 * y_beta - 0.34 + 0.341 * R_v - 1.014
                                
                f = dm_lam/dm_beta - 1
                        
        elif curve_parametrization == 'Cardelli1989':

            x_true = 1.0 / (wave / 10000.0)
            y = x_true - 1.82
        
            y_coeffs = array([ones(len(y)), y, power(y, 2), power(y, 3), power(y, 4), power(y, 5), power(y, 6), power(y, 7)])
            a_coeffs = array([1, 0.17699,    -0.50447,   -0.02427,   0.72085,    0.01979,    -0.77530,   0.32999])
            b_coeffs = array([0, 1.41338,    2.28305,   1.07233,   -5.38434,    -0.62251,    5.30260,   -2.09002])
            
            a_x =  dot(a_coeffs,y_coeffs)
            b_x =  dot(b_coeffs,y_coeffs)
            
            X_x = a_x + b_x / R_v
            
            y_beta          = (1 / (4862.683 / 10000)) - 1.82
            y_beta_coeffs   = array([1, y_beta, power(y_beta, 2), power(y_beta, 3), power(y_beta, 4), power(y_beta, 5), power(y_beta, 6), power(y_beta, 7)])
            
            X_x_beta          = dot(a_coeffs,y_beta_coeffs) + dot(b_coeffs,y_beta_coeffs) / R_v
        
            f = X_x / X_x_beta - 1
        
        return f

    def Epm_ReddeningPoints(self):
        
        x_true           = arange(1.0, 2.8, 0.1) #in microns -1
        X_Angs      = 1 / x_true * 1e4
        
        Xx          = array([1.36, 1.44, 1.84, 2.04, 2.24, 2.44, 2.66, 2.88, 3.14, 3.36, 3.56, 3.77, 3.96, 4.15, 4.26, 4.40, 4.52, 4.64])
        f_lambda    = array([-0.63,-0.61,-0.5, -0.45, -0.39, -0.34, -0.28, -0.22, -0.15, -0.09, -0.03, 0.02, 0.08, 0.13, 0.16, 0.20, 0.23, 0.26])
        
        return x_true, X_Angs, Xx, f_lambda
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
                x_range, y_range = ExtractSubRegion(Wave, Int, RightPoints[i][0], RightPoints[i][1])
                Pv.Axis1.fill_between(x_range, zeros(len(x_range)), y_range, label= "Red Continuum", facecolor=Pv.Color_Vector[2][1],alpha = 0.2)
            
            Label3 = "Blue continuum"
            x_Bluecontinuum = SubWave[where(SubWave<=BalmerJump_Wavelength)]
            y_BlueContinuum = m_blue * x_Bluecontinuum + n_blue
            Pv.DataPloter_One(x_Bluecontinuum, y_BlueContinuum, Label3, Pv.Color_Vector[2][2], LineStyle='--', LineWidth=2)
            
            Label4 = "Red continuum"
            x_Redcontinuum = SubWave[where(SubWave>=BalmerJump_Wavelength)]
            y_RedContinuum = m_red * x_Redcontinuum + n_red
            Pv.DataPloter_One(x_Redcontinuum, y_RedContinuum, Label4, Pv.Color_Vector[2][1], LineStyle='--', LineWidth=2)
            
            if CodeName == 'SHOC579':
              
                H1 = RecAtom('H', 1)
                Hbeta_Emis = H1.getEmissivity(tem = 10000, den = 100, label = '4_2')
                H11_Emis = H1.getEmissivity(tem = 10000, den = 100, label = '11_2')
                ratio11_beta = Hbeta_Emis / H11_Emis  
                
#                              
#                 y_I             = 0.1119
#                 y_II            = 0.0006
#                 H11_Flux        = 8.280005e-16 #2.174
#                 Hbalmer_flux    = 2.258348e-14 #100 
#                 H11_Trick       = Hbalmer_flux / ratio11_beta
#                  
#                 print 'Theo ratio', ratio11_beta   
#                 print 'Obs ratio', Hbalmer_flux/ H11_Flux                
#                  
                BJ = y_BlueContinuum[-1] - y_RedContinuum[0]
class He_Inference_Abundance(Dazer_Files):
    
    def __init__(self):
        
        #Import Dazer_Files Class to import data from lines_logs
        Dazer_Files.__init__(self)
                
        #Declare Hydrogen and Helium collisional lines for the analysis
        self.posHydrogen_Lines      = ['Hdelta_6_2',    'Hgamma_5_2',   'Hbeta_4_2',    'Halpha_3_2']
        self.Hydrogen_Wavelengths   = [4101.742,        4340.471,       4862.683,        6562.819]
        #self.Hydrogen_Labels       = ['6_2',           '5_2',          '4_2',          '3_2']

        self.posHelium_Lines        = ['He1_3889A',    'He1_4026A',    'He1_4387A',      'He1_4471A',    'He1_4686A',      'He1_4714A',    'He1_4922A',      'He1_5876A',    'He1_6678A',      'He1_7065A',    'He1_7281A',      'He1_10380A']     
        self.Helium_Wavelengths     = [3889.0,        4026.0,         4387.0,         4471.0,         4686.0,         4714.0,         4922.0,         5876.0,         6678.0,         7065.0,         7281.0,         10380.0]
        #self.Helium_Labels         = ['3889.0',     '4026.0',       '4471.0',       '5876.0',       '6678.0',       '7065.0']
   
        self.Cand_Hydrogen_Lines    = []
        self.Cand_Helium_Lines      = []
        
        self.nHydrogen              = None
        self.nHelium                = None
    
        #Define indexes and labels to speed up the code               
        self.HBeta_label            = 'Hbeta_4_2'
                
        #Declare pyneb Hydrogen and Helium atoms to calculate emissivities
        self.H1                     = RecAtom('H', 1)
        self.He1                    = RecAtom('He', 1)                
        
        #Import collisional coefficients table
        self.Coef_Kalpha_dict       = self.Import_Coll_Coeff_Table(self.posHydrogen_Lines, None)

        #Import Optical depth function
        self.Coef_ftau_dict         = self.Import_OpticalDepth_Coeff_Table(self.posHelium_Lines) 
            
        #Line dictionaries
        self.Flux_dict              = OrderedDict()
        self.Error_dict             = OrderedDict()
        self.Wave_dict              = OrderedDict()
        self.PynebCode_dict         = OrderedDict()
        self.flambda_dict           = self.get_flambda_dict(self.posHydrogen_Lines + self.posHelium_Lines, self.Hydrogen_Wavelengths + self.Helium_Wavelengths) #WARNING: In this analysis flambda is mantained constant
        self.EqW_dict               = OrderedDict()
        self.EqWerror_dict          = OrderedDict()
        self.hlambda_dict           = OrderedDict()
    
        #Extra
        self.EmptyRowFormat         = 'nan'
        
    def Import_TableData(self, Address, Columns):
        
        Imported_Array  = genfromtxt(Address, dtype=float, usecols = Columns, skiprows = 2).T
        Datarray = Imported_Array[:,~isnan(Imported_Array).all(0)]
                
        return Datarray
     
    def Import_Coll_Coeff_Table(self, HydrogenLines, HeliumLines):
        
        data_dict = OrderedDict()
                
        for i in range(len(HydrogenLines)):
            
            Line            = HydrogenLines[i]
            Data_Columns    = [0 + 3*i, 1 + 3*i, 2 + 3*i]
            data_dict[Line] = self.Import_TableData(self.Hydrogen_CollCoeff_TableAddress, Data_Columns)
        
        #We ignore since the emissivities from PFM already have the collisional contribution accounted
#         for j in range(len(HeliumLines)):
#             
#             Line            = HeliumLines[i]
#             Data_Columns    = [0 + 3*j, 1 + 3*j, 2 + 3*j]
#             data_dict[Line] = self.Import_TableData(self.Helium_CollCoeff_TableAddress, Data_Columns)
            
        return data_dict
     
    def Import_OpticalDepth_Coeff_Table(self, HeliumLines):
        
        data_dict = OrderedDict()

        for i in range(len(HeliumLines)):
            
            Line            = HeliumLines[i]
            data_dict[Line] = loadtxt(self.Helium_OpticalDepth_TableAddress, dtype = float, skiprows = 2, usecols = (i,))
            
        return data_dict
    
    def Import_Synthetic_Fluxes(self, case = 'case1'):
 
#         if case == 'case1':
#         
# #             H_Flux_Obs  = array([ 0.24585991,  0.45343263,  2.95803687])
# #             He_Flux_Obs = array([ 0.0891384,   0.01283333,  0.03187135,  0.09890274,  0.02582588,  0.02366021])   
# #             H_Labels_0  =       ['Hdelta_6_2',    'Hgamma_5_2',   'Halpha_3_2']
# #             H_waves_0   = array([4101.742,        4340.471,       6562.819])   
# #             He_Labels_0 =       ['He1_3889A',   'He1_4026A',   'He1_4471A',     'He1_5876A',   'He1_6678A',     'He1_7065A']
# #             He_waves_0  = array([3889.0,        4026.0,         4471.0,         5876.0,         6678.0,         7065.0])             
# #         
# #             return H_Flux_Obs, He_Flux_Obs, H_Labels_0, H_waves_0, He_Labels_0, He_waves_0
#         
        if case == 'case2':
            
            H_Flux_Obs  = array([ 0.24625485,  0.454443,    2.98352834])
            He_Flux_Obs = array([0.10100783,  0.01691781,  0.03924855,  0.12725256,  0.03553524,  0.04162797])
            H_Labels_0  =       ['Hdelta_6_2',    'Hgamma_5_2',   'Halpha_3_2']
            H_waves_0   = array([4101.742,        4340.471,       6562.819])   
            He_Labels_0 =       ['He1_3889A',   'He1_4026A',   'He1_4471A',     'He1_5876A',   'He1_6678A',     'He1_7065A']
            He_waves_0  = array([3889.0,        4026.0,         4471.0,         5876.0,         6678.0,         7065.0])   
            
            return H_Flux_Obs, He_Flux_Obs, H_Labels_0, H_waves_0, He_Labels_0, He_waves_0
        
    def Calculate_synthetic_fluxes(self, mycase="case2"):

        y_plus, n_e, a_He, tau, Te_0, cHbeta, a_H, xi, EW_Hbeta, err_Flux_H, err_Flux_He = self.Example_SyntheticParameters2()
                
        #Import observed data:
        H_Flux_Obs, He_Flux_Obs, H_Labels_0, H_waves_0, He_Labels_0, He_waves_0     = self.Import_Synthetic_Fluxes(case = mycase)
        H_Flux_Obs_err, He_Flux_Obs_er                                              = H_Flux_Obs*0.01, He_Flux_Obs*0.02

        self.Cand_Hydrogen_Lines        = H_Labels_0
        self.Cand_Helium_Lines          = He_Labels_0

        self.nHydrogen                  = len(H_Flux_Obs) 
        self.nHelium                    = len(He_Flux_Obs)
        
        self.H_He_Obs_Flux              = concatenate([H_Flux_Obs, He_Flux_Obs])
        self.H_He_Obs_Error             = concatenate([H_Flux_Obs_err, He_Flux_Obs_er])
                        
        self.Hbeta_EW                   = 250
        self.Hbeta_EWerror              = self.Hbeta_EW* 0.05  
        self.hbeta_hlambda              = 1.0
        self.hlambda_H_vector           = ones(self.nHydrogen)
        
        self.Emissivity_H_vector        = zeros(self.nHydrogen)
        self.Kalpha_vector              = zeros(self.nHydrogen)
        self.flambda_H_vector           = zeros(self.nHydrogen)
        
        self.Emissivity_He_vector       = zeros(self.nHelium)
        self.ftau_He_vector             = zeros(self.nHelium)
        self.flambda_He_vector          = zeros(self.nHelium)
        self.hlambda_He_vector          = ones(self.nHelium)

        #Calculating the hydrogen lines fluxes    
        for i in range(self.nHydrogen):
            Label = self.Cand_Hydrogen_Lines[i]
            self.PynebCode_dict[Label]              = Label[Label.find('_')+1:len(Label)]
            self.flambda_H_vector[i]                = self.flambda_dict[Label]
    
        #Calculating the helium lines fluxes 
        for i in range(self.nHelium):
            Label = self.Cand_Helium_Lines[i]
            self.PynebCode_dict[Label]              = Label[Label.find('_')+1:-1]+'.0'
            self.flambda_He_vector[i]               = self.flambda_dict[Label]            
            
        #Adding Hbeta line
        self.PynebCode_dict[self.HBeta_label]       = '4_2'        
        
        #Calculating values+
        self.Calculate_Theoretical_Parameters(Te_0, n_e, tau)
        
        #Calculating synthetic hydrogen lines
        H_Flux  = self.H_Flux_theo(xi, cHbeta, a_H)
        
        #Calculating synthetic helium lines
        He_Flux = self.He_Flux_theo_nof(xi, cHbeta, a_H, a_He, y_plus)
        
        
        
        
        return H_Flux, He_Flux

    def Import_Object_Data(self, FileAddress):

        Labels, Ions                                                    = self.get_ColumnData([self.Labels_ColumnHeader, self.Ion_ColumnHeader], TableAddress = FileAddress, HeaderSize = 2, datatype = str) 
        Wavelengths, FluxGauss, ErrorEL_MCMC, EW, EW_error, h_lines     = self.get_ColumnData([self.Wavelength_ColumnHeader, self.GaussianFlux_ColumnHeader, self.GaussianError_ColumnHeader, self.EqW_ColumnHeader, self.EqW_error_ColumnHeader, self.Line_Continuum_ColumnHeader], TableAddress = FileAddress, HeaderSize = 2)
        
        #Empty the lists of candidate lines for Hydrogen and Helium
        del self.Cand_Hydrogen_Lines[:]
        del self.Cand_Helium_Lines[:]
        
        #Getting the indexes for the observed hydrogen lines
        #The structure is kind of inefficient
        #WARGNING helium and hydrogen lines are following a different structure
        for i in range(len(self.posHelium_Lines)):
            HeliumLine_i                                                = self.posHelium_Lines[i]
            index_i                                                     = where(Labels==HeliumLine_i)[0]
            if len(index_i) != 0:
                LabelLine                                               = Labels[index_i[0]]
                self.Flux_dict[LabelLine]                               = FluxGauss[index_i[0]]
                self.Error_dict[LabelLine]                              = ErrorEL_MCMC[index_i[0]]
                self.Wave_dict[LabelLine]                               = Wavelengths[index_i[0]]
                self.PynebCode_dict[LabelLine]                          = LabelLine[LabelLine.find('_')+1:-1]+'.0'
                self.EqW_dict[LabelLine]                                = EW[index_i[0]]
                self.EqWerror_dict[LabelLine]                           = EW_error[index_i[0]]
                self.hlambda_dict[LabelLine]                            = h_lines[index_i[0]]
                self.Cand_Helium_Lines.append(LabelLine)
                
        #Getting the indexes for the observed hydrogen lines
        #The structure is kind of inefficient
        #WARGNING helium and hydrogen lines are following a different structure
        for i in range(len(self.posHydrogen_Lines)):
            HydroLine_i = self.posHydrogen_Lines[i]
            index_i     = where(Ions == HydroLine_i)[0]
            if len(index_i) != 0:
                LabelLine                                               = self.posHydrogen_Lines[i]
                self.Flux_dict[LabelLine]                               = FluxGauss[index_i[0]]
                self.Error_dict[LabelLine]                              = ErrorEL_MCMC[index_i[0]]
                self.Wave_dict[LabelLine]                               = Wavelengths[index_i[0]]
                self.PynebCode_dict[LabelLine]                          = LabelLine[LabelLine.find('_')+1:len(LabelLine)]
                self.EqW_dict[LabelLine]                                = EW[index_i[0]]
                self.EqWerror_dict[LabelLine]                           = EW_error[index_i[0]]
                self.hlambda_dict[LabelLine]                            = h_lines[index_i[0]]
                self.Cand_Hydrogen_Lines.append(LabelLine)

        #Since we do not use the Hbeta line we remove it from the Hydrogen lines    
        self.Cand_Hydrogen_Lines.remove(self.HBeta_label)
      
        #Define in advance the numper of lines
        self.nHydrogen                                                  = len(self.Cand_Hydrogen_Lines) 
        self.nHelium                                                    = len(self.Cand_Helium_Lines)
        
        self.Flux_H_vector                                              = zeros(self.nHydrogen)
        self.Error_H_vector                                             = zeros(self.nHydrogen)
        self.Emissivity_H_vector                                        = zeros(self.nHydrogen)
        self.Kalpha_vector                                              = zeros(self.nHydrogen)
        self.flambda_H_vector                                           = zeros(self.nHydrogen)
        self.Eqw_H_vector                                               = zeros(self.nHydrogen)
        self.EqwError_H_vector                                          = zeros(self.nHydrogen)
        self.hlambda_H_vector                                           = zeros(self.nHydrogen)

        self.Flux_He_vector                                             = zeros(self.nHelium)
        self.Error_He_vector                                            = zeros(self.nHelium)
        self.Emissivity_He_vector                                       = zeros(self.nHelium)
        self.ftau_He_vector                                             = zeros(self.nHelium)
        self.flambda_He_vector                                          = zeros(self.nHelium)
        self.Eqw_He_vector                                              = zeros(self.nHelium)
        self.EqwError_He_vector                                         = zeros(self.nHelium)
        self.hlambda_He_vector                                          = zeros(self.nHelium)
        
        return

    def Preload_Synthetic_data(self, mycase):

        #Import observed data:
        H_Flux_Obs, He_Flux_Obs, H_Labels_0, H_waves_0, He_Labels_0, He_waves_0     = self.Import_Synthetic_Fluxes(case = mycase)
        H_Flux_Obs_err, He_Flux_Obs_er                                              = H_Flux_Obs*0.01, He_Flux_Obs*0.02

        self.Cand_Hydrogen_Lines        = H_Labels_0
        self.Cand_Helium_Lines          = He_Labels_0

        self.nHydrogen                  = len(H_Flux_Obs) 
        self.nHelium                    = len(He_Flux_Obs)
        
        self.H_He_Obs_Flux              = concatenate([H_Flux_Obs, He_Flux_Obs])
        self.H_He_Obs_Error             = concatenate([H_Flux_Obs_err, He_Flux_Obs_er])
                        
        self.Hbeta_EW                   = 250
        self.Hbeta_EWerror              = self.Hbeta_EW* 0.05  
        self.hbeta_hlambda              = 1.0
        
        self.Emissivity_H_vector        = zeros(self.nHydrogen)
        self.Kalpha_vector              = zeros(self.nHydrogen)
        self.flambda_H_vector           = zeros(self.nHydrogen)
        self.hlambda_H_vector           = ones(self.nHydrogen)

        self.Emissivity_He_vector       = zeros(self.nHelium)
        self.ftau_He_vector             = zeros(self.nHelium)
        self.flambda_He_vector          = zeros(self.nHelium)
        self.hlambda_He_vector          = ones(self.nHelium)

        #Calculating the hydrogen lines fluxes    
        for i in range(self.nHydrogen):
            Label = self.Cand_Hydrogen_Lines[i]
            self.PynebCode_dict[Label]              = Label[Label.find('_')+1:len(Label)]
            self.flambda_H_vector[i]                = self.flambda_dict[Label]
    
        #Calculating the helium lines fluxes 
        for i in range(self.nHelium):
            Label = self.Cand_Helium_Lines[i]
            self.PynebCode_dict[Label]              = Label[Label.find('_')+1:-1]+'.0'
            self.flambda_He_vector[i]               = self.flambda_dict[Label]

        #Adding Hbeta line
        self.PynebCode_dict[self.HBeta_label]       = '4_2'
        
        print 'Printing all the data:\n'
        
        print 'self.PynebCode_dict', self.PynebCode_dict
       
        print 'self.Cand_Hydrogen_Lines',self.Cand_Hydrogen_Lines
        print 'self.Cand_Helium_Lines',self.Cand_Helium_Lines

        print 'self.nHydrogen',self.nHydrogen                
        print 'self.nHelium',self.nHelium                 
        
        print 'self.H_He_Obs_Flux',self.H_He_Obs_Flux           
        print 'self.H_He_Obs_Error',  self.H_He_Obs_Error        
                        
        print 'self.Hbeta_EW',self.Hbeta_EW                
        print 'self.Hbeta_EWerror',self.Hbeta_EWerror            
        print 'self.hbeta_hlambda',self.hbeta_hlambda           
        
        print 'self.Emissivity_H_vector' ,self.Emissivity_H_vector       
        print 'self.Kalpha_vector',self.Kalpha_vector              
        print 'self.flambda_H_vector', self.flambda_H_vector          
        print 'self.hlambda_H_vector',self.hlambda_H_vector          

        print 'self.Emissivity_He_vector',self.Emissivity_He_vector      
        print 'self.ftau_He_vector',self.ftau_He_vector            
        print 'self.flambda_He_vector',self.flambda_He_vector         
        print 'self.hlambda_He_vector', self.hlambda_He_vector        
        
        return

    def Preload_Obs_data(self, Normalized = False):

        #Calculate in advance HBeta values
        self.Hbeta_Flux                             = self.Flux_dict[self.HBeta_label]
        self.Hbeta_error                            = self.Error_dict[self.HBeta_label]
        self.Hbeta_EW                               = self.EqW_dict[self.HBeta_label]
        self.Hbeta_EWerror                          = self.EqWerror_dict[self.HBeta_label]      
        self.hbeta_hlambda                          = self.hlambda_dict[self.HBeta_label]
        
        #Calculate in advance observed physical parameters vectors for Hydrogen lines
        for i in range(self.nHydrogen):
            Line_Label                              = self.Cand_Hydrogen_Lines[i]        
            self.Flux_H_vector[i]                   = self.Flux_dict[Line_Label]
            self.Error_H_vector[i]                  = self.Error_dict[Line_Label]
            self.Eqw_H_vector[i]                    = self.EqW_dict[Line_Label]
            self.EqwError_H_vector[i]               = self.EqWerror_dict[Line_Label]
            self.hlambda_H_vector[i]                = self.hlambda_dict[Line_Label]
            self.flambda_H_vector[i]                = self.flambda_dict[Line_Label]
                
        #Calculate in advance observed physical parameters vectors for the Helium lines
        for i in range(self.nHelium):
            Line_Label                              = self.Cand_Helium_Lines[i]
            self.Flux_He_vector[i]                  = self.Flux_dict[Line_Label]
            self.Error_He_vector[i]                 = self.Error_dict[Line_Label]
            self.Eqw_He_vector[i]                   = self.EqW_dict[Line_Label]
            self.EqwError_He_vector[i]              = self.EqWerror_dict[Line_Label]
            self.flambda_He_vector[i]               = self.flambda_dict[Line_Label]
            self.hlambda_He_vector[i]               = self.hlambda_dict[Line_Label]     

        #Combine Hydrogen and Helium values into a single vector
        if Normalized: 
            self.H_He_Obs_Flux                      = concatenate([self.Flux_H_vector, self.Flux_He_vector])
            self.H_He_Obs_Error                     = concatenate([self.Error_H_vector, self.Error_He_vector])

        else:
            self.H_He_Obs_Flux                      = concatenate([self.Flux_H_vector, self.Flux_He_vector])    / self.Hbeta_Flux
            self.H_He_Obs_Error                     = concatenate([self.Error_H_vector, self.Error_He_vector])  

    def Calculate_Theoretical_Parameters(self, T_e, n_e, tau):
        
        #Calculate in advance the T_4 parameter
        T_4 = T_e / 10000.0
        
        #Calculate the hbeta parameters
        self.Hbeta_Kalpha                           = self.Kalpha_Ratio_H(T_4 = T_4, H_label=self.HBeta_label)
        self.Hbeta_emis                             = self.H1.getEmissivity(T_e, n_e, label = self.PynebCode_dict[self.HBeta_label])

        #Calculate physical parameters for Hydrogen lines
        for i in range(self.nHydrogen):
            Line_Label                              = self.Cand_Hydrogen_Lines[i]
            self.Emissivity_H_vector[i]             = self.H1.getEmissivity(T_e, n_e, label = self.PynebCode_dict[Line_Label])
            self.Kalpha_vector[i]                   = self.Kalpha_Ratio_H(T_4 = T_4, H_label=Line_Label)
            
        #Calculate physical parameters for Helium lines
        for i in range(self.nHelium):
            Line_Label                              = self.Cand_Helium_Lines[i]
            self.Emissivity_He_vector[i]            = self.He1.getEmissivity(T_e, n_e, label = self.PynebCode_dict[Line_Label])
            self.ftau_He_vector[i]                  = self.OpticalDepth_He(tau = tau, T_4 = T_4, n_e = n_e, He_label = Line_Label)

        return

    def H_Flux_theo(self, xi, cHbeta, a_H):
        
        #Calculate the emissivities for each of the lines for the given temperature and density
        Emissivities_module = self.Emissivity_H_vector / self.Hbeta_emis
        
        #Calculate the Collisional excitation fraction
        CR_Module           = (1.0 + 0.0001* xi * self.Kalpha_vector) / (1.0 + 0.0001* xi * self.Hbeta_Kalpha)
        
        #Calculate the reddening component
        f_module            = power(10, -1 * self.flambda_H_vector * cHbeta)
        
        #Calculate the Hbeta normalization module
        EW_Hbeta_module     = (self.Hbeta_EW + a_H) / self.Hbeta_EW
        
        #Calculate stellar absorption module
        a_H_module          = ( a_H * self.hlambda_H_vector ) / (self.Hbeta_EW * self.hbeta_hlambda)
        
        #Calculate theoretical Hydrogen flux for each emission line
        H_Flux              = Emissivities_module * CR_Module * f_module * EW_Hbeta_module - a_H_module
        
        return H_Flux
        
    def He_Flux_theo_nof(self, xi, cHbeta, a_H, a_He, y_plus):
        
        #Calculate the emissivities for each of the lines for the given temperature and density
        Emissivities_module = self.Emissivity_He_vector / self.Hbeta_emis
        
        #Calculate the collisional excitation fraction
        CR_Module           = 1 / (1.0 + 0.0001* xi * self.Hbeta_Kalpha)

        #Calculate the reddening component
        f_module            = power(10, -1 * self.flambda_He_vector * cHbeta)

        #Calculate the Hbeta normalization module
        EW_Hbeta_module     = (self.Hbeta_EW + a_H) / self.Hbeta_EW
        
        #Calculate stellar absorption module
        a_He_module         = (a_He * self.hlambda_He_vector ) / (self.Hbeta_EW * self.hbeta_hlambda)
             
        #Calculate theoretical Hydrogen flux for each emission line
        He_Flux             = y_plus * Emissivities_module * self.ftau_He_vector * CR_Module * f_module * EW_Hbeta_module - a_He_module

        return He_Flux  
      
    def get_flambda_dict(self, lines_labels , lines_wavelengths, R_v=3.1):
    
        x_true          = 1.0 / (array(lines_wavelengths) / 10000.0)
        y               = x_true - 1.82
    
        y_coeffs        = array([ones(len(y)), y, power(y, 2), power(y, 3), power(y, 4), power(y, 5), power(y, 6), power(y, 7)])
        a_coeffs        = array([1, 0.17699,    -0.50447,   -0.02427,   0.72085,    0.01979,    -0.77530,   0.32999])
        b_coeffs        = array([0, 1.41338,    2.28305,   1.07233,   -5.38434,    -0.62251,    5.30260,   -2.09002])
        
        a_x             = dot(a_coeffs,y_coeffs)
        b_x             = dot(b_coeffs,y_coeffs)
        
        X_x             = a_x + b_x / R_v
        
        y_beta          = (1 / (4862.683 / 10000)) - 1.82
        y_beta_coeffs   = array([1, y_beta, power(y_beta, 2), power(y_beta, 3), power(y_beta, 4), power(y_beta, 5), power(y_beta, 6), power(y_beta, 7)])
        
        X_x_beta        = dot(a_coeffs,y_beta_coeffs) + dot(b_coeffs,y_beta_coeffs) / R_v
    
        f               = X_x / X_x_beta - 1
        
        return dict(zip(lines_labels , f))
         
    def Kalpha_Ratio_H(self, T_4, H_label):
                                          
        K_alpha_Ratio   = sum(self.Coef_Kalpha_dict[H_label][0] * exp(self.Coef_Kalpha_dict[H_label][1] / T_4) * power(T_4, self.Coef_Kalpha_dict[H_label][2]))
        
        return K_alpha_Ratio
    
    def OpticalDepth_He(self, tau, T_4, n_e, He_label):
                        
        f_tau   = 1 + (tau/2) * (self.Coef_ftau_dict[He_label][0] + (self.Coef_ftau_dict[He_label][1] + self.Coef_ftau_dict[He_label][2]*n_e + self.Coef_ftau_dict[He_label][3]*n_e*n_e) * T_4)

        return f_tau        
    
    def Example_SyntheticParameters(self):
        
        y_plus      = 0.08          #He+/H+
        n_e         = 100.0         #cm^-3 
        a_He        = 1.0           #Angstroms...
        tau         = 0.2         
        Te_0        = 18000.0       #K
        cHbeta      = 0.1           # 
        a_H         = 1.0           #Angstroms
        xi          = 1.0           #Angstroms
        EW_Hbeta    = 250           #Angstroms
        err_Flux_H  = 0.01          #Emission Line flux percentage
        err_Flux_He = 0.02          #Emission Line flux percentage
        
        return y_plus, n_e, a_He, tau, Te_0, cHbeta, a_H, xi, EW_Hbeta, err_Flux_H, err_Flux_He

    def Example_SyntheticParameters2(self):
        
        y_plus      = 0.085         #He+/H+
        n_e         = 500.0         #cm^-3 
        a_He        = 0.5           #Angstroms...
        tau         = 1.0         
        Te_0        = 16000.0       #K
        cHbeta      = 0.1           # 
        a_H         = 1.0           #Angstroms
        xi          = 1.0           #Angstroms
        EW_Hbeta    = 250           #Angstroms
        err_Flux_H  = 0.01          #Emission Line flux percentage
        err_Flux_He = 0.02          #Emission Line flux percentage
        
        return y_plus, n_e, a_He, tau, Te_0, cHbeta, a_H, xi, EW_Hbeta, err_Flux_H, err_Flux_He