import pandas as pd
import os

from .func import *
from .SEDanalysis import *
from .toolplot import *

def fitSpec(wavSpec, fluxSpec, efluxSpec,\
			wavPhot, fluxPhot, efluxPhot, \
			filters, \
			z = -0.01,\
			ULPhot = [],\
			obsCorr = True,\
			S9p7_fixed = -99.,\
			Nmc = 10000, pgrbar = 1, \
			Pdust = [10., 3.], PPAH = [9., 3.], Ppl = [-1., 3.], Pbreak = [40., 1.], Pslope1 = [1., 2.], Pslope2 = [1., 2.], \
			Plsg = [-1., 3.], Pllg = [-1., 3.],\
			sourceName = 'NoName', pathTable = './', pathFig = './', \
			redoFit = True, saveRes = True):

	"""
    This function fits the observed SED when a spectrum is combined to photometric data. The observed wavelengths, fluxes and uncertainties on the fluxes are passed separately for the spectrum and the photometric data.
    ------------
    :param wavSpec: observed wavelengths for the spectrum (in microns).
    :param fluxSpec: observed fluxes for the spectrum (in Jansky).
    :param efluxSpec: observed uncertainties on the fluxes for the spectrum (in Jansky).
    :param wavPhot: observed wavelengths for the photometry (in microns).
    :param fluxPhot: observed fluxes for the photometry (in Jansky).
    :param efluxPhot: observed uncertainties on the fluxes for the photometry (in Jansky).
    :param filters: name of the photometric filters to include in the fit.
    ------------
    :keyword z: redshift of the source. Default = 0.01.
    :keyword ULPhot: vector of length Nphot, where Nphot is the number of photometric data. If any of the value is set to 1, the corresponding flux is set has an upper limit in the fit. Default = [].
    :keyword obsCorr: if set to True, iragnsep attempt to calculate the total silicate absorption at 9.7micron, and to correct the observed fluxes for obscuration. Default = True
    :keyword S9p7_fixed: can be used to pass a fixed value for the total silicate absorption at 9.7 micron. Default = -99.
    :keyword Nmc: numer of MCMC run. Default = 10000.
    :keyword pgrbar: if set to 1, display a progress bar while fitting the SED. Default = 1.
    :keyword Pdust: normal prior on the log-normalisation of the galaxy dust continuum template. Default = [10., 3.] ([mean, std dev]).
    :keyword PPAH: normal prior on the log-normalisation of the PAH template. Default = [9., 3.] ([mean, std dev]).
	:keyword Ppl: normal prior on the log-normalisation AGN continuum (defined at 10 micron). Default = [-1., 3.] ([mean, std dev]).
	:keyword Pbreak: normal prior on lbreak, the position of the log-break. Default = [1.6, 0.01] ([mean, std dev]).
	:keyword Pslope1: normal prior on alpha1, the slope of the first power-law defined between 1<lambda<15 microns. Default = [1., 2.] ([mean, std dev]).
	:keyword Pslope2: normal prior on alpha2, the slope of the second power-law defined between 15<lambda<lbreak. Default = [1., 2.] ([mean, std dev]).
	:keyword Plsg: normal prior on the log-normalisation of the silicate emission at 11micron. Default = [-1., 3.] ([mean, std dev]).
	:keyword Pllg: normal prior on the log-normalisation of the silicate emission at 18micron. Default = [-1., 3.] ([mean, std dev]).
	:keyword sourceName: name of the source. Default = 'NoName'.
	:keyword pathTable: if saveRes is set to True, the tables containing the results of the fits will be saved at the location pathTable. Default = './'.
	:keyword pathFig: if saveRes is set to True, the figues showing the results of the fits will be saved at the location pathFig. Default = './'.
	:keyword redoFit: if set to True, re-performs the fits. Otherwise, find the table saved at pathTable and reproduces the analysis and the figures only. Default = True.
	:keyword saveRes: if set to True, the tables containing the results of the fits as well as the figures are saved. Default = True.
	------------
    :return res_fit: dataframe containing the results of all the possible fits.
    :return res_fitBM: dataframe containing the results of the best fit only.
    """
	
	# test if the path for the tables exists. If not, raise ValueError, crash.
	if pathTable.endswith('/') == False:
		pathTable = pathTable+'/'
	if os.path.isdir(pathTable) == False:
		raise ValueError('The path '+pathTable+' to save the tables does not exist. Please create it.')

	# test if the path for the figures exists. If not, raise ValueError, crash.
	if pathFig.endswith('/') == False:
		pathFig = pathFig+'/'	
	if os.path.isdir(pathFig) == False:
		raise ValueError('The path '+pathFig+' to save the figures does not exist. Please create it.')

	# run basic tests to avoid crashing while fitting (see func.py file). 
	basictests(wavSpec, fluxSpec, efluxSpec, wavPhot, fluxPhot, efluxPhot, filters, z, specOn = True)
	z = abs(z)

	# open the galaxy and AGN templates.
	path = os.path.dirname(iragnsep.__file__)
	templ = pd.read_csv(path+'/iragnsep_templ.csv')

	# Test that the obscuration
	if S9p7_fixed != -99.:
		if S9p7_fixed < 1e-3:
			S9p7_fixed = -98.
		if S9p7_fixed > 1e5:
			raise ValueError("S9p7_fixed has been set above to the maximum allowed value (i.e. 1e5). Please check.")

	# Test if the length of the upper-limit vector is that of the length of photometric point. If not, raise ValueError, crash.
	if (len(ULPhot) > 0) & (len(ULPhot) != (len(wavPhot))):
		raise ValueError("UPPER LIMITS ISSUE: Crashed because the vector UL for photometry has been passed but has not the same length as the photometric data.")

	# If redoFit is set to True, re-performs the fits. Otherwise, try to open the table results and jump to calculating the IR properties and plotting the results.
	if redoFit == True:
		# run the SED fit (see SEDanalysis.py file).
		res_fit = runSEDspecFit(wavSpec, fluxSpec, efluxSpec,\
								wavPhot, fluxPhot, efluxPhot, \
								filters, \
								z = z,\
								ULPhot = ULPhot, \
								obsCorr = obsCorr,\
								S9p7_fixed = S9p7_fixed,\
								Nmc = Nmc, pgrbar = pgrbar, \
								Pdust = Pdust, PPAH = PPAH, Ppl = Ppl, Pbreak = Pbreak, Pslope1 = Pslope1, Pslope2 = Pslope2, Plsg = Plsg, Pllg = Pllg,\
								templ = templ)
	else:
		# If redoFit is not set to True, attempt to open the table containing the results of the fits. If failed, raise ValueError, crash.
		try:
			res_fit = pd.read_csv(pathTable+sourceName+'_fitRes_spec.csv')
		except:
			raise ValueError('Cannot find the table. Check the name or redo the fit.')

	# Prepare the upper limits. Stick together a vector of zeros if no upper-limits are provided.
	if len(ULPhot) != len(wavPhot):
		ULPhot = np.zeros(len(wavPhot))
	ULSpec = np.zeros(len(wavSpec))
	UL = np.concatenate([ULSpec, ULPhot])

	# Generate a global uncertainties on the fluxes to pass to 'get_prop' to estimate the uncertainties on the fits.
	efluxChar_spec = np.sqrt(np.sum(efluxSpec**2.))/len(efluxSpec)/np.mean(fluxSpec)
	o = np.where(ULPhot == 0.)[0]
	efluxChar_phot = np.sqrt(np.sum(efluxPhot[o]**2.))/len(efluxPhot[o])/np.mean(fluxPhot[o])
	efluxChar = np.sqrt(efluxChar_phot**2. + efluxChar_spec**2.)

	# Calculate the IR properties of the galaxy and the AGN.
	loglum_hostIR, eloglum_hostIR, \
	loglum_hostMIR, eloglum_hostMIR, \
	loglum_hostFIR, eloglum_hostFIR, \
	loglum_AGNIR, loglum_AGNMIR, loglum_AGNFIR, \
	AGNfrac_IR, AGNfrac_MIR, AGNfrac_FIR, SFR, eSFR, wSFR, ewSFR = get_prop(res_fit, efluxChar, templ = templ, z = z)

	# Set default values to -99. for the final table.
	logNormGal_dust = res_fit['logNormGal_dust'].values
	logNormGal_dust = np.round(logNormGal_dust,3)
	res_fit['logNormGal_dust'] = logNormGal_dust

	elogNormGal_dust = res_fit['elogNormGal_dust'].values
	elogNormGal_dust = np.round(elogNormGal_dust,3)
	res_fit['elogNormGal_dust'] = elogNormGal_dust

	logNormGal_PAH = res_fit['logNormGal_PAH'].values
	o = np.where(logNormGal_PAH == -11.)[0]
	logNormGal_PAH[o] = -99.
	logNormGal_PAH = np.round(logNormGal_PAH,3)
	res_fit['logNormGal_PAH'] = logNormGal_PAH

	elogNormGal_PAH = res_fit['elogNormGal_PAH'].values
	o = np.where(elogNormGal_PAH == 0.)[0]
	elogNormGal_PAH[o] = -99.
	elogNormGal_PAH = np.round(elogNormGal_PAH,3)
	res_fit['elogNormGal_PAH'] = elogNormGal_PAH

	logNormAGN_PL = res_fit['logNormAGN_PL'].values
	o = np.where(logNormAGN_PL == -100.)[0]
	logNormAGN_PL[o] = -99.
	logNormAGN_PL = np.round(logNormAGN_PL,3)
	res_fit['logNormAGN_PL'] = logNormAGN_PL

	elogNormAGN_PL = res_fit['elogNormAGN_PL'].values
	elogNormAGN_PL = np.round(elogNormAGN_PL,3)
	res_fit['elogNormAGN_PL'] = elogNormAGN_PL

	lBreak_PL = res_fit['lBreak_PL'].values
	o = np.where(lBreak_PL == -59.)[0]
	lBreak_PL[o] = -99.
	lBreak_PL = np.round(lBreak_PL,3)
	res_fit['lBreak_PL'] = lBreak_PL

	elBreak_PL = res_fit['elBreak_PL'].values
	elBreak_PL = np.round(elBreak_PL,3)
	res_fit['elBreak_PL'] = elBreak_PL

	alpha1_PL = res_fit['alpha1_PL'].values
	o = np.where(alpha1_PL == -98.)[0]
	alpha1_PL[o] = -99.
	alpha1_PL = np.round(alpha1_PL,3)
	res_fit['alpha1_PL'] = alpha1_PL

	ealpha1_PL = res_fit['ealpha1_PL'].values
	ealpha1_PL = np.round(ealpha1_PL,3)
	res_fit['ealpha1_PL'] = ealpha1_PL

	alpha2_PL = res_fit['alpha2_PL'].values
	o = np.where(alpha2_PL == -98.)[0]
	alpha2_PL[o] = -99.
	alpha2_PL = np.round(alpha2_PL,3)
	res_fit['alpha2_PL'] = alpha2_PL

	ealpha2_PL = res_fit['ealpha2_PL'].values
	ealpha2_PL = np.round(ealpha2_PL,3)
	res_fit['ealpha2_PL'] = ealpha2_PL

	logNorm_Si11 = res_fit['logNorm_Si11'].values
	o = np.where(logNorm_Si11 == -100.)[0]
	logNorm_Si11[o] = -99.
	logNorm_Si11 = np.round(logNorm_Si11,3)
	res_fit['logNorm_Si11'] = logNorm_Si11

	elogNorm_Si11 = res_fit['elogNorm_Si11'].values
	elogNorm_Si11 = np.round(elogNorm_Si11,3)
	res_fit['elogNorm_Si11'] = elogNorm_Si11

	logNorm_Si18 = res_fit['logNorm_Si18'].values
	o = np.where(logNorm_Si18 == -100.)[0]
	logNorm_Si18[o] = -99.
	logNorm_Si18 = np.round(logNorm_Si18,3)
	res_fit['logNorm_Si18'] = logNorm_Si18

	elogNorm_Si18 = res_fit['elogNorm_Si18'].values
	elogNorm_Si18 = np.round(elogNorm_Si18,3)
	res_fit['elogNorm_Si18'] = elogNorm_Si18

	Aw = res_fit['Aw'].values
	o = np.where(Aw < 1e-3)[0]
	if len(o > 0.):
		Aw[o] = 0.0
	Aw = np.round(Aw, 3)
	res_fit['Aw'] = Aw

	logl = res_fit['logl']
	logl = np.round(logl,3)
	res_fit['logl'] = logl

	# Generate the final table
	try:
		res_fit['logLumIR_host'] = loglum_hostIR
		res_fit['elogLumIR_host'] = eloglum_hostIR
		res_fit['logLumMIR_host'] = loglum_hostMIR
		res_fit['elogLumMIR_host'] = eloglum_hostMIR
		res_fit['logLumFIR_host'] = loglum_hostFIR
		res_fit['elogLumFIR_host'] = eloglum_hostFIR
		res_fit['logLumIR_AGN'] = loglum_AGNIR
		res_fit['logLumMIR_AGN'] = loglum_AGNMIR
		res_fit['logLumFIR_AGN'] = loglum_AGNFIR
		res_fit['AGNfrac_IR'] = AGNfrac_IR
		res_fit['AGNfrac_MIR'] = AGNfrac_MIR
		res_fit['AGNfrac_FIR'] = AGNfrac_FIR
		res_fit['SFR'] = SFR
		res_fit['eSFR'] = eSFR
		res_fit['wSFR'] = wSFR
		res_fit['ewSFR'] = ewSFR
	except:
		res_fit['logLumIR_host'] = pd.Series(loglum_hostIR, index=res_fit.index)
		res_fit['elogLumIR_host'] = pd.Series(eloglum_hostIR, index=res_fit.index)
		res_fit['logLumMIR_host'] = pd.Series(loglum_hostMIR, index=res_fit.index)
		res_fit['elogLumMIR_host'] = pd.Series(eloglum_hostMIR, index=res_fit.index)
		res_fit['logLumFIR_host'] = pd.Series(loglum_hostFIR, index=res_fit.index)
		res_fit['elogLumFIR_host'] = pd.Series(eloglum_hostFIR, index=res_fit.index)
		res_fit['logLumIR_AGN'] = pd.Series(loglum_AGNIR, index=res_fit.index)
		res_fit['logLumMIR_AGN'] = pd.Series(loglum_AGNMIR, index=res_fit.index)
		res_fit['logLumFIR_AGN'] = pd.Series(loglum_AGNFIR, index=res_fit.index)
		res_fit['AGNfrac_IR'] = pd.Series(AGNfrac_IR, index=res_fit.index)
		res_fit['AGNfrac_MIR'] = pd.Series(AGNfrac_MIR, index=res_fit.index)
		res_fit['AGNfrac_FIR'] = pd.Series(AGNfrac_FIR, index=res_fit.index)
		res_fit['SFR'] = pd.Series(SFR, index=res_fit.index)
		res_fit['eSFR'] = pd.Series(eSFR, index=res_fit.index)
		res_fit['wSFR'] = pd.Series(wSFR, index=res_fit.index)
		res_fit['ewSFR'] = pd.Series(ewSFR, index=res_fit.index)

	# If saveRes is set to True, save the table
	if saveRes == True:
		order = ['tplName', 'AGNon', 'logNormGal_dust', 'elogNormGal_dust', 'logNormGal_PAH','elogNormGal_PAH', 'logNormAGN_PL', 'elogNormAGN_PL', 'lBreak_PL',\
				 'elBreak_PL', 'alpha1_PL', 'ealpha1_PL', 'alpha2_PL', 'ealpha2_PL', 'logNorm_Si11', 'elogNorm_Si11', 'logNorm_Si18', 'elogNorm_Si18',\
				 'logLumIR_host', 'elogLumIR_host', 'logLumMIR_host', 'elogLumMIR_host', 'logLumFIR_host', 'elogLumFIR_host', 'logLumIR_AGN', \
				 'logLumMIR_AGN', 'logLumFIR_AGN', 'AGNfrac_IR', 'AGNfrac_MIR', 'AGNfrac_FIR', 'SFR','eSFR', 'wSFR', 'ewSFR', 'logl', \
				 'Aw', 'tau9p7', 'bestModelFlag']

		res_fit.to_csv(pathTable+sourceName+'_fitRes_spec.csv', index = False, columns = order)

	print('#########################')
	print('# Generating the plots. #')
	print('#########################')
	# Plot all the fits
	wav = np.concatenate([wavSpec, wavPhot])
	flux = np.concatenate([fluxSpec, fluxPhot])
	eflux = np.concatenate([efluxSpec, efluxPhot])
	plotFitSpec(res_fit, wavSpec, fluxSpec, efluxSpec,\
				wavPhot, fluxPhot, efluxPhot,\
				UL = ULPhot, pathFig = pathFig, sourceName = sourceName, \
				templ = templ, z = z, saveRes = saveRes)

	# Select the best model
	o = np.where(res_fit['bestModelFlag'] == 1)[0]
	res_fitBM = res_fit.iloc[o]

	return res_fit, res_fitBM

