import os
import numpy as np,sys,matplotlib.pyplot as plt,time,logging,matplotlib,json,urllib.request,glob
from casatools import msmetadata,table,measures,quanta,agentflagger,image,calibrater,ms
from casatasks import *
from paircarstools.access_ms import *
from paircarstools.basic_func import *
from paircarstools.intensity_selfcal_LTS import *
from paircarstools.flagger import *
from optparse import OptionParser
from astropy.io import fits
from astropy import wcs
from paircarstools.libpaircars import send_paircars_notification
matplotlib.use('Agg')
os.system('rm -rf casa*log')

'''
Code is written by Devojyoti Kansabanik, 07 Mar, 2021
'''
global logger
formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s',datefmt='%Y-%m-%d %H:%M:%S')
logger = logging.getLogger('bandpass_selfcal_log')
logger.setLevel(logging.DEBUG)


def init_logger_console(working_dir='',verbose=False):
	'''
	Initial logger
	Parameters
	----------
	working_dir : str
		Name of the working directory
	verbose : bool
		Verbose output or not
	'''
	if verbose==True:
		console=logging.StreamHandler(sys.stdout)
		console.setFormatter(formatter)
		logger.addHandler(console)
	if working_dir!='':	
		filehandle=logging.FileHandler(working_dir+'/Bandpass_Selfcal.log')
		filehandle.setFormatter(formatter)
		logger.addHandler(filehandle)
	logger.propagate = False
	return


# This part will run the self calibration loops. If the code is imported in some other python code, this part will not be executed