def fitPhoto(wav, flux, eflux,\
			 filters, \
			 z = -0.01,\
			 UL = [], \
			 Nmc = 10000, pgrbar = 1, \
			 NoSiem = False, \
			 Pdust = [10., 3.], PPAH = [9., 3.], PnormAGN = [10., 3.], PSiEm = [10., 3.], \
			 sourceName = 'NoName', pathTable = './', pathFig = './', \
			 redoFit = True, saveRes = True, \
			 NOAGN = False):

	"""
    This function fits the observed photometric SED.
    ------------
    :param wav: observed wavelengths (in microns).
    :param fluxSpec: observed fluxes (in Jansky).
    :param efluxSpec: observed uncertainties on the fluxes (in Jansky).
    :param filters: name of the photometric filters to include in the fit.
    ------------
    :keyword z: redshift of the source. Default = 0.01.
    :keyword UL: vector of length Nphot, where Nphot is the number of photometric data. If any of the value is set to 1, the corresponding flux is set has an upper limit in the fit. Default = [].
    :keyword Nmc: numer of MCMC run. Default = 10000.
    :keyword pgrbar: if set to 1, display a progress bar while fitting the SED. Default = 1.
	:keyword NoSiem: if set to True, no silicate emission template is included in the fit. Default = False.
    :keyword Pdust: normal prior on the log-normalisation of the galaxy dust continuum template. Default = [10., 3.] ([mean, std dev]).
    :keyword PPAH: normal prior on the log-normalisation of the PAH template. Default = [9., 3.] ([mean, std dev]).
    :keyword PnormAGN: normal prior on the log-normalisation of the AGN template. Default = [10., 3.] ([mean, std dev]).
    :keyword PSiem: normal prior on the log-normalisation of the silicate emission template. Default = [10., 3.] ([mean, std dev]).
    :keyword sourceName: name of the source. Default = 'NoName'.
	:keyword pathTable: if saveRes is set to True, the tables containing the results of the fits will be saved at the location pathTable. Default = './'.
	:keyword pathFig: if saveRes is set to True, the figues showing the results of the fits will be saved at the location pathFig. Default = './'.
	:keyword redoFit: if set to True, re-performs the fits. Otherwise, find the table saved at pathTable and reproduces the analysis and the figures only. Default = True.
	:keyword saveRes: if set to True, the tables containing the results of the fits as well as the figures are saved. Default = True.
	:keyword NOAGN: if set to True, fits are ran with SF templates only (i.e. no AGN emission is accounted for). Default = False.
	------------
    :return res_fit: dataframe containing the results of all the possible fits.
    :return res_fitBM: dataframe containing the results of the best fit only.
    """

	# test if the path for the tables exists. If not, raise ValueError, crash.
	if pathTable.endswith('/') == False:
		pathTable = pathTable+'/'	
	if os.path.isdir(pathTable) == False:
		raise ValueError('The path specified to save the tables does not exist. Please create it.')

	# test if the path for the figures exists. If not, raise ValueError, crash.
	if pathFig.endswith('/') == False:
		pathFig = pathFig+'/'	
	if os.path.isdir(pathFig) == False:
		raise ValueError('The path specified to save the figures does not exist. Please create it.')

	# test on the length of upper limits.
	if (len(UL)>0) & (len(UL) != len(wav)):
		raise ValueError('UPPER LIMITS: The length of the vector for the upper limits passed to fitPhoto does not match that of the number of photometric points.')		

	# if no UL vector is passed, then defined a vector of zeros
	if len(UL) != len(wav):
		UL = np.zeros(len(wav))

	# test if any of the photometry is detected:
	# if less than 3 photometry is used, or that only UL are defined, remove the AGN contribution (i.e. SF only).
	o = np.where(UL == 0.)[0]
	if (len(wav) < 3.) | (len(o) == 0.):
		NOAGN = True
		NoSiem = True
		
	# Test if any FIR data are included (rest wavelength > 50 microns). If not AGN contribution removed.
	o = np.where(wav/(1.+z) > 50.)[0]
	if len(o) == 0.:
		NOAGN = True
		NoSiem = True

	# if the AGN contribution is included run some basic tests.
	if NOAGN != True:
		# run basic tests to avoid crashing while fitting (see func.py file).
		basictests([], [], [], wav, flux, eflux, filters, z, specOn = False)
	z = abs(z)

	# If no silicate emission template are set for the fit, jump straight to the fit.
	if NoSiem == True:
		pass
	else:
		# If the silicate emission template is considered in the fit, test that there are enough photometric data to constrain it.
		# If not, remove the siliate emission template by setting NoSiem to True, and display a warning.
		SiRange = [int(9.*(1.+z)), int(20.*(1.+z))]
		o = np.where((wav>SiRange[0]) & (wav<SiRange[1]))[0]
		if len(o) == 0.:
			NoSiem = True
			print('The silicate emission template is excluded from the fit due to the lack of data points around the silicate emission features.')
			pass

		o = np.where(wav < 70.)[0]
		if len(o) < 4:
			NoSiem = True
			print('The silicate emission template is excluded from the fit due to the lack of data points at shorter wavelengths.')
			pass

	# open the galaxy and AGN templates.
	path = os.path.dirname(iragnsep.__file__)
	templ = pd.read_csv(path+'/iragnsep_templ.csv')

	# If redoFit is set to True, re-performs the fits. Otherwise, try to open the table results and jump to calculating the IR properties and plotting the results.
	if redoFit == True:
		# run the SED fit (see SEDanalysis.py file).
		res_fit = runSEDphotFit(wav, flux, eflux,\
								z = z,\
								filters = filters, \
								UL = UL, \
								Nmc = Nmc, pgrbar = pgrbar, \
								NoSiem = NoSiem, \
								Pdust = Pdust, PPAH = PPAH, PnormAGN = PnormAGN, PSiEm = PSiEm,\
								templ = templ, \
								NOAGN = NOAGN)
	else:
		try:
			# If redoFit is not set to True, attempt to open the table containing the results of the fits. If failed, raise ValueError, crash.
			res_fit = pd.read_csv(pathTable+sourceName+'_fitRes_photo.csv')
		except:
			raise ValueError('Cannot find the table. Check the name or redo the fit.')

	# define a general uncertainties on the fluxes to pass to "get_prop" to calculate the uncertainties on the IR properties.
	o = np.where(UL == 0.)[0]
	if len(o) > 0.:
		efluxChar = np.sqrt(np.sum(eflux[o]**2.))/len(eflux[o])/np.mean(flux[o])
	else:
		efluxChar = np.sum(flux*0.1)/len(flux)

	# Calculate the IR properties of the galaxy and the AGN.
	loglum_hostIR, eloglum_hostIR, \
	loglum_hostMIR, eloglum_hostMIR, \
	loglum_hostFIR, eloglum_hostFIR, \
	loglum_AGNIR, loglum_AGNMIR, loglum_AGNFIR, \
	AGNfrac_IR, AGNfrac_MIR, AGNfrac_FIR, SFR, eSFR, wSFR, ewSFR = get_prop(res_fit,efluxChar, templ = templ, z = z, specOn = False)

	# Set default values to -99. for the final table.
	logNormGal_dust = res_fit['logNormGal_dust'].values
	logNormGal_dust = np.round(logNormGal_dust,3)
	res_fit['logNormGal_dust'] = logNormGal_dust

	elogNormGal_dust = res_fit['elogNormGal_dust'].values
	elogNormGal_dust = np.round(elogNormGal_dust,3)
	res_fit['elogNormGal_dust'] = elogNormGal_dust

	logNormGal_PAH = res_fit['logNormGal_PAH'].values
	o = np.where(logNormGal_PAH == -11.)[0]
	logNormGal_PAH[o] = -99.
	logNormGal_PAH = np.round(logNormGal_PAH,3)
	res_fit['logNormGal_PAH'] = logNormGal_PAH

	elogNormGal_PAH = res_fit['elogNormGal_PAH'].values
	o = np.where(elogNormGal_PAH == 0.)[0]
	elogNormGal_PAH[o] = -99.
	elogNormGal_PAH = np.round(elogNormGal_PAH,3)
	res_fit['elogNormGal_PAH'] = elogNormGal_PAH

	logNormAGN = res_fit['logNormAGN'].values
	o = np.where(logNormAGN == -89.)[0]
	logNormAGN[o] = -99.
	logNormAGN = np.round(logNormAGN,3)
	res_fit['logNormAGN'] = logNormAGN

	elogNormAGN = res_fit['elogNormAGN'].values
	elogNormAGN = np.round(elogNormAGN,3)
	res_fit['elogNormAGN'] = elogNormAGN

	logNormSiem = res_fit['logNormSiem'].values
	o = np.where(logNormSiem == -89.)[0]
	logNormSiem[o] = -99.
	o = np.where(logNormSiem == -10.)[0]
	logNormSiem[o] = -99.
	logNormSiem = np.round(logNormSiem,3)
	res_fit['logNormSiem'] = logNormSiem

	elogNormSiem = res_fit['elogNormSiem'].values
	o = np.where(elogNormSiem == 0.)[0]
	elogNormSiem[o] = -99.
	elogNormSiem = np.round(elogNormSiem,3)
	res_fit['elogNormSiem'] = elogNormSiem

	Aw = res_fit['Aw'].values
	o = np.where(Aw < 1e-3)[0]
	Aw[o] = 0.0
	Aw = np.round(Aw, 3)
	res_fit['Aw'] = Aw

	# Generate the final table
	try:
		res_fit['logLumIR_host'] = loglum_hostIR
		res_fit['elogLumIR_host'] = eloglum_hostIR
		res_fit['logLumMIR_host'] = loglum_hostMIR
		res_fit['elogLumMIR_host'] = eloglum_hostMIR
		res_fit['logLumFIR_host'] = loglum_hostFIR
		res_fit['elogLumFIR_host'] = eloglum_hostFIR
		res_fit['logLumIR_AGN'] = loglum_AGNIR
		res_fit['logLumMIR_AGN'] = loglum_AGNMIR
		res_fit['logLumFIR_AGN'] = loglum_AGNFIR
		res_fit['AGNfrac_IR'] = AGNfrac_IR
		res_fit['AGNfrac_MIR'] = AGNfrac_MIR
		res_fit['AGNfrac_FIR'] = AGNfrac_FIR
		res_fit['SFR'] = SFR
		res_fit['eSFR'] = eSFR
		res_fit['wSFR'] = wSFR
		res_fit['ewSFR'] = ewSFR
		# res_fit['QF'] = QF
	except:
		res_fit['logLumIR_host'] = pd.Series(loglum_hostIR, index=res_fit.index)
		res_fit['elogLumIR_host'] = pd.Series(eloglum_hostIR, index=res_fit.index)
		res_fit['logLumMIR_host'] = pd.Series(loglum_hostMIR, index=res_fit.index)
		res_fit['elogLumMIR_host'] = pd.Series(eloglum_hostMIR, index=res_fit.index)
		res_fit['logLumFIR_host'] = pd.Series(loglum_hostFIR, index=res_fit.index)
		res_fit['elogLumFIR_host'] = pd.Series(eloglum_hostFIR, index=res_fit.index)
		res_fit['logLumIR_AGN'] = pd.Series(loglum_AGNIR, index=res_fit.index)
		res_fit['logLumMIR_AGN'] = pd.Series(loglum_AGNMIR, index=res_fit.index)
		res_fit['logLumFIR_AGN'] = pd.Series(loglum_AGNFIR, index=res_fit.index)
		res_fit['AGNfrac_IR'] = pd.Series(AGNfrac_IR, index=res_fit.index)
		res_fit['AGNfrac_MIR'] = pd.Series(AGNfrac_MIR, index=res_fit.index)
		res_fit['AGNfrac_FIR'] = pd.Series(AGNfrac_FIR, index=res_fit.index)
		res_fit['SFR'] = pd.Series(SFR, index=res_fit.index)
		res_fit['eSFR'] = pd.Series(eSFR, index=res_fit.index)
		res_fit['wSFR'] = pd.Series(wSFR, index=res_fit.index)
		res_fit['ewSFR'] = pd.Series(ewSFR, index=res_fit.index)
		# res_fit['QF'] = pd.Series(QF, index=res_fit.index)

	# If saveRes is set to True, save the table
	if saveRes == True:
		order = ['tplName_gal', 'AGNon', 'tplName_AGN', 'logNormGal_dust', 'elogNormGal_dust', 'logNormGal_PAH','elogNormGal_PAH', 'logNormAGN', 'elogNormAGN',\
				 'logNormSiem', 'elogNormSiem', 'logLumIR_host', 'elogLumIR_host', 'logLumMIR_host', 'elogLumMIR_host', 'logLumFIR_host', \
				 'elogLumFIR_host', 'logLumIR_AGN', 'logLumMIR_AGN', 'logLumFIR_AGN', 'AGNfrac_IR', 'AGNfrac_MIR', 'AGNfrac_FIR', 'SFR','eSFR', \
				 'wSFR', 'ewSFR', 'logl', 'Aw', 'bestModelFlag']
		res_fit.to_csv(pathTable+sourceName+'_fitRes_photo.csv', index = False, columns = order)

	print('#########################')
	print('# Generating the plots. #')
	print('#########################')
	# Plot all the fits
	plotFitPhoto(res_fit, wav, flux, eflux, UL = UL, pathFig = pathFig, sourceName = sourceName, templ = templ, z = z, saveRes = saveRes, NOAGN = NOAGN)

	# Select the best model
	o = np.where(res_fit['bestModelFlag'] == 1)[0]
	res_fitBM = res_fit.iloc[o]

	return res_fit, res_fitBM