def run_bandpass_selfcal(msname,metafits,working_dir,verbose=False,start_fresh=True,caltables=[],use_wsclean=True,perform_fluxcal=False,use_cubical=False,selfcal_input_file='',num_cpus=3):
	'''
	Heart of the bandpass self calibration part of the PAIRCARS
	This function performs the bandpass selfcal for PAIRCARS
	This script can be run directly from python IDE or can be imported to other scripts.
	Here some functionalities are chosen specific to MWA solar imaging. Which may not be valid for other instruments and imaging of other sources.
	Use this module only for Solar Imaging with MWA.
	Parameters
	----------
	msname : str 
		Name of the measurement set
	metafits : str 
		Name of the metafits fil
	working_dir : str 
		Name of the working directory
	verbose : bool 
		If True keep all intermediate selfcal records
	start_fresh : bool
		Start fresh selfcal rounds from scratch or start from last round
	caltables : str 
		Previous caltables, comma separated
	use_wsclean : bool 
		Use WSClean for imaging or not
	perform_fluxcal : bool
		Perform flux calibration or not
	selfcal_input_file : str
		Selfcal input file
	num_cpus : int
		Number of CPUs to use
	Returns
	--------
	int
		Suucess/Error message code
	'''
	start_time=time.time()

	if working_dir[-1]=='/':
		working_dir=working_dir[:-1]
	if os.path.isfile(selfcal_input_file)==False:
		print ('Input file does not exist.\n')
		return 'noinput'
	else:
		sys.path.append(os.path.dirname(selfcal_input_file))
		import selfcal_inputs as inputs

	cwd=os.getcwd()

	os.chdir(msname)
	mspath=os.path.dirname(os.path.realpath(os.getcwd()))
	os.chdir(cwd)
	
	if mspath[-1]=='/':
		mspath=mspath[:-1] 

	if mspath!=working_dir:
		if os.path.isdir(working_dir+'/'+os.path.basename(msname)):
			os.system('rm -rf '+working_dir+'/'+os.path.basename(msname))
		os.system('mv '+msname+' '+working_dir)
		msname=working_dir+'/'+os.path.basename(msname)


	os.chdir(working_dir)
	if start_fresh==False and os.path.isdir('junk1.ms'):
		os.system('rm -rf '+msname)
		os.system('cp -r junk1.ms '+msname)
	else:
		start_fresh=True
		if os.path.isfile('DR_rms.npy')==True:
			os.system('rm -rf DR_rms.npy')
		if os.path.isfile('DR_neg.npy')==True:
			os.system('rm -rf DR_neg.npy')
		if caltables!='':
			try:
				if use_cubical:
					caltable_list=caltables.split(',')
					for i in range(len(caltable_list)):
						if i==0:
							datacolumn='DATA'
						else:
							datacolumn='CORRECTED_DATA'
						cubical_args=['paircars_cubical','--data-ms '+msname,'--out-casa-gaintables 0','--bbc-plot 0','--data-column '+datacolumn,'--flags-save FLAG','--g-xfer-from '\
										+caltable_list[i],'--out-mode ac','--g-clip-low 0','--g-clip-after 0','--g-solvable 0']
						if verbose:
							logger.info(' '.join(cubical_args)+'\n')
						success=os.system(' '.join(cubical_args)+' > tmp')
						if os.path.exists('cubical.cc-out'):
							os.system('rm -rf cubical.cc-out* tmp')
						if success!=0:
							return 15	
					flagdata(vis=msname,mode='clip',clipzeros=True,flagbackup=False)
					tb=table()
					tb.open(msname,nomodify=False)
					cor_data=tb.getcol('CORRECTED_DATA')
					tb.putcol('DATA',cor_data)
					tb.flush()
					tb.close()	
				else:
					caltable_list=caltables.split(',')
					logger.info('Applying solutions from previous calibrations : '+str(caltables)+'\n')
					logger.info('applycal(vis=\''+msname+'\',gaintable='+str(caltable_list)+',applymode=\'calflag\',calwt=[False],flagbackup=True)\n')
					try:
						applycal(vis=msname,gaintable=caltable_list,applymode='calflag',calwt=[True],flagbackup=True)
						tb=table()
						tb.open(msname,nomodify=False)
						cor_data=tb.getcol('CORRECTED_DATA')
						tb.putcol('DATA',cor_data)
						tb.flush()
						tb.close()
						'''logger.info('flagmanager(vis=\''+msname+'\',mode=\'restore\',versionname=\'applycal_1\')\n')
						flagmanager(vis=msname,mode='restore',versionname='applycal_1')
						logger.info('flagmanager(vis=\''+msname+'\',mode=\'delete\',versionname=\'applycal_1\')\n')
						flagmanager(vis=msname,mode='delete',versionname='applycal_1')'''
					except:
						return 15
			except:
				logger.info('Error in applying solutions. Provide correct CASA or CubiCal gaintable for calibration mode cubical = '+str(use_cubical)+'\n')
				if verbose==False:
					print ('Error in applying solutions. Provide correct CASA or CubiCal gaintable for calibration mode cubical = '+str(use_cubical)+'\n')
				return 15
		else:
			caltable_list=[]
		
	if msname[-1]=='/':
		msname=msname[:-1]
	if inputs.basedir[-1]=='/':
		inputs.basedir=inputs.basedir[:-1]
	else:
		inputs.basedir=inputs.basedir

	OBSID=get_OBSID_from_metafits(metafits)
	if 'ref' in msname:
		msname_str=os.path.basename(splited_ms_rename(msname,ref_time_chan=True,change_msname=False))
	else:
		msname_str=os.path.basename(splited_ms_rename(msname,ref_time_chan=False,change_msname=False))
	freqstr=msname_str.split('.ms')[0].split('_freq_')[1].split('_')[0]  # Frequency string in MHz
	datestr_list=msname_str.split('.ms')[0].split('_freq_')[0].split('time_')[1].split('_')
	datestr='/'.join(datestr_list[:3])+'/'+':'.join(datestr_list[3:]) # Datetime string 
	datestrfile='_'.join(datestr_list[:3])+'_'+'_'.join(datestr_list[3:]) # Datetime string for name 

	OBSID=get_OBSID_from_metafits(metafits)
	basemsdir=os.path.dirname(working_dir).split('/')[-1]
	c=0
	while c<=10:
		c+=1
		try:
			if os.path.isdir(inputs.basedir+'/bpcaltables/'+str(OBSID)+'/'+basemsdir)==False: # Directory to keep caltables
				os.makedirs(inputs.basedir+'/bpcaltables/'+str(OBSID)+'/'+basemsdir)
			if os.path.isdir(inputs.basedir+'/bpimagemodels/'+str(OBSID)+'/'+basemsdir)==False: # Directory to keep models
				os.makedirs(inputs.basedir+'/bpimagemodels/'+str(OBSID)+'/'+basemsdir)
			if os.path.isdir(inputs.basedir+'/bpcalms/'+str(OBSID)+'/'+basemsdir)==False: # Directory to keep models
				os.makedirs(inputs.basedir+'/bpcalms/'+str(OBSID)+'/'+basemsdir)
			if os.path.isdir(inputs.basedir+'/logs/'+str(OBSID)+'/'+basemsdir)==False: # Directory to keep models
				os.makedirs(inputs.basedir+'/logs/'+str(OBSID)+'/'+basemsdir)
			if os.path.isdir(inputs.basedir+'/verbose_logs/'+str(OBSID)+'/'+basemsdir)==False and inputs.keep_logger==True and verbose==True:
				os.makedirs(inputs.basedir+'/verbose_logs/'+str(OBSID)+'/'+basemsdir)
			break
		except:
			time.sleep(2.0)
			pass
	
	if 'ref' in msname:
		refcals=glob.glob(inputs.basedir+'/bpcaltables/'+str(OBSID)+'/'+basemsdir+'/*ref*')
		refimages=glob.glob(inputs.basedir+'/bpimagemodels/'+str(OBSID)+'/'+basemsdir+'/*ref*')
		if len(refcals)!=0:
			for i in refcals:
				os.system('rm -rf '+i)
		if len(refimages)!=0:
			for j in refimages:
				os.system('rm -rf '+j)

	if start_fresh==False:
		num_iter,DR1,DR3,DR5,DR2,DR4,DR6,rms_list,calmode,scratch,antenna_list_index,start_sigma,num_iter_fixed_sigma,num_iter_fixed_ant,stokes,startmodel,\
		startmask,uvsub_flag_count,modify_datacolumn,sigma_reduced_count,last_sigma_DR=np.load('Bandpass_selfcal_record.npy',allow_pickle=True)	
	
	scratch=False # For bandpass selfcal scratch is always False, since gain calibration is already applied
	if 'ref' in msname:
		if start_fresh==False:
			logger.info('Restarting selfcal from selfcal round : '+str(num_iter)+'\n')
		logger.info('Starting imaging for Reference time : '+str(datestr)+' and frequency : '+str(freqstr)+' MHz\n')
		logger.info('Scratch = '+str(scratch)+'\n')
		if verbose==False:
			if start_fresh==False:
				print('Restarting selfcal from selfcal round : '+str(num_iter)+'\n')
			print ('Starting imaging for Reference time : '+str(datestr)+' and frequency : '+str(freqstr)+' MHz\n')
			print ('Scratch = '+str(scratch)+'\n')
	else: # For other time and frequency
		if start_fresh==False:
			logger.info('Restarting selfcal from selfcal round : '+str(num_iter)+'\n')
		logger.info('Reference time frequency slice imaging has been done. Starting imaging for time : '+str(datestr)+' and frequency : '+str(freqstr)+' MHz\n')
		logger.info('Scratch = '+str(scratch)+'\n')
		if verbose==False:
			if start_fresh==False:
				print('Restarting selfcal from selfcal round : '+str(num_iter)+'\n')
			print ('Reference time frequency slice imaging has been done. Starting imaging for time : '+str(datestr)+' and frequency : '+str(freqstr)+' MHz\n')
			print ('Scratch = '+str(scratch)+'\n')
	
	if inputs.quality_factor==0:
		num_pixel_in_psf=3
	elif inputs.quality_factor==1:
		num_pixel_in_psf=3
	else:
		num_pixel_in_psf=5

	if os.path.isdir(working_dir+'/Backup_uncalib.ms')==True:
		os.system('rm -rf '+working_dir+'/Backup_uncalib.ms')
	logger.info('split(vis=\''+msname+'\',outputvis=\''+working_dir+'/Backup_uncalib.ms\',datacolumn=\'data\')\n')
	try:
		split(vis=msname,outputvis=working_dir+'/Backup_uncalib.ms',datacolumn='data') # Backup of uncalibrated ms
	except Exception as e:
		logger.info('Split error : '+str(e)+'\n')

	ISC=IntensitySelfcal(msname,metafits,16*60,num_pixel_in_psf=num_pixel_in_psf,largest_scale=20,verbose=verbose,use_wsclean=use_wsclean,savelog=inputs.keep_logger)
																												 # Creating selfcal object 16 arcmin maximum scale size
	AM=AccessMS(msname)
	bandwidth=round((AM.calc_bandwidth()/10**3),2)
	timewidth=round(AM.calc_total_time(),2)
	###################
	# Putting user defined inputs if exisis or go with default values
	###################

	if inputs.calc_image_parameters==False:
		if cellsize!='' and cellsize!='nan':
			ISC.cellsize=inputs.cellsize
		if len(imsize)!=0 and imsize[0]!='nan':
			ISC.imsize=inputs.imsize
		if len(multiscale_scales)!=0 and multiscale_scales[0]!='nan':
			ISC.multiscale_scales=inputs.multiscale_scales
		if uvtaper!='':
			ISC.uvtaper=inputs.uvtaper
		if inputs.weight=='' or (inputs.weight!='uniform' and inputs.weight!='natural' and inputs.weight!='briggs'):
			weight='briggs'
		else:
			weight=inputs.weight
		if inputs.robust<-1.0 or inputs.robust>1.0:
			robust=1.0
		else:
			robust=inputs.robust
	else:
		weight=inputs.weight
		robust=inputs.robust
	
	if inputs.calc_selfcalib_params==False:
		if uvrange_to_cal!='':
			ISC.calib_uvrange=uvrange_to_cal

	end_selfcal=False

	###############################################################
	# Calculating minimum number of iterations and antenna bin size
	###############################################################
	
	min_num_iter_fixed_sigma,min_iteration,max_iteration,antenna_bin,res_flux,min_sigma,frac_flux_change=\
			ISC.calc_iter_num(inputs.safety_factor,inputs.quality_factor,scratch=scratch,bandpass_selfcal=True)

	if inputs.calc_selfcalib_params==False:
		min_sigma=inputs.min_sigma

	logger.info('########################\n')
	logger.info('Estimating the number of selfcal iterations\n')
	logger.info('Minimum number of iteration at fixed sigma : '+str(min_num_iter_fixed_sigma)\
		+'; Minimum number of total selfcal iterations : '+str(min_iteration)+'; Maximum number of selfcal iterations : '+str(max_iteration)\
		+'; Antenna bins : '+str(antenna_bin)+'\n')

	antenna_list,num_ant=AM.make_antenna_list(num_bins=antenna_bin)  # Making the antenna list
	
	###########################
	# Initiating loop variables
	###########################

	if start_fresh:
		stokes='XXYY'
		calmode='ap'
		antenna_list_index=-1
		num_iter=0
		startmodel=''
		startmask=''
		uvsub_flag_count=0
		num_iter_fixed_sigma=0
		num_iter_fixed_ant=0
		modify_datacolumn=False	
		last_sigma_DR=0	
		sigma_reduced_count=0
	else:
		antenna_list_index=antenna_list_index
		num_iter=num_iter
		if os.path.isdir(startmodel):
			startmodel=startmodel
		else:
			startmodel=''
		if os.path.isdir(startmask):
			startmask=startmask
		else:
			startmask=''
		calmode=calmode
		uvsub_flag_count=uvsub_flag_count
		num_iter_fixed_sigma=num_iter_fixed_sigma
		num_iter_fixed_ant=num_iter_fixed_ant
		stokes=stokes
		modify_datacolumn=modify_datacolumn
		last_sigma_DR=last_sigma_DR
		sigma_reduced_count=sigma_reduced_count
	num_iter_after_uvflag=0
	phasecenter_changed=False
	phasecenter_change_done=False
	if inputs.maskstr!='':
		mask_str=inputs.maskstr
	else:
		mask_str=''
	file_str=os.path.basename(msname).split('.ms')[0]

	if scratch==False:
		min_sigma_reduce_count=0
	else:
		if inputs.safety_factor==0:
			min_sigma_reduce_count=1
		elif inputs.safety_factor==1:
			min_sigma_reduce_count=2
		else:
			min_sigma_reduce_count=3

	if os.path.exists(inputs.basedir+'/Ref_time_chan_sigma.npy')==True:
		try:
			start_sigma=np.load(inputs.basedir+'/Ref_time_chan_sigma.npy',allow_pickle=True)[0] # Starting with last gaincal start_sigma and threshold
			if start_sigma>6:
				start_sigma=6  # Perform bandpass calibration at 6 sigma or lower to avoid any missing flux issues
			if min_sigma>6:
				min_sigma=6
			rms_list=np.load(inputs.basedir+'/Ref_time_chan_sigma.npy',allow_pickle=True)[1]
			if len(rms_list)!=2:
				rms_list.append(rms_list[0])
		except:
			try:
				logger.info('Start sigma and threshold information for last intensity selfcal round for reference time channel is not found.'+\
							' Making dirty map to get rms threshold.\n')
				if verbose==False:
					print('Start sigma and threshold information for last intensity selfcal round for reference time channel is not found.'+\
							' Making dirty map to get rms threshold.\n')
				start_sigma=inputs.start_sigma
				msg_code,out_dict,negative_dyn_range,selfcal_snr=ISC.dirty_image(start_sigma,antenna_to_use=ISC.antenna_string(antenna_list,antenna_list_index),\
																	weight=weight,robust=robust)
				ISC.file_remover_and_keeper('dirty',msg_code,do_bandpass=False,ref_time_chan=False)
				if msg_code==0:
					logger.info('Initial selfcal SNR : '+str(selfcal_snr)+'\n')
					try:
						rms_list=[out_dict['I'][1]]
					except:
						rms_list=[out_dict['XX'][1]]
			except:
				logger.info('Start sigma and threshold information for last intensity selfcal round for reference time channel is not found and dirty image making failed.\n')
				if verbose==False:
					print('Start sigma and threshold information for last intensity selfcal round for reference time channel is not found and dirty image making failed.\n')
				os.chdir(cwd)
				touch_file=inputs.basedir+'/.Finished_bcal_'+str(OBSID)+'_'+basemsdir+'_'+os.path.basename(msname)+'_12'
				end_time=time.time()
				run_time=time.strftime('%Hh %Mm %Ss',time.gmtime(end_time-start_time))
				logger.info('Total runtime : '+str(run_time)+'\n')
				msg_str='Dear P-AIRCARS user,\n\nBandpass self-calibration for : '+os.path.basename(msname)+'\nMessage :'+error_msgs(12)+\
						'\nTotal runtime : '+str(run_time)+'\n\nP-AIRCARS'
				msg_subject='Notification from P-AIRCARS : Bandpass Selfcal : OBSID = '+str(OBSID)
				if inputs.send_notification==True:
					sent,send_msg=send_paircars_notification(inputs.email,msg_subject,msg_str,attachments=[])
					if sent==0:
						logger.info('Notification sent successfully.\n')
					else:
						logger.warning('Notification could not be sent.\n')
						logger.warning('Error during sending notification : '+str(send_msg)+'\n')
				os.system('touch '+touch_file)
				os.system('cp -r '+working_dir+'/Bandpass_Selfcal.log '+inputs.basedir+'/logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
				if inputs.keep_logger and verbose==True:
					os.system('cp -r '+working_dir+'/Intensity_Selfcal_verbose.log '+inputs.basedir+'/verbose_logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
				os.system('rm -rf '+working_dir+'/*.log '+working_dir+'/TempLattice*')
				os.system('rm -rf '+working_dir+'/'+file_str+'* '+working_dir+'/cubical.last '+working_dir+'/~*.cal')
				return 12
	else:
		try:
			logger.info('Start sigma and threshold information for last intensity selfcal round for reference time channel is not found.'+\
						' Making dirty map to get rms threshold.\n')
			if verbose==False:
				print('Start sigma and threshold information for last intensity selfcal round for reference time channel is not found.'+\
						' Making dirty map to get rms threshold.\n')
			start_sigma=inputs.start_sigma
			msg_code,out_dict,negative_dyn_range,selfcal_snr=ISC.dirty_image(start_sigma,antenna_to_use=ISC.antenna_string(antenna_list,antenna_list_index),\
																weight=weight,robust=robust)
			ISC.file_remover_and_keeper('dirty',msg_code,do_bandpass=False,ref_time_chan=False)
			if msg_code==0:
				logger.info('Initial selfcal SNR : '+str(selfcal_snr)+'\n')
				try:
					rms_list=[out_dict['I'][1]]
				except:
					rms_list=[out_dict['XX'][1]]
		except:
			logger.info('Start sigma and threshold information for last intensity selfcal round for reference time channel is not found and dirty image making failed.\n')
			if verbose==False:
				print('Start sigma and threshold information for last intensity selfcal round for reference time channel is not found and dirty image making failed.\n')
			os.chdir(cwd)
			touch_file=inputs.basedir+'/.Finished_bcal_'+str(OBSID)+'_'+basemsdir+'_'+os.path.basename(msname)+'_12'
			end_time=time.time()
			run_time=time.strftime('%Hh %Mm %Ss',time.gmtime(end_time-start_time))
			logger.info('Total runtime : '+str(run_time)+'\n')
			msg_str='Dear P-AIRCARS user,\n\nBandpass self-calibration for : '+os.path.basename(msname)+'\nMessage :'+error_msgs(12)+\
					'\nTotal runtime : '+str(run_time)+'\n\nP-AIRCARS'
			msg_subject='Notification from P-AIRCARS : Bandpass Selfcal : OBSID = '+str(OBSID)
			if inputs.send_notification==True:
				sent,send_msg=send_paircars_notification(inputs.email,msg_subject,msg_str,attachments=[])
				if sent==0:
					logger.info('Notification sent successfully.\n')
				else:
					logger.warning('Notification could not be sent.\n')
					logger.warning('Error during sending notification : '+str(send_msg)+'\n')
			os.system('touch '+touch_file)
			os.system('cp -r '+working_dir+'/Bandpass_Selfcal.log '+inputs.basedir+'/logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
			if inputs.keep_logger and verbose==True:
				os.system('cp -r '+working_dir+'/Intensity_Selfcal_verbose.log '+inputs.basedir+'/verbose_logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
			os.system('rm -rf '+working_dir+'/*.log '+working_dir+'/TempLattice*')
			os.system('rm -rf '+working_dir+'/'+file_str+'* '+working_dir+'/cubical.last '+working_dir+'/~*.cal')
			return 12

	if os.path.isdir(working_dir+'/Backup_gaincaled.ms')==True:
		os.system('rm -rf '+working_dir+'/Backup_gaincaled.ms')
	logger.info('split(vis=\''+msname+'\',outputvis=\''+working_dir+'/Backup_gaincaled.ms\',datacolumn=\'data\')\n')
	try:
		split(vis=msname,outputvis=working_dir+'/Backup_gaincaled.ms',datacolumn='data') # Backup of gain calibrated ms
	except Exception as e:
		logger.info('Split error : '+str(e)+'\n')

	while end_selfcal==False:
		##############
		# Selfcal loop
		##############
		if verbose==False:
			print ('#####################\nBandpass Selfcal iteration:'+str(num_iter)+'\n#####################\n')

		if os.path.isdir(startmodel)==False:
			startmodel=''
		if os.path.isdir(startmask)==False:
			startmask=''
		if num_iter>min_iteration:
			if use_cubical:
				calc_flag_frac=calc_flag_fraction_cubical_caltable(working_dir+'/junk1.cal',verbose=verbose)
			else:
				calc_flag_frac=calc_flag_fraction_caltable(working_dir+'/junk1.cal')
			if inputs.safety_factor==0:
				min_cal_frac=0.05
			elif inputs.safety_factor==1:
				min_cal_frac=0.1
			else:
				min_cal_frac=0.15
			if inputs.gain_minsnr>=3.5 and calc_flag_frac>min_cal_frac:
				inputs.gain_minsnr-=0.5
		if perform_fluxcal:
			if num_iter==1:
				do_fluxcal=True
				modify_datacolumnm=True
			else:
				do_fluxcal=False
				modify_datacolumnm=False
		else:
			do_fluxcal=False
			modify_datacolumnm=False
		if inputs.want_auto_masking==True:
			output_ISC=ISC.selfcal_iteration(num_iter,rms_list,start_sigma,mask_str,ISC.antenna_string(antenna_list,antenna_list_index),startmodel,startmask,inputs.ref_ant,\
			inputs.gain_minsnr,calmode,maskfile='',want_auto_masking=inputs.want_auto_masking,stokes=stokes,do_bandpass=True,correct_phasecenter=phasecenter_changed,box_width=3,\
			weight=weight,robust=robust,use_cubical=use_cubical,modify_datacolumn=modify_datacolumnm,restore_flag=True,do_flag=False,do_fluxcal=do_fluxcal,cpus=num_cpus,normtype='median')
		else:
			output_ISC=ISC.selfcal_iteration(num_iter,rms_list,start_sigma,'',ISC.antenna_string(antenna_list,antenna_list_index),startmodel,startmask,inputs.ref_ant,inputs.gain_minsnr,\
			calmode,maskfile='',want_auto_masking=False,stokes=stokes,do_bandpass=True,correct_phasecenter=phasecenter_changed,box_width=3,weight=weight,robust=robust,use_cubical=use_cubical,\
			modify_datacolumn=modify_datacolumn,restore_flag=True,do_flag=False,do_fluxcal=do_fluxcal,cpus=num_cpus,normtype='median')  

		if type(output_ISC)==tuple:				
			msg_code,out_dict,negative_dyn_range=output_ISC
		else:
			msg_code=output_ISC

		if 'ref' in msname:		
			ISC.file_remover_and_keeper(num_iter,msg_code,do_bandpass=True,ref_time_chan=True)  # Removing files and keeping the required ones
		else:
			ISC.file_remover_and_keeper(num_iter,msg_code,do_bandpass=True,ref_time_chan=False)
		if msg_code!=0:
			if verbose==False:
				print (error_msgs(msg_code))
			logger.error(error_msgs(msg_code))
			end_selfcal=True
			if 'ref' in msname:
				os.chdir(cwd)
				touch_file=inputs.basedir+'/.Finished_bcal_'+str(OBSID)+'_'+basemsdir+'_'+os.path.basename(msname)+'_'+str(msg_code+100)
				end_time=time.time()
				run_time=time.strftime('%Hh %Mm %Ss',time.gmtime(end_time-start_time))
				logger.info('Total runtime : '+str(run_time)+'\n')
				msg_str='Dear P-AIRCARS user,\n\nBandpass self-calibration for : '+os.path.basename(msname)+'\nMessage : '+error_msgs(100)+', '+error_msgs(msg_code)\
								+'\nTotal runtime : '+str(run_time)+'\n\nP-AIRCARS'
				msg_subject='Notification from P-AIRCARS : Bandpass Selfcal : OBSID = '+str(OBSID)
				if inputs.send_notification==True:
					sent,send_msg=send_paircars_notification(inputs.email,msg_subject,msg_str,attachments=[])
					if sent==0:
						logger.info('Notification sent successfully.\n')
					else:
						logger.warning('Notification could not be sent.\n')
						logger.warning('Error during sending notification : '+str(send_msg)+'\n')
				os.system('touch '+touch_file)
				os.system('cp -r '+working_dir+'/Bandpass_Selfcal.log '+inputs.basedir+'/logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
				if inputs.keep_logger and verbose==True:
					os.system('cp -r '+working_dir+'/Intensity_Selfcal_verbose.log '+inputs.basedir+'/verbose_logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
				os.system('rm -rf '+working_dir+'/*.log '+working_dir+'/TempLattice*')
				os.system('rm -rf '+working_dir+'/'+file_str+'* '+working_dir+'/cubical.last '+working_dir+'/~*.cal')
				return msg_code+100
			else:
				os.chdir(cwd)
				touch_file=inputs.basedir+'/.Finished_bcal_'+str(OBSID)+'_'+basemsdir+'_'+os.path.basename(msname)+'_'+str(msg_code)
				end_time=time.time()
				run_time=time.strftime('%Hh %Mm %Ss',time.gmtime(end_time-start_time))
				logger.info('Total runtime : '+str(run_time)+'\n')
				msg_str='Dear P-AIRCARS user,\n\nBandpass self-calibration for : '+os.path.basename(msname)+'\nMessage : '+error_msgs(6)+\
						'\nTotal runtime : '+str(run_time)+'\n\nP-AIRCARS'
				msg_subject='Notification from P-AIRCARS : Bandpass Selfcal : OBSID = '+str(OBSID)
				if inputs.send_notification==True:
					sent,send_msg=send_paircars_notification(inputs.email,msg_subject,msg_str,attachments=[])
					if sent==0:
						logger.info('Notification sent successfully.\n')
					else:
						logger.warning('Notification could not be sent.\n')
						logger.warning('Error during sending notification : '+str(send_msg)+'\n')
				os.system('touch '+touch_file)
				os.system('cp -r '+working_dir+'/Bandpass_Selfcal.log '+inputs.basedir+'/logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
				if inputs.keep_logger and verbose==True:
					os.system('cp -r '+working_dir+'/Intensity_Selfcal_verbose.log '+inputs.basedir+'/verbose_logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
				os.system('rm -rf '+working_dir+'/*.log '+working_dir+'/TempLattice*')
				os.system('rm -rf '+working_dir+'/'+file_str+'* '+working_dir+'/cubical.last '+working_dir+'/~*.cal')
				return msg_code
		else:	
			try:
				dyn1=(out_dict['XX'][0]+out_dict['YY'][0])/2.0
				dyn2=negative_dyn_range
				rms_list=[out_dict['XX'][1],out_dict['YY'][1]]
			except:
				dyn1=out_dict['I'][0]
				dyn2=negative_dyn_range
				rms_list=[out_dict['I'][1]]			
			if num_iter==0:
				DR5=DR3=DR1=dyn1
				DR6=DR4=DR2=dyn2
				if os.path.isfile('DR_rms.npy')==False:		
					ISC.DR_record(DR1,'DR_rms',init=True)
				else:
					ISC.DR_record(DR1,'DR_rms',init=False)
				if os.path.isfile('DR_neg.npy')==False:
					ISC.DR_record(DR2,'DR_neg',init=True)
				else:
					ISC.DR_record(DR2,'DR_neg',init=False)
			elif num_iter==1:
				DR5=dyn1
				DR6=dyn2
				ISC.DR_record(dyn1,'DR_rms',init=False)
				ISC.DR_record(dyn2,'DR_neg',init=False)
			else:
				DR1=DR3
				DR3=DR5
				DR5=dyn1
				DR2=DR4
				DR4=DR6 
				DR6=dyn2
				ISC.DR_record(dyn1,'DR_rms',init=False)
				ISC.DR_record(dyn2,'DR_neg',init=False)
			
			if os.path.isfile('Bandpass_selfcal_record.npy'):
				os.system('rm -rf Bandpass_selfcal_record.npy')
			selfcal_record=np.array([num_iter,DR1,DR3,DR5,DR2,DR4,DR6,rms_list,calmode,scratch,antenna_list_index,start_sigma,num_iter_fixed_sigma,num_iter_fixed_ant,stokes,\
				startmodel,startmask,uvsub_flag_count,modify_datacolumn,sigma_reduced_count,last_sigma_DR],dtype='object')
			np.save('Bandpass_selfcal_record',selfcal_record)

			if verbose==False:
				print ('RMS based dynamic ranges:\n')
				print ('Negative based dynamic ranges:\n')
				print(str(DR2)+','+str(DR4)+','+str(DR6)+'\n')
				print ('Calmode : '+calmode+'\n')
				print ('Scartch = '+str(scratch)+'\n')
				print ('Sigma = '+str(start_sigma)+'\n')
			logger.info('RMS based dynamic ranges:\n')
			logger.info(str(DR1)+','+str(DR3)+','+str(DR5)+'\n')
			logger.info('Negative based dynamic ranges:\n')
			logger.info(str(DR2)+','+str(DR4)+','+str(DR6)+'\n')
			logger.info('Calmode : '+calmode+'\n')
			logger.info('Scratch = '+str(scratch)+'\n')
			logger.info('Sigma = '+str(start_sigma)+'\n')

			# Phase center change
			#####################
			'''if num_iter==0:
				ra,dec,phasecenter_changed=ISC.cal_solar_phaseshift('junk0.image',sigma=20)
				logger.info('Phase center changed required : '+str(phasecenter_changed)+'\n')
				if verbose==False:
					print ('Phase center changed required : '+str(phasecenter_changed)+'\n')
				if phasecenter_changed==True:							
					logger.info('New phasecenter : RA = '+str(ra)+' deg, DEC = '+str(dec)+' deg.\n')
				else:
					logger.info('New phasecenter : RA = '+str(ra)+' deg, DEC = '+str(dec)+' deg.\n')
					phasecenter_change_done=True
			if phasecenter_changed==True and phasecenter_change_done==False:
				phasecenter_changed=False
				phasecenter_change_done=True'''

			############
			# If DR decreaes due to flagging, restore the flags
			###########
			if uvsub_flag_count==1 and num_iter_after_uvflag==1:
				if DR5<0.9*DR3 or DR5<0.9*DR1 or DR6<0.85*DR4 or DR6<0.85*DR2:
					DR5=DR3
					DR6=DR4
					flaglist=flagmanager(vis=msname,mode='list')
					logger.info('Present flag versions : \n')
					logger.info(str(flaglist)+'\n')
					flaglist_keys=list(flaglist.keys())
					flaglist_keys.remove('MS')
					for key in flaglist_keys:		
						flagversion=flaglist[key]['name']
						if 'aNKflag' in flagversion or 'uvsub_flag' in flagversion:
							logger.info('flagmanager(vis=\''+msname+'\',mode=\'delete\',versionname=\''+flagversion+'\')\n')
							flagmanager(vis=msname,mode='delete',versionname=flagversion)
						logger.info('flagmanager(vis=\''+msname+'\',mode=\'delete\',versionname=\''+flagversion+'\')\n')
						flagmanager(vis=msname,mode='delete',versionname=flagversion)
					uvsub_flag_count+=1
					continue
				
			############## 
			# If statement 1 (DR decrease)

			if ((DR5<0.85*DR3 and DR5<0.9*DR1 and DR3>DR1) or (DR6<0.75*DR4 and DR6<0.8*DR2 and DR4>DR2) or (DR5<0.9*DR3 and DR1>1.5*DR3) or (DR6<0.8*DR4 and DR2>2*DR4)) \
				and num_iter>min_iteration:
				# If DR decreases.
				# Case 1: If DR decreases less than 90% and 85% of previous two rounds and all antennas are added. This is a check if the rms is diverging. 
				# Case 2: If DR decreases less than 90% of previous round but DR increases more than 1.5 times in last two rounds and no new antennas are added
				if uvsub_flag_count<1 and inputs.want_uvsub_flag==True:
					DR3=DR1
					DR4=DR2
					flaglist=flagmanager(vis=msname,mode='list')
					logger.info('Present flag versions : \n')
					logger.info(str(flaglist)+'\n')
					flaglist_keys=list(flaglist.keys())
					flaglist_keys.remove('MS')
					for key in flaglist_keys:	
						flagversion=flaglist[key]['name']
						logger.info('flagmanager(vis=\''+msname+'\',mode=\'delete\',versionname=\''+flagversion+'\')\n')
						flagmanager(vis=msname,mode='delete',versionname=flagversion)
					AM=AccessMS(msname)
					prev_flag_frac=AM.calc_flagfrac()
					os.system('cp -r '+msname+' '+msname+'.aNKflag.backup')
					if inputs.use_ankflagger:
						try:
							logger.info('Performing uvsub flagging using aNKflagger due to DR decrease.\n')
							logger.info('do_uvsub_ankflag(\''+msname+'\',model=\'junk0.model\',nthread=1,verbose='+str(verbose)+',flagbackup=True,corr=\'XXYY\')\n')
							do_uvsub_ankflag(msname,model='junk0.model',nthread=1,verbose=verbose,flagbackup=False,corr='XXYY')
						except Exception as e:
							os.system('cp -r '+msname+'.aNKflag.backup '+msname)
							logger.error('Error in aNKflagger : '+str(e)+'\n')
							logger.info('Error in running aNKflagger. Using rms threshold based flagging.\n')
							logger.info('Performing uvsub flagging due to DR decrease.\n')
							logger.info('do_uvsub_flagger(\''+msname+'\',model=\'junk0.model\',mode=\'uvsub_flag\',rmsthresh=[10,7,5,3.5],flagbackup=False)\n')
							do_uvsub_flagger(msname,model='junk0.model',mode='uvsub_flag',rmsthresh=[10,7,5,3.5],flagbackup=False)
					else:
						logger.info('Performing uvsub flagging due to DR decrease.\n')
						logger.info('do_uvsub_flagger(\''+msname+'\',model=\'junk0.model\',mode=\'uvsub_flag\',rmsthresh=[10,7,5,3.5],flagbackup=False)\n')
						do_uvsub_flagger(msname,model='junk0.model',mode='uvsub_flag',rmsthresh=[10,7,5,3.5],flagbackup=False)
					uvsub_flag_count+=1
					num_iter_after_uvflag+=1
					os.system('rm -rf junk1.model')
					os.system('cp -r junk0.model junk1.model')
					AM=AccessMS(msname)
					present_flag_frac=AM.calc_flagfrac()
					if ((present_flag_frac-prev_flag_frac)/prev_flag_frac)>0.3:
						os.system('rm -rf '+msname+' '+msname+'.flagversions')
						os.system('cp -r '+msname+'.aNKflag.backup '+msname)
						os.system('rm -rf '+msname+'.aNKflag.backup')
						pass
					else:
						os.system('rm -rf '+msname+'.aNKflag.backup')
						continue
				if DR5>inputs.min_DR and num_iter>min_iteration: # If minimum number of iteration is completed (Only considered the rms based DR here)
					os.system('rm -rf '+file_str+'.cal')
					os.system('rm -rf '+file_str+'_'+str(num_iter)+'.model')
					if use_cubical:
						AM=am.AccessMS(working_dir+'/Backup_uncalib.ms')
						logger.info('ft(vis=\''+working_dir+'/Backup_uncalib.ms\',model=\'junk0.model\',usescratch=True)\n')
						ft(vis=working_dir+'/Backup_uncalib.ms',model='junk0.model',usescratch=True)
						IB=ImageBasic(working_dir+'/Backup_uncalib.ms')
						calib_uvrange=IB.calc_calib_uvrange(20,includeflag=True)
						calib_uvrange_min=calib_uvrange[1]
						calib_uvrange_max=calib_uvrange[2]
						ref_ant_name=AM.get_antenna_name(antenna_id=int(inputs.ref_ant))
						flagdata(vis=msname,mode='clip',clipzeros=True,flagbackup=False)
						tb=table()
						tb.open(msname)
						flag=tb.getcol('FLAG')
						tb.close()
						tb.open(working_dir+'/Backup_uncalib.ms',nomodify=False)
						tb.putcol('FLAG',flag)
						tb.flush()
						tb.close()
						cubical_args=['paircars_cubical','--data-ms '+working_dir+'/Backup_uncalib.ms','--out-casa-gaintables 0','--model-list MODEL_DATA','--bbc-plot 0',\
						'--g-type complex-2x2','--sol-jones g','--data-column DATA','--sol-min-bl '+str(calib_uvrange_min),'--sol-max-bl '+str(calib_uvrange_max),\
						'--flags-save FLAG ','--g-ref-ant '+str(ref_ant_name),'--out-mode so','--g-update-type diag','--g-diag-only 1','--out-overwrite 0','--out-backup 0',\
						'--g-save-to junk1.cal']
						if verbose:
							logger.info(' '.join(cubical_args)+'\n')
						os.system(' '.join(cubical_args)+' > tmp')
						os.system('cp -r cubical.cc-out/cc.stats.pickle junk0.cal.stat')
						if os.path.exists('cubical.cc-out'):
							os.system('rm -rf cubical.cc-out* tmp')
						if perform_fluxcal==False:
							logger.info('normalize_cubical_caltable(\'junk0.cal\',soltype=\'B\',normtype=\'mean\',overwrite=True,verbose='+str(verbose)+')\n')
							final_caltable_name=normalize_cubical_caltable('junk0.cal',soltype='B',normtype='mean',overwrite=True,verbose=verbose)
					else:
						if perform_fluxcal:
							solnorm=False
						else:
							solnorm=True
						logger.info('delmod(vis=\''+working_dir+'/Backup_gaincaled.ms\',scr=True)\n')
						delmod(vis=working_dir+'/Backup_gaincaled.ms',scr=True)
						logger.info('ft(vis=\''+working_dir+'/Backup_gaincaled.ms\',model=\'junk0.model\',usescratch=True)\n')
						ft(vis=working_dir+'/Backup_gaincaled.ms',model='junk0.model',usescratch=True)
						if os.path.exists('junk0.cal'):
							os.system('rm -rf junk0.cal')
						os.system('cp -r '+working_dir+'/Backup_gaincaled.ms '+inputs.basedir+'/bpcalms/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'_'+str(bandwidth)+'kHz_'+str(timewidth)+'s.ms')
						logger.info('bandpass(vis=\''+working_dir+'/Backup_gaincaled.ms\',caltable=\'junk0.cal\',solnorm='+str(solnorm)+',refant=\''+str(inputs.ref_ant)+'\',minsnr='+str(inputs.gain_minsnr)+')\n')
						bandpass(vis=working_dir+'/Backup_gaincaled.ms',caltable='junk0.cal',solnorm=solnorm,refant=str(inputs.ref_ant),minsnr=float(inputs.gain_minsnr))
					if os.path.exists(inputs.basedir+'/bpcaltables/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bcal'):
						os.system('rm -rf '+inputs.basedir+'/bpcaltables/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bcal')
					caltable_name='junk0.cal'
					if do_fluxcal:
						atten=float(fits.getheader(metafits)['ATTEN_DB'])
						logger.info('fluxcal_bptable(\'junk0.cal\',\''+metafits+'\',atten='+str(atten)+')\n')
						caltable_name=fluxcal_bptable('junk0.cal',metafits,atten=atten)
					os.system('cp -r '+caltable_name+' '+inputs.basedir+'/bpcaltables/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bcal')  # Keeping the last good caltable
					os.system('cp -r junk0.model '+inputs.basedir+'/bpimagemodels/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'_'+str(bandwidth)+'kHz_'+str(timewidth)+'s.model') # Keeping last good model
					os.system('cp -r junk0.image '+inputs.basedir+'/bpimagemodels/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'_'+str(bandwidth)+'kHz_'+str(timewidth)+'s.image') # Keeping last good model
					if verbose==False:
						print (error_msgs(8))
					logger.error(error_msgs(8))
					end_selfcal=True
					if inputs.send_notification==True:
						quickimage=get_quicklook_image('junk0.image','quick_image_freq_'+freqstr+'_time_'+datestrfile+'.png',freqstr,datestr,DR3,DR4,field_of_view=3)
					os.system('rm -rf '+working_dir+'/junk*')
					if 'ref' in msname:
						os.chdir(cwd)
						touch_file=inputs.basedir+'/.Finished_bcal_'+str(OBSID)+'_'+basemsdir+'_'+os.path.basename(msname)+'_108'
						end_time=time.time()
						run_time=time.strftime('%Hh %Mm %Ss',time.gmtime(end_time-start_time))
						logger.info('Total runtime : '+str(run_time)+'\n')
						msg_str='Dear P-AIRCARS user,\n\nBandpass self-calibration for : '+os.path.basename(msname)+'\nMessage : '+error_msgs(100)+', '+error_msgs(8)\
							+'\nTotal runtime : '+str(run_time)+'\n\nP-AIRCARS'
						msg_subject='Notification from P-AIRCARS : Bandpass Selfcal : OBSID = '+str(OBSID)
						if inputs.send_notification==True:
							sent,send_msg=send_paircars_notification(inputs.email,msg_subject,msg_str,attachments=[quickimage])
							if sent==0:
								logger.info('Notification sent successfully.\n')
							else:
								logger.warning('Notification could not be sent.\n')
								logger.warning('Error during sending notification : '+str(send_msg)+'\n')
							os.system('rm -rf '+quickimage)
						os.system('touch '+touch_file)
						os.system('cp -r '+working_dir+'/Bandpass_Selfcal.log '+inputs.basedir+'/logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
						if inputs.keep_logger and verbose==True:
							os.system('cp -r '+working_dir+'/Intensity_Selfcal_verbose.log '+inputs.basedir+'/verbose_logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
						os.system('rm -rf '+working_dir+'/*.log '+working_dir+'/TempLattice*')
						os.system('rm -rf '+working_dir+'/'+file_str+'* '+working_dir+'/cubical.last '+working_dir+'/~*.cal')
						return 108
					else:
						os.chdir(cwd)
						touch_file=inputs.basedir+'/.Finished_bcal_'+str(OBSID)+'_'+basemsdir+'_'+os.path.basename(msname)+'_8'
						end_time=time.time()
						run_time=time.strftime('%Hh %Mm %Ss',time.gmtime(end_time-start_time))
						logger.info('Total runtime : '+str(run_time)+'\n')
						msg_str='Dear P-AIRCARS user,\n\nBandpass self-calibration for : '+os.path.basename(msname)+'\nMessage : '+error_msgs(8)+\
								'\nTotal runtime : '+str(run_time)+'\n\nP-AIRCARS'
						msg_subject='Notification from P-AIRCARS : Bandpass Selfcal : OBSID = '+str(OBSID)
						if inputs.send_notification==True:
							sent,send_msg=send_paircars_notification(inputs.email,msg_subject,msg_str,attachments=[quickimage])
							if sent==0:
								logger.info('Notification sent successfully.\n')
							else:
								logger.warning('Notification could not be sent.\n')
								logger.warning('Error during sending notification : '+str(send_msg)+'\n')
							os.system('rm -rf '+quickimage)
						os.system('touch '+touch_file)
						os.system('cp -r '+working_dir+'/Bandpass_Selfcal.log '+inputs.basedir+'/logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
						if inputs.keep_logger and verbose==True:
							os.system('cp -r '+working_dir+'/Intensity_Selfcal_verbose.log '+inputs.basedir+'/verbose_logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
						os.system('rm -rf '+working_dir+'/*.log '+working_dir+'/TempLattice*')
						os.system('rm -rf '+working_dir+'/'+file_str+'* '+working_dir+'/cubical.last '+working_dir+'/~*.cal')
						return 8

			#######################################################
			# If statement 2 (Exiting selfcal conditions)
			if DR5>=inputs.max_DR and num_iter>min_iteration:
				if verbose==False:
					print ('Reached limiting dynamic range\n')
				logger.info('Reached limiting dynamic range\n')
				end_selfcal=True
				if use_cubical:
					AM=am.AccessMS(working_dir+'/Backup_uncalib.ms')
					logger.info('ft(vis=\''+working_dir+'/Backup_uncalib.ms\',model=\'junk1.model\',usescratch=True)\n')
					ft(vis=working_dir+'/Backup_uncalib.ms',model='junk1.model',usescratch=True)
					IB=ImageBasic(working_dir+'/Backup_uncalib.ms')
					calib_uvrange=IB.calc_calib_uvrange(20,includeflag=True)
					calib_uvrange_min=calib_uvrange[1]
					calib_uvrange_max=calib_uvrange[2]
					ref_ant_name=AM.get_antenna_name(antenna_id=int(inputs.ref_ant))
					flagdata(vis=msname,mode='clip',clipzeros=True,flagbackup=False)
					tb=table()
					tb.open(msname)
					flag=tb.getcol('FLAG')
					tb.close()
					tb.open(working_dir+'/Backup_uncalib.ms',nomodify=False)
					tb.putcol('FLAG',flag)
					tb.flush()
					tb.close()
					cubical_args=['paircars_cubical','--data-ms '+working_dir+'/Backup_uncalib.ms','--out-casa-gaintables 0','--model-list MODEL_DATA','--bbc-plot 0',\
					'--g-type complex-2x2','--sol-jones g','--data-column DATA','--sol-min-bl '+str(calib_uvrange_min),'--sol-max-bl '+str(calib_uvrange_max),\
					'--flags-save FLAG ','--g-ref-ant '+str(ref_ant_name),'--out-mode so','--g-update-type diag','--g-diag-only 1','--out-overwrite 0','--out-backup 0',\
					'--g-save-to junk1.cal']
					if verbose:
						logger.info(' '.join(cubical_args)+'\n')
					os.system(' '.join(cubical_args)+' > tmp')
					os.system('cp -r cubical.cc-out/cc.stats.pickle junk1.cal.stat')
					if os.path.exists('cubical.cc-out'):
						os.system('rm -rf cubical.cc-out* tmp')
					if perform_fluxcal==False:
						logger.info('normalize_cubical_caltable(\'junk1.cal\',soltype=\'B\',normtype=\'mean\',overwrite=True,verbose='+str(verbose)+')\n')
						final_caltable_name=normalize_cubical_caltable('junk1.cal',soltype='B',normtype='mean',overwrite=True,verbose=verbose)
				else:
					if perform_fluxcal:
						solnorm=False
					else:
						solnorm=True
					logger.info('delmod(vis=\''+working_dir+'/Backup_gaincaled.ms\',scr=True)\n')
					delmod(vis=working_dir+'/Backup_gaincaled.ms',scr=True)
					logger.info('ft(vis=\''+working_dir+'/Backup_gaincaled.ms\',model=\'junk1.model\',usescratch=True)\n')
					ft(vis=working_dir+'/Backup_gaincaled.ms',model='junk1.model',usescratch=True)
					if os.path.exists('junk1.cal'):
						os.system('rm -rf junk1.cal')
					os.system('cp -r '+working_dir+'/Backup_gaincaled.ms '+inputs.basedir+'/bpcalms/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'_'+str(bandwidth)+'kHz_'+str(timewidth)+'s.ms')
					logger.info('bandpass(vis=\''+working_dir+'/Backup_gaincaled.ms\',caltable=\'junk1.cal\',solnorm='+str(solnorm)+',refant=\''+str(inputs.ref_ant)+'\',minsnr='+str(inputs.gain_minsnr)+')\n')
					bandpass(vis=working_dir+'/Backup_gaincaled.ms',caltable='junk1.cal',solnorm=solnorm,refant=str(inputs.ref_ant),minsnr=float(inputs.gain_minsnr))
				if os.path.exists(inputs.basedir+'/bpcaltables/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bcal'):
					os.system('rm -rf '+inputs.basedir+'/bpcaltables/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bcal')
				caltable_name='junk1.cal'
				if do_fluxcal:
					atten=float(fits.getheader(metafits)['ATTEN_DB'])
					logger.info('fluxcal_bptable(\'junk0.cal\',\''+metafits+'\',atten='+str(atten)+')\n')
					caltable_name=fluxcal_bptable('junk0.cal',metafits,atten=atten)
				os.system('cp -r '+caltable_name+' '+inputs.basedir+'/bpcaltables/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bcal')  # Keeping the last good caltable
				os.system('cp -r junk1.model '+inputs.basedir+'/bpimagemodels/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'_'+str(bandwidth)+'kHz_'+str(timewidth)+'s.model')
				os.system('cp -r junk1.image '+inputs.basedir+'/bpimagemodels/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'_'+str(bandwidth)+'kHz_'+str(timewidth)+'s.image')
				if inputs.send_notification==True:
					quickimage=get_quicklook_image('junk1.image','quick_image_freq_'+freqstr+'_time_'+datestrfile+'.png',freqstr,datestr,DR5,DR6,field_of_view=3)
				os.system('rm -rf '+working_dir+'/junk*')
				os.chdir(cwd)
				touch_file=inputs.basedir+'/.Finished_bcal_'+str(OBSID)+'_'+basemsdir+'_'+os.path.basename(msname)+'_0'
				end_time=time.time()
				run_time=time.strftime('%Hh %Mm %Ss',time.gmtime(end_time-start_time))
				logger.info('Total runtime : '+str(run_time)+'\n')
				msg_str='Dear P-AIRCARS user,\n\nBandpass self-calibration for : '+os.path.basename(msname)+'\nMessage : '+error_msgs(0)+\
						'\nTotal runtime : '+str(run_time)+'\n\nP-AIRCARS'
				msg_subject='Notification from P-AIRCARS : Bandpass Selfcal : OBSID = '+str(OBSID)
				if inputs.send_notification==True:
					sent,send_msg=send_paircars_notification(inputs.email,msg_subject,msg_str,attachments=[quickimage])
					if sent==0:
						logger.info('Notification sent successfully.\n')
					else:
						logger.warning('Notification could not be sent.\n')
						logger.warning('Error during sending notification : '+str(send_msg)+'\n')
					os.system('rm -rf '+quickimage)
				os.system('touch '+touch_file)
				os.system('cp -r '+working_dir+'/Bandpass_Selfcal.log '+inputs.basedir+'/logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
				if inputs.keep_logger and verbose==True:
					os.system('cp -r '+working_dir+'/Intensity_Selfcal_verbose.log '+inputs.basedir+'/verbose_logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
				os.system('rm -rf '+working_dir+'/*.log '+working_dir+'/TempLattice*')
				os.system('rm -rf '+working_dir+'/'+file_str+'* '+working_dir+'/cubical.last '+working_dir+'/~*.cal')
				return 0
			elif num_iter_fixed_sigma>=min_num_iter_fixed_sigma and (np.nanmedian([np.nanmedian([DR1,DR3]),DR5])-last_sigma_DR)<(0.1*inputs.DR_delta) and \
					sigma_reduced_count>=min_sigma_reduce_count:
				if start_sigma<=6 and uvsub_flag_count<1 and inputs.want_uvsub_flag==True:
					DR3=DR1
					DR4=DR2
					flaglist=flagmanager(vis=msname,mode='list')
					logger.info('Present flag versions : \n')
					logger.info(str(flaglist)+'\n')
					flaglist_keys=list(flaglist.keys())
					flaglist_keys.remove('MS')
					for key in flaglist_keys:	
						flagversion=flaglist[key]['name']
						logger.info('flagmanager(vis=\''+msname+'\',mode=\'delete\',versionname=\''+flagversion+'\')\n')
						flagmanager(vis=msname,mode='delete',versionname=flagversion)
					AM=AccessMS(msname)
					prev_flag_frac=AM.calc_flagfrac()
					os.system('cp -r '+msname+' '+msname+'.aNKflag.backup')
					if inputs.use_ankflagger:
						try:
							logger.info('Performing uvsub flagging using aNKflagger as selfcal converged.\n')
							logger.info('do_uvsub_ankflag(\''+msname+'\',model=\'junk1.model\',nthread=1,verbose='+str(verbose)+',flagbackup=False,corr=\'XXYY\')\n')
							do_uvsub_ankflag(msname,model='junk1.model',nthread=1,verbose=verbose,flagbackup=False,corr='XXYY')
						except Exception as e:
							os.system('cp -r '+msname+'.aNKflag.backup '+msname)
							logger.error('Error in aNKflagger : '+str(e)+'\n')
							logger.info('Error in running aNKflagger. Using rms threshold based flagging.\n')
							logger.info('Performing uvsub flagging using aNKflagger as selfcal converged.\n')
							logger.info('do_uvsub_flagger(\''+msname+'\',model=\'junk1.model\',mode=\'uvsub_flag\',rmsthresh=[10,7,5,3.5],flagbackup=False)\n')
							do_uvsub_flagger(msname,model='junk1.model',mode='uvsub_flag',rmsthresh=[10,7,5,3.5],flagbackup=False)
					else:
						logger.info('Performing uvsub flagging using aNKflagger as selfcal converged.\n')
						logger.info('do_uvsub_flagger(\''+msname+'\',model=\'junk1.model\',mode=\'uvsub_flag\',rmsthresh=[10,7,5,3.5],flagbackup=False)\n')
						do_uvsub_flagger(msname,model='junk1.model',mode='uvsub_flag',rmsthresh=[10,7,5,3.5],flagbackup=False)
					uvsub_flag_count+=1
					num_iter_after_uvflag+=1
					AM=AccessMS(msname)
					present_flag_frac=AM.calc_flagfrac()
					if ((present_flag_frac-prev_flag_frac)/prev_flag_frac)>0.1:
						os.system('rm -rf '+msname+' '+msname+'.flagversions')
						os.system('cp -r '+msname+'.aNKflag.backup '+msname)
						os.system('rm -rf '+msname+'.aNKflag.backup')
						pass
					else:
						os.system('rm -rf '+msname+'.aNKflag.backup')
						continue
				if verbose==False:
					print ('#################\nSelfcal converged. Dynamic range does not increase by reducing sigma. Stopped sigma : '+\
							str(start_sigma)+'\n##################\n') 	
				logger.info('########################\n')							
				logger.info('Selfcal converged. Dynamic range does not increase by reducing sigma. Stopped sigma : '+str(start_sigma)+'\n')	
				logger.info('########################\n')									
				end_selfcal=True
				if use_cubical:
					AM=am.AccessMS(working_dir+'/Backup_uncalib.ms')
					logger.info('ft(vis=\''+working_dir+'/Backup_uncalib.ms\',model=\'junk1.model\',usescratch=True)\n')
					ft(vis=working_dir+'/Backup_uncalib.ms',model='junk1.model',usescratch=True)
					IB=ImageBasic(working_dir+'/Backup_uncalib.ms')
					calib_uvrange=IB.calc_calib_uvrange(20,includeflag=True)
					calib_uvrange_min=calib_uvrange[1]
					calib_uvrange_max=calib_uvrange[2]
					ref_ant_name=AM.get_antenna_name(antenna_id=int(inputs.ref_ant))
					flagdata(vis=msname,mode='clip',clipzeros=True,flagbackup=False)
					tb=table()
					tb.open(msname)
					flag=tb.getcol('FLAG')
					tb.close()
					tb.open(working_dir+'/Backup_uncalib.ms',nomodify=False)
					tb.putcol('FLAG',flag)
					tb.flush()
					tb.close()
					cubical_args=['paircars_cubical','--data-ms '+working_dir+'/Backup_uncalib.ms','--out-casa-gaintables 0','--model-list MODEL_DATA','--bbc-plot 0',\
					'--g-type complex-2x2','--sol-jones g','--data-column DATA','--sol-min-bl '+str(calib_uvrange_min),'--sol-max-bl '+str(calib_uvrange_max),\
					'--flags-save FLAG ','--g-ref-ant '+str(ref_ant_name),'--out-mode so','--g-update-type diag','--g-diag-only 1','--out-overwrite 0','--out-backup 0',\
					'--g-save-to junk1.cal']
					if verbose:
						logger.info(' '.join(cubical_args)+'\n')
					os.system(' '.join(cubical_args)+' > tmp')
					os.system('cp -r cubical.cc-out/cc.stats.pickle junk1.cal.stat')
					if os.path.exists('cubical.cc-out'):
						os.system('rm -rf cubical.cc-out* tmp')
					if perform_fluxcal==False:
						logger.info('normalize_cubical_caltable(\'junk1.cal\',soltype=\'B\',normtype=\'mean\',overwrite=True,verbose='+str(verbose)+')\n')
						final_caltable_name=normalize_cubical_caltable('junk1.cal',soltype='B',normtype='mean',overwrite=True,verbose=verbose)
				else:
					if perform_fluxcal:
						solnorm=False
					else:
						solnorm=True
					logger.info('delmod(vis=\''+working_dir+'/Backup_gaincaled.ms\',scr=True)\n')
					delmod(vis=working_dir+'/Backup_gaincaled.ms',scr=True)
					logger.info('ft(vis=\''+working_dir+'/Backup_gaincaled.ms\',model=\'junk1.model\',usescratch=True)\n')
					ft(vis=working_dir+'/Backup_gaincaled.ms',model='junk1.model',usescratch=True)
					if os.path.exists('junk1.cal'):
						os.system('rm -rf junk1.cal')
					os.system('cp -r '+working_dir+'/Backup_gaincaled.ms '+inputs.basedir+'/bpcalms/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'_'+str(bandwidth)+'kHz_'+str(timewidth)+'s.ms')
					logger.info('bandpass(vis=\''+working_dir+'/Backup_gaincaled.ms\',caltable=\'junk1.cal\',solnorm='+str(solnorm)+',refant=\''+str(inputs.ref_ant)+'\',minsnr='+str(inputs.gain_minsnr)+')\n')
					bandpass(vis=working_dir+'/Backup_gaincaled.ms',caltable='junk1.cal',solnorm=solnorm,refant=str(inputs.ref_ant),minsnr=float(inputs.gain_minsnr))
				if os.path.exists(inputs.basedir+'/bpcaltables/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bcal'):
					os.system('rm -rf '+inputs.basedir+'/bpcaltables/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bcal')
				caltable_name='junk1.cal'
				if do_fluxcal:
					atten=float(fits.getheader(metafits)['ATTEN_DB'])
					logger.info('fluxcal_bptable(\'junk0.cal\',\''+metafits+'\',atten='+str(atten)+')\n')
					caltable_name=fluxcal_bptable('junk0.cal',metafits,atten=atten)
				os.system('cp -r '+caltable_name+' '+inputs.basedir+'/bpcaltables/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bcal')  # Keeping the last good caltable
				os.system('cp -r junk1.model '+inputs.basedir+'/bpimagemodels/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'_'+str(bandwidth)+'kHz_'+str(timewidth)+'s.model')
				os.system('cp -r junk1.image '+inputs.basedir+'/bpimagemodels/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'_'+str(bandwidth)+'kHz_'+str(timewidth)+'s.image')
				if inputs.send_notification==True:
					quickimage=get_quicklook_image('junk1.image','quick_image_freq_'+freqstr+'_time_'+datestrfile+'.png',freqstr,datestr,DR5,DR6,field_of_view=3)
				os.system('rm -rf '+working_dir+'/junk*') 
				os.chdir(cwd)
				touch_file=inputs.basedir+'/.Finished_bcal_'+str(OBSID)+'_'+basemsdir+'_'+os.path.basename(msname)+'_0'
				end_time=time.time()
				run_time=time.strftime('%Hh %Mm %Ss',time.gmtime(end_time-start_time))
				logger.info('Total runtime : '+str(run_time)+'\n')
				msg_str='Dear P-AIRCARS user,\n\nBandpass self-calibration for : '+os.path.basename(msname)+'\nMessage : '+error_msgs(0)+\
						'\nTotal runtime : '+str(run_time)+'\n\nP-AIRCARS'
				msg_subject='Notification from P-AIRCARS : Bandpass Selfcal : OBSID = '+str(OBSID)
				if inputs.send_notification==True:
					sent,send_msg=send_paircars_notification(inputs.email,msg_subject,msg_str,attachments=[quickimage])
					if sent==0:
						logger.info('Notification sent successfully.\n')
					else:
						logger.warning('Notification could not be sent.\n')
						logger.warning('Error during sending notification : '+str(send_msg)+'\n')
					os.system('rm -rf '+quickimage)
				os.system('touch '+touch_file)
				os.system('cp -r '+working_dir+'/Bandpass_Selfcal.log '+inputs.basedir+'/logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
				if inputs.keep_logger and verbose==True:
					os.system('cp -r '+working_dir+'/Intensity_Selfcal_verbose.log '+inputs.basedir+'/verbose_logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
				os.system('rm -rf '+working_dir+'/*.log '+working_dir+'/TempLattice*')
				os.system('rm -rf '+working_dir+'/'+file_str+'* '+working_dir+'/cubical.last '+working_dir+'/~*.cal')
				return 0
			elif (abs(DR5-DR3)<inputs.DR_delta and abs(DR5-DR1)<inputs.DR_delta and abs(DR5/DR3-1)<frac_flux_change):
			#  If DR does not increas more the DR delta in last two steps and DR does not increase 8% for rms based and 5% for negative based => Converge
				if (num_iter_fixed_sigma>min_iteration) and num_iter>min_iteration:
					logger.info('Calculating new sigma....\n')
					sigma=ISC.reduce_sigma('junk1.image',start_sigma,inputs.sigma_step,min_sigma,residual_frac=res_flux,stokes_list=['XX','YY'])
					if sigma<start_sigma: # If the next sigma is less than the present sigma
						start_sigma=sigma	
						num_iter_fixed_sigma=0
						logger.info('New sigma : '+str(start_sigma)+'\n')
						sigma_reduced_count+=1
						last_sigma_DR=np.nanmedian([np.nanmedian([DR1,DR3]),DR5])
					elif start_sigma<=6 and uvsub_flag_count<1 and inputs.want_uvsub_flag==True:
						DR3=DR1
						DR4=DR2
						flaglist=flagmanager(vis=msname,mode='list')
						logger.info('Present flag versions : \n')
						logger.info(str(flaglist)+'\n')
						flaglist_keys=list(flaglist.keys())
						flaglist_keys.remove('MS')
						for key in flaglist_keys:	
							flagversion=flaglist[key]['name']
							logger.info('flagmanager(vis=\''+msname+'\',mode=\'delete\',versionname=\''+flagversion+'\')\n')
							flagmanager(vis=msname,mode='delete',versionname=flagversion)
						AM=AccessMS(msname)
						prev_flag_frac=AM.calc_flagfrac()
						os.system('cp -r '+msname+' '+msname+'.aNKflag.backup')
						if inputs.use_ankflagger:
							try:
								logger.info('Performing uvsub flagging using aNKflagger as selfcal converged.\n')
								logger.info('do_uvsub_ankflag(\''+msname+'\',model=\'junk1.model\',nthread=1,verbose='+str(verbose)+',flagbackup=False,corr=\'XXYY\')\n')
								do_uvsub_ankflag(msname,model='junk1.model',nthread=1,verbose=verbose,flagbackup=False,corr='XXYY')
							except Exception as e:
								os.system('cp -r '+msname+'.aNKflag.backup '+msname)
								logger.error('Error in aNKflagger : '+str(e)+'\n')
								logger.info('Error in running aNKflagger. Using rms threshold based flagging.\n')
								logger.info('Performing uvsub flagging using aNKflagger as selfcal converged.\n')
								logger.info('do_uvsub_flagger(\''+msname+'\',model=\'junk1.model\',mode=\'uvsub_flag\',rmsthresh=[10,7,5,3.5],flagbackup=False)\n')
								do_uvsub_flagger(msname,model='junk1.model',mode='uvsub_flag',rmsthresh=[10,7,5,3.5],flagbackup=False)
						else:
							logger.info('Performing uvsub flagging using aNKflagger as selfcal converged.\n')
							logger.info('do_uvsub_flagger(\''+msname+'\',model=\'junk1.model\',mode=\'uvsub_flag\',rmsthresh=[10,7,5,3.5],flagbackup=False)\n')
							do_uvsub_flagger(msname,model='junk1.model',mode='uvsub_flag',rmsthresh=[10,7,5,3.5],flagbackup=False)
						uvsub_flag_count+=1
						num_iter_after_uvflag+=1
						AM=AccessMS(msname)
						present_flag_frac=AM.calc_flagfrac()
						if ((present_flag_frac-prev_flag_frac)/prev_flag_frac)>0.1:
							os.system('rm -rf '+msname+' '+msname+'.flagversions')
							os.system('cp -r '+msname+'.aNKflag.backup '+msname)
							os.system('rm -rf '+msname+'.aNKflag.backup')
							pass
						else:
							os.system('rm -rf '+msname+'.aNKflag.backup')
							continue
					else:
						if verbose==False:
							print ('#################\nSelfcal converged. Residual flux inside the mask is less than : '+\
									str(res_flux*100)+'%. Stopped sigma : '+str(start_sigma)+'\n##################\n') 	
						logger.info('########################\n')							
						logger.info('Selfcal converged. Residual flux inside the mask is less than : '+str(res_flux*100)+'%. Stopped sigma : '+str(start_sigma)+'\n')	
						logger.info('########################\n')								
						end_selfcal=True
						if use_cubical:
							AM=am.AccessMS(working_dir+'/Backup_uncalib.ms')
							logger.info('ft(vis=\''+working_dir+'/Backup_uncalib.ms\',model=\'junk1.model\',usescratch=True)\n')
							ft(vis=working_dir+'/Backup_uncalib.ms',model='junk1.model',usescratch=True)
							IB=ImageBasic(working_dir+'/Backup_uncalib.ms')
							calib_uvrange=IB.calc_calib_uvrange(20,includeflag=True)
							calib_uvrange_min=calib_uvrange[1]
							calib_uvrange_max=calib_uvrange[2]
							ref_ant_name=AM.get_antenna_name(antenna_id=int(inputs.ref_ant))
							flagdata(vis=msname,mode='clip',clipzeros=True,flagbackup=False)
							tb=table()
							tb.open(msname)
							flag=tb.getcol('FLAG')
							tb.close()
							tb.open(working_dir+'/Backup_uncalib.ms',nomodify=False)
							tb.putcol('FLAG',flag)
							tb.flush()
							tb.close()
							cubical_args=['paircars_cubical','--data-ms '+working_dir+'/Backup_uncalib.ms','--out-casa-gaintables 0','--model-list MODEL_DATA','--bbc-plot 0',\
							'--g-type complex-2x2','--sol-jones g','--data-column DATA','--sol-min-bl '+str(calib_uvrange_min),'--sol-max-bl '+str(calib_uvrange_max),\
							'--flags-save FLAG ','--g-ref-ant '+str(ref_ant_name),'--out-mode so','--g-update-type diag','--g-diag-only 1','--out-overwrite 0','--out-backup 0',\
							'--g-save-to junk1.cal']
							if verbose:
								logger.info(' '.join(cubical_args)+'\n')
							os.system(' '.join(cubical_args)+' > tmp')
							os.system('cp -r cubical.cc-out/cc.stats.pickle junk1.cal.stat')
							if os.path.exists('cubical.cc-out'):
								os.system('rm -rf cubical.cc-out* tmp')
							if perform_fluxcal==False:
								logger.info('normalize_cubical_caltable(\'junk1.cal\',soltype=\'B\',normtype=\'mean\',overwrite=True,verbose='+str(verbose)+')\n')
								final_caltable_name=normalize_cubical_caltable('junk1.cal',soltype='B',normtype='mean',overwrite=True,verbose=verbose)
						else:
							if perform_fluxcal:
								solnorm=False
							else:
								solnorm=True
							logger.info('delmod(vis=\''+working_dir+'/Backup_gaincaled.ms\',scr=True)\n')
							delmod(vis=working_dir+'/Backup_gaincaled.ms',scr=True)
							logger.info('ft(vis=\''+working_dir+'/Backup_gaincaled.ms\',model=\'junk1.model\',usescratch=True)\n')
							ft(vis=working_dir+'/Backup_gaincaled.ms',model='junk1.model',usescratch=True)
							if os.path.exists('junk1.cal'):
								os.system('rm -rf junk1.cal')
							os.system('cp -r '+working_dir+'/Backup_gaincaled.ms '+inputs.basedir+'/bpcalms/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'_'+str(bandwidth)+'kHz_'+str(timewidth)+'s.ms')
							logger.info('bandpass(vis=\''+working_dir+'/Backup_gaincaled.ms\',caltable=\'junk1.cal\',solnorm='+str(solnorm)+',refant=\''+str(inputs.ref_ant)+'\',minsnr='+str(inputs.gain_minsnr)+')\n')
							bandpass(vis=working_dir+'/Backup_gaincaled.ms',caltable='junk1.cal',solnorm=solnorm,refant=str(inputs.ref_ant),minsnr=float(inputs.gain_minsnr))
						if os.path.exists(inputs.basedir+'/bpcaltables/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bcal'):
							os.system('rm -rf '+inputs.basedir+'/bpcaltables/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bcal')
						caltable_name='junk1.cal'
						if do_fluxcal:
							atten=float(fits.getheader(metafits)['ATTEN_DB'])
							logger.info('fluxcal_bptable(\'junk0.cal\',\''+metafits+'\',atten='+str(atten)+')\n')
							caltable_name=fluxcal_bptable('junk0.cal',metafits,atten=atten)
						os.system('cp -r '+caltable_name+' '+inputs.basedir+'/bpcaltables/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bcal')  # Keeping the last good caltable
						os.system('cp -r junk1.model '+inputs.basedir+'/bpimagemodels/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'_'+str(bandwidth)+'kHz_'+str(timewidth)+'s.model')
						os.system('cp -r junk1.image '+inputs.basedir+'/bpimagemodels/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'_'+str(bandwidth)+'kHz_'+str(timewidth)+'s.image')
						if inputs.send_notification==True:
							quickimage=get_quicklook_image('junk1.image','quick_image_freq_'+freqstr+'_time_'+datestrfile+'.png',freqstr,datestr,DR5,DR6,field_of_view=3)
						os.system('rm -rf '+working_dir+'/junk*') 
						os.chdir(cwd)
						touch_file=inputs.basedir+'/.Finished_bcal_'+str(OBSID)+'_'+basemsdir+'_'+os.path.basename(msname)+'_0'
						end_time=time.time()
						run_time=time.strftime('%Hh %Mm %Ss',time.gmtime(end_time-start_time))
						logger.info('Total runtime : '+str(run_time)+'\n')
						msg_str='Dear P-AIRCARS user,\n\nBandpass self-calibration for : '+os.path.basename(msname)+'\nMessage : '+error_msgs(0)+\
								'\nTotal runtime : '+str(run_time)+'\n\nP-AIRCARS'
						msg_subject='Notification from P-AIRCARS : Bandpass Selfcal : OBSID = '+str(OBSID)
						if inputs.send_notification==True:
							sent,send_msg=send_paircars_notification(inputs.email,msg_subject,msg_str,attachments=[quickimage])
							if sent==0:
								logger.info('Notification sent successfully.\n')
							else:
								logger.warning('Notification could not be sent.\n')
								logger.warning('Error during sending notification : '+str(send_msg)+'\n')
							os.system('rm -rf '+quickimage)
						os.system('touch '+touch_file)
						os.system('cp -r '+working_dir+'/Bandpass_Selfcal.log '+inputs.basedir+'/logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
						if inputs.keep_logger and verbose==True:
							os.system('cp -r '+working_dir+'/Intensity_Selfcal_verbose.log '+inputs.basedir+'/verbose_logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
						os.system('rm -rf '+working_dir+'/*.log '+working_dir+'/TempLattice*')
						os.system('rm -rf '+working_dir+'/'+file_str+'* '+working_dir+'/cubical.last '+working_dir+'/~*.cal')
						return 0
			
			#############################################################			
			# If statement 3 (Using last round model) 
			#(If DR increases at least DR_delta and all antennas are added and number of iteration at fixed antenna is greater than 5)

			if DR5>DR3 and DR5>DR1 and num_iter>min_iteration:
				startmodel='junk1.model'
			else:
				startmodel=''
			if DR5>DR3 and DR5>DR1:
				startmask='junk1.mask'
			else:
				startmask=''
			num_iter+=1
			num_iter_fixed_sigma+=1
			num_iter_fixed_ant+=1
			if uvsub_flag_count>=1:
				num_iter_after_uvflag+=1
		
			###############################################################
			# If statement 4 (Reached maximum selfcal rounds)
	
			if num_iter>max_iteration:
				if DR5>inputs.min_DR:
					os.system('rm -rf '+file_str+'.cal')
					os.system('cp -r junk0.cal junk1.cal')  # Keeping the last good caltable
					os.system('cp -r junk0.ms junk1.ms')  # Keeping the last good calibrated ms
					if verbose==False:
						print (error_msgs(9))
					logger.error(error_msgs(9))
					end_selfcal=True
					if use_cubical:
						AM=am.AccessMS(working_dir+'/Backup_uncalib.ms')
						logger.info('ft(vis=\''+working_dir+'/Backup_uncalib.ms\',model=\'junk1.model\',usescratch=True)\n')
						ft(vis=working_dir+'/Backup_uncalib.ms',model='junk1.model',usescratch=True)
						IB=ImageBasic(working_dir+'/Backup_uncalib.ms')
						calib_uvrange=IB.calc_calib_uvrange(20,includeflag=True)
						calib_uvrange_min=calib_uvrange[1]
						calib_uvrange_max=calib_uvrange[2]
						ref_ant_name=AM.get_antenna_name(antenna_id=int(inputs.ref_ant))
						flagdata(vis=msname,mode='clip',clipzeros=True,flagbackup=False)
						tb=table()
						tb.open(msname)
						flag=tb.getcol('FLAG')
						tb.close()
						tb.open(working_dir+'/Backup_uncalib.ms',nomodify=False)
						tb.putcol('FLAG',flag)
						tb.flush()
						tb.close()
						cubical_args=['paircars_cubical','--data-ms '+working_dir+'/Backup_uncalib.ms','--out-casa-gaintables 0','--model-list MODEL_DATA','--bbc-plot 0',\
						'--g-type complex-2x2','--sol-jones g','--data-column DATA','--sol-min-bl '+str(calib_uvrange_min),'--sol-max-bl '+str(calib_uvrange_max),\
						'--flags-save FLAG ','--g-ref-ant '+str(ref_ant_name),'--out-mode so','--g-update-type diag','--g-diag-only 1','--out-overwrite 0','--out-backup 0',\
						'--g-save-to junk1.cal']
						if verbose:
							logger.info(' '.join(cubical_args)+'\n')
						os.system(' '.join(cubical_args)+' > tmp')
						os.system('cp -r cubical.cc-out/cc.stats.pickle junk1.cal.stat')
						if os.path.exists('cubical.cc-out'):
							os.system('rm -rf cubical.cc-out* tmp')
						if perform_fluxcal==False:
							logger.info('normalize_cubical_caltable(\'junk1.cal\',soltype=\'B\',normtype=\'mean\',overwrite=True,verbose='+str(verbose)+')\n')
							final_caltable_name=normalize_cubical_caltable('junk1.cal',soltype='B',normtype='mean',overwrite=True,verbose=verbose)
					else:
						logger.info('delmod(vis=\''+working_dir+'/Backup_gaincaled.ms\',scr=True)\n')
						delmod(vis=working_dir+'/Backup_gaincaled.ms',scr=True)
						logger.info('ft(vis=\''+working_dir+'/Backup_gaincaled.ms\',model=\'junk1.model\',usescratch=True)\n')
						ft(vis=working_dir+'/Backup_gaincaled.ms',model='junk1.model',usescratch=True)
						if os.path.exists('junk1.cal'):
							os.system('rm -rf junk1.cal')
						if perform_fluxcal==True:
							solnorm=False
						else:
							solnorm=True
						os.system('cp -r '+working_dir+'/Backup_gaincaled.ms '+inputs.basedir+'/bpcalms/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'_'+str(bandwidth)+'kHz_'+str(timewidth)+'s.ms')
						logger.info('bandpass(vis=\''+working_dir+'/Backup_gaincaled.ms\',caltable=\'junk1.cal\',solnorm='+str(solnorm)+',refant=\''+str(inputs.ref_ant)+'\',minsnr='+str(inputs.gain_minsnr)+')\n')
						bandpass(vis=working_dir+'/Backup_gaincaled.ms',caltable='junk1.cal',solnorm=solnorm,refant=str(inputs.ref_ant),minsnr=float(inputs.gain_minsnr))
					if os.path.exists(inputs.basedir+'/bpcaltables/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bcal'):
						os.system('rm -rf '+inputs.basedir+'/bpcaltables/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bcal')
					caltable_name='junk1.cal'
					if do_fluxcal:
						atten=float(fits.getheader(metafits)['ATTEN_DB'])
						logger.info('fluxcal_bptable(\'junk0.cal\',\''+metafits+'\',atten='+str(atten)+')\n')
						caltable_name=fluxcal_bptable('junk0.cal',metafits,atten=atten)
					os.system('cp -r '+caltable_name+' '+inputs.basedir+'/bpcaltables/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bcal')  # Keeping the last good caltable
					os.system('cp -r junk1.model '+inputs.basedir+'/bpimagemodels/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'_'+str(bandwidth)+'kHz_'+str(timewidth)+'s.model')
					os.system('cp -r junk1.image '+inputs.basedir+'/bpimagemodels/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'_'+str(bandwidth)+'kHz_'+str(timewidth)+'s.image')
					if inputs.send_notification==True:
						quickimage=get_quicklook_image('junk1.image','quick_image_freq_'+freqstr+'_time_'+datestrfile+'.png',freqstr,datestr,DR5,DR6,field_of_view=3)
					os.system('rm -rf '+working_dir+'/junk*')
					if 'ref' in msname:
						os.chdir(cwd)
						touch_file=inputs.basedir+'/.Finished_bcal_'+str(OBSID)+'_'+basemsdir+'_'+os.path.basename(msname)+'_109'
						end_time=time.time()
						run_time=time.strftime('%Hh %Mm %Ss',time.gmtime(end_time-start_time))
						logger.info('Total runtime : '+str(run_time)+'\n')
						msg_str='Dear P-AIRCARS user,\n\nBandpass self-calibration for : '+os.path.basename(msname)+'\nMessage : '+error_msgs(100)+', '+error_msgs(9)\
									+'\nTotal runtime : '+str(run_time)+'\n\nP-AIRCARS'
						msg_subject='Notification from P-AIRCARS : Bandpass Selfcal : OBSID = '+str(OBSID)
						if inputs.send_notification==True:
							sent,send_msg=send_paircars_notification(inputs.email,msg_subject,msg_str,attachments=[quickimage])
							if sent==0:
								logger.info('Notification sent successfully.\n')
							else:
								logger.warning('Notification could not be sent.\n')
								logger.warning('Error during sending notification : '+str(send_msg)+'\n')
							os.system('rm -rf '+quickimage)
						os.system('touch '+touch_file)
						os.system('cp -r '+working_dir+'/Bandpass_Selfcal.log '+inputs.basedir+'/logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
						if inputs.keep_logger and verbose==True:
							os.system('cp -r '+working_dir+'/Intensity_Selfcal_verbose.log '+inputs.basedir+'/verbose_logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
						os.system('rm -rf '+working_dir+'/*.log '+working_dir+'/TempLattice*')
						os.system('rm -rf '+working_dir+'/'+file_str+'* '+working_dir+'/cubical.last '+working_dir+'/~*.cal')
						return 109		
					else:
						os.chdir(cwd)
						touch_file=inputs.basedir+'/.Finished_bcal_'+str(OBSID)+'_'+basemsdir+'_'+os.path.basename(msname)+'_9'
						end_time=time.time()
						run_time=time.strftime('%Hh %Mm %Ss',time.gmtime(end_time-start_time))
						logger.info('Total runtime : '+str(run_time)+'\n')
						msg_str='Dear P-AIRCARS user,\n\nBandpass self-calibration for : '+os.path.basename(msname)+'\nMessage : '+error_msgs(9)+\
								'\nTotal runtime : '+str(run_time)+'\n\nP-AIRCARS'
						msg_subject='Notification from P-AIRCARS : Bandpass Selfcal : OBSID = '+str(OBSID)
						if inputs.send_notification==True:
							sent,send_msg=send_paircars_notification(inputs.email,msg_subject,msg_str,attachments=[quickimage])
							if sent==0:
								logger.info('Notification sent successfully.\n')
							else:
								logger.warning('Notification could not be sent.\n')
								logger.warning('Error during sending notification : '+str(send_msg)+'\n')
							os.system('rm -rf '+quickimage)
						os.system('touch '+touch_file)
						os.system('cp -r '+working_dir+'/Bandpass_Selfcal.log '+inputs.basedir+'/logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
						if inputs.keep_logger and verbose==True:
							os.system('cp -r '+working_dir+'/Intensity_Selfcal_verbose.log '+inputs.basedir+'/verbose_logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
						os.system('rm -rf '+working_dir+'/*.log '+working_dir+'/TempLattice*')
						os.system('rm -rf '+working_dir+'/'+file_str+'* '+working_dir+'/cubical.last '+working_dir+'/~*.cal')
						return 9
				else:
					if verbose==False:
						print (error_msgs(13))
					logger.error(error_msgs(13))
					end_selfcal=True
					os.system('rm -rf '+working_dir+'/junk*')
					os.chdir(cwd)
					touch_file=inputs.basedir+'/.Finished_bcal_'+str(OBSID)+'_'+basemsdir+'_'+os.path.basename(msname)+'_13'
					end_time=time.time()
					run_time=time.strftime('%Hh %Mm %Ss',time.gmtime(end_time-start_time))
					logger.info('Total runtime : '+str(run_time)+'\n')
					msg_str='Dear P-AIRCARS user,\n\nBandpass self-calibration for : '+os.path.basename(msname)+'\nMessage : '+error_msgs(13)+\
							'\nTotal runtime : '+str(run_time)+'\n\nP-AIRCARS'
					msg_subject='Notification from P-AIRCARS : Intensity Selfcal : OBSID = '+str(OBSID)
					if inputs.send_notification==True:
						sent,send_msg=send_paircars_notification(inputs.email,msg_subject,msg_str,attachments=[quickimage])
						if sent==0:
							logger.info('Notification sent successfully.\n')
						else:
							logger.warning('Notification could not be sent.\n')
							logger.warning('Error during sending notification : '+str(send_msg)+'\n')
						os.system('rm -rf '+quickimage)
					os.system('touch '+touch_file)
					os.system('cp -r '+working_dir+'/Bandpass_Selfcal.log '+inputs.basedir+'/logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
					if inputs.keep_logger and verbose==True:
						os.system('cp -r '+working_dir+'/Intensity_Selfcal_verbose.log '+inputs.basedir+'/verbose_logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
					os.system('rm -rf '+working_dir+'/*.log '+working_dir+'/TempLattice*')
					os.system('rm -rf '+working_dir+'/'+file_str+'* '+working_dir+'/cubical.last '+working_dir+'/~*.cal')
					return 13
						
# Function to run the script stand alone from command line
def main():
	start_time=time.time()
	usage= ' Perform bandpass self calibration'
	parser = OptionParser(usage=usage)
	parser.add_option('--msname',dest="chantime_msname",default=None,help="Name of measurement set of a single time and frequency slice",metavar="Measurement Set")
	parser.add_option('--metafits',dest="metafits",default=None,help="Name of metafits file of the observation",metavar="Metafits file")
	parser.add_option('--workdir',dest='workdir',default=None,help='Name of the working directory',metavar='Directory path')
	parser.add_option('--verbose',dest="verbose",default=False,help="Verbose mode",metavar="Boolean")
	parser.add_option('--fresh',dest="fresh",default=True,help="Start fresh self calibration loop",metavar="Boolean")
	parser.add_option('--caltables',dest="caltables",default='',help="Previous caltables",metavar="String, comma separated")
	parser.add_option('--wsclean',dest="use_wsclean",default=True,help="Use WSClean for imaging or not",metavar="Boolean")
	parser.add_option('--do_fluxcal',dest="do_fluxcal",default=False,help="Perform flux calibration or not",metavar="Boolean")
	parser.add_option('--cubical',dest="use_cubical",default=False,help="Use CubiCal for calibration or not",metavar="Boolean")
	parser.add_option('--input',dest="input_file",default=None,help="Selfcal input file",metavar="String")
	parser.add_option('--num_cpus',dest="num_cpus",default=3,help="Number of CPU threads to use",metavar="Integer")
	(options, args) = parser.parse_args()
	if options.workdir==None:
		print('Working directory is not given. Exititing...\n')
		touch_file=inputs.basedir+'/.Finished_gcal_'+str(OBSID)+'_'+basemsdir+'_'+msbasename+'_'+str('noms')
		end_time=time.time()
		run_time=time.strftime('%Hh %Mm %Ss',time.gmtime(end_time-start_time))
		print('#############################\n')
		print('Gain selfcal failed for ms : '+options.chantime_msname+'\n')
		print('Total runtime : '+str(run_time)+'\n')
		print('##############################\n')
		msg_str='Dear P-AIRCARS user,\n\nIntensity self-calibration for : '+msbasename+'\nMessage : No measurement set is present\nTotal runtime : '+\
					str(run_time)+'\n\nP-AIRCARS'
		msg_subject='Notification from P-AIRCARS : Intensity Selfcal : OBSID = '+str(OBSID)
		if inputs.send_notification==True:
			sent,send_msg=send_paircars_notification(inputs.email,msg_subject,msg_str)
			if sent==0:
				logger.info('Notification sent successfully.\n')
			else:
				logger.warning('Notification could not be sent.\n')
				logger.warning('Error during sending notification : '+str(send_msg)+'\n')
		os.system('touch '+touch_file)
		return 1
	elif os.path.isdir(options.workdir)==False:
		try:
			os.makedirs(options.workdir)
			print ('Working directory is made at : '+options.workdir+'\n')
		except:
			print('Working directory could not be made. Exititing...\n')
			touch_file=inputs.basedir+'/.Finished_gcal_'+str(OBSID)+'_'+basemsdir+'_'+msbasename+'_'+str('noms')
			end_time=time.time()
			run_time=time.strftime('%Hh %Mm %Ss',time.gmtime(end_time-start_time))
			print('#############################\n')
			print('Gain selfcal failed for ms : '+options.chantime_msname+'\n')
			print('Total runtime : '+str(run_time)+'\n')
			print('##############################\n')
			msg_str='Dear P-AIRCARS user,\n\nIntensity self-calibration for : '+msbasename+'\nMessage : No measurement set is present\nTotal runtime : '+\
						str(run_time)+'\n\nP-AIRCARS'
			msg_subject='Notification from P-AIRCARS : Intensity Selfcal : OBSID = '+str(OBSID)
			if inputs.send_notification==True:
				sent,send_msg=send_paircars_notification(inputs.email,msg_subject,msg_str)
				if sent==0:
					logger.info('Notification sent successfully.\n')
				else:
					logger.warning('Notification could not be sent.\n')
					logger.warning('Error during sending notification : '+str(send_msg)+'\n')
			os.system('touch '+touch_file)
			return 1
	cwd=os.getcwd()
	sys.path.append(cwd)
	if (os.path.isfile(str(options.workdir)+'/Bandpass_Selfcal.log') and eval(str(options.fresh))==True) or \
		(os.path.isfile(str(options.workdir)+'/Bandpass_Selfcal.log') and os.path.isdir(str(options.workdir)+'/junk1.ms')==False and eval(str(options.fresh))==False):
		os.system('rm -rf '+str(options.workdir)+'/Bandpass_Selfcal.log')
	if os.path.isfile(str(options.workdir)+'/Intensity_Selfcal_verbose.log') and eval(str(options.verbose))==True:
			os.system('rm -rf '+str(options.workdir)+'/Intensity_Selfcal_verbose.log')
	if os.path.isfile(cwd+'/selfcal_inputs.py')==False and os.path.isfile(str(options.workdir)+'/selfcal_inputs.py')==False and \
			(options.input_file==None or os.path.isfile(options.input_file)==False): 
		print('Input file does not exist.1\n')
		return 1
	elif options.input_file!=None and os.path.isfile(options.input_file)==True:
		os.system('cp -r '+options.input_file+' '+str(options.workdir)+'/selfcal_inputs.py')
	elif os.path.isfile(cwd+'/selfcal_inputs.py')==True:
		os.system('cp -r '+cwd+'/selfcal_inputs.py '+str(options.workdir)+'/selfcal_inputs.py')
	elif os.path.isfile(str(options.workdir)+'/selfcal_inputs.py')==True:
		os.system('cp -r '+str(options.workdir)+'/selfcal_inputs.py '+cwd+'/selfcal_inputs.py')
	input_file=cwd+'/selfcal_inputs.py'
	import selfcal_inputs as inputs

	msbasename=os.path.basename(options.chantime_msname)
	OBSID=get_OBSID_from_metafits(options.metafits)
	basemsdir=os.path.dirname(options.workdir).split('/')[-1]

	
	if os.path.isdir(inputs.basedir+'/logs/'+str(OBSID)+'/'+basemsdir)==False:
		os.makedirs(inputs.basedir+'/logs/'+str(OBSID)+'/'+basemsdir)
	if os.path.isdir(inputs.basedir+'/verbose_logs/'+str(OBSID)+'/'+basemsdir)==False and inputs.keep_logger==True and eval(str(options.verbose)):
		os.makedirs(inputs.basedir+'/verbose_logs/'+str(OBSID)+'/'+basemsdir)
	init_logger_console(working_dir=str(options.workdir),verbose=eval(str(options.verbose)))
	if options.chantime_msname[-1]=='/':
		options.chantime_msname=options.chantime_msname[:-1]

	if options.chantime_msname==None or os.path.isdir(options.chantime_msname)==False:
		logger.info('Measurement set does not exist. Exititing...\n')
		touch_file=inputs.basedir+'/.Finished_bcal_'+str(OBSID)+'_'+basemsdir+'_'+msbasename+'_'+str('noms')
		end_time=time.time()
		run_time=time.strftime('%Hh %Mm %Ss',time.gmtime(end_time-start_time))
		logger.info('#############################\n')
		logger.info('Bandpass selfcal failed for ms : '+options.chantime_msname+'\n')
		logger.info('Total runtime : '+str(run_time)+'\n')
		logger.info('##############################\n')
		msg_str='Dear P-AIRCARS user,\n\nBandpass self-calibration for : '+msbasename+'\nMessage : No measurement set is present\nTotal runtime : '+\
					str(run_time)+'\n\nP-AIRCARS'
		msg_subject='Notification from P-AIRCARS : Bandpass Selfcal : OBSID = '+str(OBSID)
		file_str=msbasename.split('.ms')[0]
		os.system('cp -r '+options.workdir+'/Bandpass_Selfcal.log '+inputs.basedir+'/logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
		os.system('rm -rf '+options.workdir+'/*.log '+options.workdir+'/TempLattice*')
		os.system('rm -rf '+options.workdir+'/'+file_str+'*')
		return 1
	
	if options.metafits==None or os.path.isfile(options.metafits)==False:
		logger.info('Metafits file does not exist. Exititing...\n')
		touch_file=inputs.basedir+'/.Finished_bcal_'+str(OBSID)+'_'+basemsdir+'_'+msbasename+'_'+str('nometa')
		end_time=time.time()
		run_time=time.strftime('%Hh %Mm %Ss',time.gmtime(end_time-start_time))
		logger.info('#############################\n')
		logger.info('Bandpass selfcal failed for ms : '+options.chantime_msname+'\n')
		logger.info('Total runtime : '+str(run_time)+'\n')
		logger.info('##############################\n')
		msg_str='Dear P-AIRCARS user,\n\nBandpass self-calibration for : '+msbasename+'\nMessage : No metafits file is present\nTotal runtime : '+\
					str(run_time)+'\n\nP-AIRCARS'
		msg_subject='Notification from P-AIRCARS : Bandpass Selfcal : OBSID = '+str(OBSID)
		if inputs.send_notification==True:
			sent,send_msg=send_paircars_notification(inputs.email,msg_subject,msg_str)
			if sent==0:
				logger.info('Notification sent successfully.\n')
			else:
				logger.warning('Notification could not be sent.\n')
				logger.warning('Error during sending notification : '+str(send_msg)+'\n')
		os.system('touch '+touch_file)
		file_str=msbasename.split('.ms')[0]
		os.system('cp -r '+options.workdir+'/Bandpass_Selfcal.log '+inputs.basedir+'/logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
		os.system('rm -rf '+options.workdir+'/*.log '+options.workdir+'/TempLattice*')
		os.system('rm -rf '+options.workdir+'/'+file_str+'*')
		return 1

	try:
		previous_touch_list=glob.glob(inputs.basedir+'/.Finished_bcal_'+str(OBSID)+'_'+basemsdir+'_'+msbasename+'_*')
		if len(previous_touch_list)!=0:
			os.system('rm -rf '+inputs.basedir+'/.Finished_bcal_'+str(OBSID)+'_'+basemsdir+'_'+msbasename+'_*')
		print ('\n\t##########################\n\tStarting Bandpass self-calibration.....\n\t##########################\n')
		print ('run_bandpass_selfcal(\''+options.chantime_msname+'\',\''+options.metafits+'\',\''+options.workdir+'\',verbose=\''+str(options.verbose)+'\',start_fresh='+\
			str(options.fresh)+',caltables=\''+str(options.caltables)+'\',use_wsclean='+str(options.use_wsclean)+',perform_fluxcal='+str(options.do_fluxcal)+',use_cubical='+\
			str(options.use_cubical)+',selfcal_input_file=\''+str(input_file)+'\',num_cpus='+str(options.num_cpus)+')\n')
		msg=run_bandpass_selfcal(options.chantime_msname,options.metafits,options.workdir,verbose=eval(str(options.verbose)),start_fresh=eval(str(options.fresh)),\
			caltables=str(options.caltables),use_wsclean=eval(str(options.use_wsclean)),perform_fluxcal=eval(str(options.do_fluxcal)),use_cubical=eval(str(options.use_cubical)),\
			selfcal_input_file=input_file,num_cpus=int(options.num_cpus))
		if msg=='noinput':			
			msg_str='Message : No input file.\n'
			if options.verbose==False:
				print ('Message : No input file.\n')
			logger.info('Message : No input file.\n')
		elif type(msg)==int:
			if msg>100:
				msg1=msg-100
				if msg1==10:
					send_notification=False
				else:
					send_notification=True
				msg_str='Message : '+error_msgs(100)+', '+error_msgs(msg1)+'\n'
				if options.verbose==False:
					print ('Message : '+error_msgs(100)+', '+error_msgs(msg1)+'\n')
				logger.info('Message : '+error_msgs(100)+', '+error_msgs(msg1)+'\n')
			else:
				if msg==10:
					send_notification=False
				else:
					send_notification=True
				msg_str='Message : '+error_msgs(msg)+'\n'
				if options.verbose==False:
					print ('Message : '+error_msgs(msg)+'\n')
				logger.info('Message : '+error_msgs(msg)+'\n')
		touch_file=inputs.basedir+'/.Finished_bcal_'+str(OBSID)+'_'+basemsdir+'_'+msbasename+'_'+str(msg)
		end_time=time.time()
		run_time=time.strftime('%Hh %Mm %Ss',time.gmtime(end_time-start_time))
		logger.info('#############################\n')
		logger.info('Bandpass selfcal finished for ms : '+options.chantime_msname+'\n')
		logger.info('Total runtime : '+str(run_time)+'\n')
		logger.info('##############################\n')
		msg_str='Dear P-AIRCARS user,\n\nBandpass self-calibration for : '+msbasename+'\n'+msg_str+'\nTotal runtime : '+str(run_time)+'\n\nP-AIRCARS'
		msg_subject='Notification from P-AIRCARS : Bandpass Selfcal : OBSID = '+str(OBSID)
		os.system('touch '+touch_file)
		file_str=msbasename.split('.ms')[0]
		os.system('rm -rf '+options.workdir+'/*.log '+options.workdir+'/TempLattice*')
		os.system('rm -rf '+options.workdir+'/'+file_str+'*')
		if inputs.keep_logger and eval(str(options.verbose))==True:
			if os.path.exists(options.workdir+'/Intensity_Selfcal_verbose.log'):
				os.system('cp -r '+options.workdir+'/Intensity_Selfcal_verbose.log '+inputs.basedir+'/verbose_logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
		return 0
	except Exception as e:
		touch_file=inputs.basedir+'/.Finished_bcal_'+str(OBSID)+'_'+basemsdir+'_'+msbasename+'_'+str('error')
		end_time=time.time()
		run_time=time.strftime('%Hh %Mm %Ss',time.gmtime(end_time-start_time))
		logger.info('#############################\n')
		logger.info('Bandpass selfcal failed for ms : '+options.chantime_msname+'\n')
		logger.info('Error occured : '+str(e)+'\n')
		logger.info('Total runtime : '+str(run_time)+'\n')
		logger.info('##############################\n')
		msg_str='Dear P-AIRCARS user,\n\nBandpass self-calibration for : '+msbasename+'\nMessage : Error in runtime : '+str(e)+'\nTotal runtime : '+\
					str(run_time)+'\n\nP-AIRCARS'
		msg_subject='Notification from P-AIRCARS : Bandpass Selfcal : OBSID = '+str(OBSID)
		if inputs.send_notification==True:
			sent,send_msg=send_paircars_notification(inputs.email,msg_subject,msg_str)
			if sent==0:
				logger.info('Notification sent successfully.\n')
			else:
				logger.warning('Notification could not be sent.\n')
				logger.warning('Error during sending notification : '+str(send_msg)+'\n')
		os.system('touch '+touch_file)
		file_str=msbasename.split('.ms')[0]
		try:
			os.system('cp -r '+options.workdir+'/Bandpass_Selfcal.log '+inputs.basedir+'/logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
			if inputs.keep_logger and eval(str(options.verbose))==True:
				os.system('cp -r '+options.workdir+'/Intensity_Selfcal_verbose.log '+inputs.basedir+'/verbose_logs/'+str(OBSID)+'/'+basemsdir+'/'+file_str+'.bpasslog')
		except:
			pass
		os.system('rm -rf '+options.workdir+'/*.log '+options.workdir+'/TempLattice*')
		os.system('rm -rf '+options.workdir+'/'+file_str+'*')
		return 1
if __name__=='__main__':
	success=main()
	os._exit(success)
