def __init__(self,scl_long_tuneup_controller):
		self.scl_long_tuneup_controller = scl_long_tuneup_controller
		self.scl_accSeq = self.scl_long_tuneup_controller.scl_accSeq
		self.part_tracker = AlgorithmFactory.createParticleTracker(self.scl_accSeq)
		self.part_tracker.setRfGapPhaseCalculation(true)
		self.part_probe_init = ProbeFactory.createParticleProbe(self.scl_accSeq,self.part_tracker)
		self.scenario = Scenario.newScenarioFor(self.scl_accSeq)
		self.scenario.setSynchronizationMode(Scenario.SYNC_MODE_DESIGN)
		self.scenario.resync()
		# in the dictionary we will have 
		# cav_wrappers_param_dict[cav_wrapper] = [cavAmp,phase,[[gapLattElem,E0,ETL],...]]
		# E0 and ETL are parameters for all RF gaps
		self.cav_wrappers_param_dict = {}
		cav_wrappers = self.scl_long_tuneup_controller.cav_wrappers
		self.cav_amp_phase_dict = {}
		for cav_wrapper in cav_wrappers:
			amp = cav_wrapper.cav.getDfltCavAmp()
			phase = cav_wrapper.cav.getDfltCavPhase()
			self.cav_amp_phase_dict[cav_wrapper] = (amp,phase)
		#------ Make rf gap arrays for each cavity. 
		#------ The elements are IdealRfGap instances not AcceleratorNode. 
		#------ self.cavToGapsDict has {cav_name:[irfGaps]}
		rfGaps = self.scl_accSeq.getAllNodesWithQualifier(AndTypeQualifier().and((OrTypeQualifier()).or(RfGap.s_strType)))	
		self.cavToGapsDict = {}		
		for cav_wrapper in cav_wrappers:
			self.cavToGapsDict[cav_wrapper] = []
			for rfGap in rfGaps:
				if(rfGap.getId().find(cav_wrapper.cav.getId()) >= 0):
					irfGaps = self.scenario.elementsMappedTo(rfGap)
					self.cavToGapsDict[cav_wrapper].append(irfGaps[0])				
		#self.scenario.setModelInput(self.gap_first,RfGapPropertyAccessor.PROPERTY_PHASE,phase)
		#self.scenario.setModelInput(self.gap_first,RfGapPropertyAccessor.PROPERTY_ETL,val)
		#self.scenario.setModelInput(self.gap_first,RfGapPropertyAccessor.PROPERTY_E0,val)
		#self.scenario.setModelInput(quad,ElectromagnetPropertyAccessor,PROPERTY_FIELD,val)		
		#----------------------------------------------------------------
		self.scan_gd = BasicGraphData()
		self.harmonicsAnalyzer = HarmonicsAnalyzer(2)
		self.eKin_in = 185.6
		self.cav_amp = 14.0
		self.cav_phase_shift = 0.
		#------------------------
		self.active_cav_wrapper = null
		self.solver = null
	def __init__(self,scl_long_tuneup_controller, run_to_end = true):
		self.scl_long_tuneup_controller = scl_long_tuneup_controller
		self.run_to_end = run_to_end
		self.harmonicsAnalyzer = HarmonicsAnalyzer(2)
		#--- fake scan boolean variable
		scl_long_tuneup_phase_scan_controller = self.scl_long_tuneup_controller.scl_long_tuneup_phase_scan_controller
		set_phase_shift_panel = scl_long_tuneup_phase_scan_controller.set_phase_shift_panel
		self.fake_scan = set_phase_shift_panel.scanSim_RadioButton.isSelected()
		self.useTrigger = set_phase_shift_panel.beamTrigger_RadioButton.isSelected()
		self.keepCavPhases = set_phase_shift_panel.keepLiveCavPhases_RadioButton.isSelected()
		self.wrapPhases = set_phase_shift_panel.wrapPhases_RadioButton.isSelected()
class SCL_One_Cavity_Tracker_Model:
	def __init__(self,scl_long_tuneup_controller):
		self.scl_long_tuneup_controller = scl_long_tuneup_controller
		self.scl_accSeq = self.scl_long_tuneup_controller.scl_accSeq
		self.part_tracker = AlgorithmFactory.createParticleTracker(self.scl_accSeq)
		self.part_tracker.setRfGapPhaseCalculation(true)
		self.part_probe_init = ProbeFactory.createParticleProbe(self.scl_accSeq,self.part_tracker)
		self.scenario = Scenario.newScenarioFor(self.scl_accSeq)
		self.scenario.setSynchronizationMode(Scenario.SYNC_MODE_DESIGN)
		self.scenario.resync()
		# in the dictionary we will have 
		# cav_wrappers_param_dict[cav_wrapper] = [cavAmp,phase,[[gapLattElem,E0,ETL],...]]
		# E0 and ETL are parameters for all RF gaps
		self.cav_wrappers_param_dict = {}
		cav_wrappers = self.scl_long_tuneup_controller.cav_wrappers
		self.cav_amp_phase_dict = {}
		for cav_wrapper in cav_wrappers:
			amp = cav_wrapper.cav.getDfltCavAmp()
			phase = cav_wrapper.cav.getDfltCavPhase()
			self.cav_amp_phase_dict[cav_wrapper] = (amp,phase)
		#------ Make rf gap arrays for each cavity. 
		#------ The elements are IdealRfGap instances not AcceleratorNode. 
		#------ self.cavToGapsDict has {cav_name:[irfGaps]}
		rfGaps = self.scl_accSeq.getAllNodesWithQualifier(AndTypeQualifier().and((OrTypeQualifier()).or(RfGap.s_strType)))	
		self.cavToGapsDict = {}		
		for cav_wrapper in cav_wrappers:
			self.cavToGapsDict[cav_wrapper] = []
			for rfGap in rfGaps:
				if(rfGap.getId().find(cav_wrapper.cav.getId()) >= 0):
					irfGaps = self.scenario.elementsMappedTo(rfGap)
					self.cavToGapsDict[cav_wrapper].append(irfGaps[0])				
		#self.scenario.setModelInput(self.gap_first,RfGapPropertyAccessor.PROPERTY_PHASE,phase)
		#self.scenario.setModelInput(self.gap_first,RfGapPropertyAccessor.PROPERTY_ETL,val)
		#self.scenario.setModelInput(self.gap_first,RfGapPropertyAccessor.PROPERTY_E0,val)
		#self.scenario.setModelInput(quad,ElectromagnetPropertyAccessor,PROPERTY_FIELD,val)		
		#----------------------------------------------------------------
		self.scan_gd = BasicGraphData()
		self.harmonicsAnalyzer = HarmonicsAnalyzer(2)
		self.eKin_in = 185.6
		self.cav_amp = 14.0
		self.cav_phase_shift = 0.
		#------------------------
		self.active_cav_wrapper = null
		self.solver = null
		
	def restoreInitAmpPhases(self):
		cav_wrappers = self.scl_long_tuneup_controller.cav_wrappers
		for cav_wrapper in cav_wrappers:
			(amp,phase) = self.cav_amp_phase_dict[cav_wrapper]
			self.active_cav_wrapper.cav.updateDesignAmp(amp)
			self.active_cav_wrapper.cav.updateDesignPhase(phase)
		self.setActiveCavity(null)
		
	def getEkinAmpPhaseShift(self):
		return (self.eKin_in,self.cav_amp,self.cav_phase_shift)
		
	def setModelAmpPhaseToActiveCav(self,amp,phase,phase_shift):
		if(self.active_cav_wrapper != null):
			self.active_cav_wrapper.cav.updateDesignAmp(amp)
			self.active_cav_wrapper.cav.updateDesignPhase(phase-phase_shift)
			
	def getAvgGapPhase(self):
		#------------- calculate avg. RF gap phase -----------
		if(self.active_cav_wrapper == null): return 0.
		rf_gap_arr = self.cavToGapsDict[self.active_cav_wrapper]
		phase_rf_gaps_avg = 0.
		for irfGap in rf_gap_arr:
			phase_rf_gaps_avg += makePhaseNear(irfGap.getPhase(),0.)
		phase_rf_gaps_avg /= len(rf_gap_arr)
		phase_rf_gaps_avg = makePhaseNear((phase_rf_gaps_avg*180./math.pi)%360.,0.)
		return phase_rf_gaps_avg
			
	def getModelEnergyOut(self,eKin_in,amp,phase,phase_shift):
		if(self.active_cav_wrapper == null): return 0.
		self.setModelAmpPhaseToActiveCav(amp,phase,phase_shift)
		part_probe = ParticleProbe(self.part_probe_init)
		part_probe.setKineticEnergy(eKin_in*1.0e+6)
		self.scenario.setProbe(part_probe)	
		self.scenario.resync()
		self.scenario.run()
		return self.scenario.getTrajectory().finalState().getKineticEnergy()/1.0e+6
			
	def fillOutEneregyVsPhase(self,eKin_in,amp,phase_shift,phase_arr):
		self.scan_gd.removeAllPoints()
		if(self.active_cav_wrapper == null): return
		self.active_cav_wrapper.cav.updateDesignAmp(amp)
		self.scenario.resync()
		irfGap = self.cavToGapsDict[self.active_cav_wrapper][0]	
		for phase in phase_arr:
			part_probe = ParticleProbe(self.part_probe_init)
			part_probe.setKineticEnergy(eKin_in*1.0e+6)
			self.scenario.setProbe(part_probe)		
			#self.active_cav_wrapper.cav.updateDesignPhase(phase-phase_shift)
			#self.scenario.resync()
			irfGap.setPhase((phase-phase_shift)*math.pi/180.)
			self.scenario.run()
			eKin_out = self.scenario.getTrajectory().finalState().getKineticEnergy()/1.0e+6
			self.scan_gd.addPoint(phase,eKin_out)
		return self.scan_gd
			
	def getDiff2(self,eKin_in,amp,phase_shift):
		if(self.active_cav_wrapper == null): return 0.
		scan_gdExp = self.active_cav_wrapper.eKinOutPlot
		n_points = scan_gdExp.getNumbOfPoints()
		if(n_points <= 0): return 0.
		phase_arr = []
		for ip in range(n_points):
			phase_arr.append(scan_gdExp.getX(ip))
		scan_gd = self.fillOutEneregyVsPhase(eKin_in,amp,phase_shift,phase_arr)
		diff2 = 0.
		for ip in range(n_points):
			diff2 += (scan_gd.getY(ip) - scan_gdExp.getY(ip))**2
		diff2 /= n_points
		return diff2
			
	def setActiveCavity(self,cav_wrapper):
		self.active_cav_wrapper = cav_wrapper
		if(cav_wrapper != null):
			self.gap_list = cav_wrapper.cav.getGapsAsList()
			self.gap_first = self.gap_list.get(0)
			self.gap_last = self.gap_list.get(self.gap_list.size()-1)
			self.scenario.setStartNode(self.gap_first.getId())
			self.scenario.setStopNode(self.gap_last.getId())
		else:
			self.scenario.unsetStartNode()
			self.scenario.unsetStopNode()
			self.gap_first = null
			self.gap_last = null	
			self.gap_list = null
			
	def harmonicsAnalysisStep(self):
		if(self.active_cav_wrapper == null): return
		self.eKin_in = self.active_cav_wrapper.eKin_in
		self.cav_amp = 14.0
		self.cav_phase_shift = 0.
		#--------- first iteration
		self.getDiff2(self.eKin_in,self.cav_amp,self.cav_phase_shift)
		err = self.harmonicsAnalyzer.analyzeData(self.scan_gd)	
		harm_function = self.harmonicsAnalyzer.getHrmonicsFunction()
		energy_amp_test = harm_function.getParamArr()[1]
		energy_amp_exp = self.active_cav_wrapper.energy_guess_harm_funcion.getParamArr()[1]
		self.cav_amp = self.cav_amp*energy_amp_exp/energy_amp_test
		#--------- second iteration	
		self.getDiff2(self.eKin_in,self.cav_amp,self.cav_phase_shift)
		err = self.harmonicsAnalyzer.analyzeData(self.scan_gd)	
		harm_function = self.harmonicsAnalyzer.getHrmonicsFunction()
		energy_amp_test = harm_function.getParamArr()[1]
		energy_amp_exp = self.active_cav_wrapper.energy_guess_harm_funcion.getParamArr()[1]
		self.cav_amp = self.cav_amp*energy_amp_exp/energy_amp_test
		max_model_energy_phase = self.harmonicsAnalyzer.getPositionOfMax()
		max_exp_energy_phase = self.active_cav_wrapper.energy_guess_harm_funcion.findMax()
		self.cav_phase_shift = makePhaseNear(-(max_model_energy_phase - max_exp_energy_phase),0.)
		#print "debug model max=",max_model_energy_phase," exp=",max_exp_energy_phase," shift=",self.cav_phase_shift," amp=",self.cav_amp
		
	def fit(self):
		if(self.active_cav_wrapper == null): return
		variables = ArrayList()
		delta_hint = InitialDelta()
		#----- variable eKin_in
		var = Variable("eKin_in",self.eKin_in, - Double.MAX_VALUE, Double.MAX_VALUE)
		variables.add(var)
		delta_hint.addInitialDelta(var,0.3)
		#----- variable cavity amplitude
		var = Variable("cav_amp",self.cav_amp, - Double.MAX_VALUE, Double.MAX_VALUE)
		variables.add(var)
		delta_hint.addInitialDelta(var,self.cav_amp*0.01)
		#----- variable cavity phase offset
		var = Variable("phase_offset",self.cav_phase_shift, - Double.MAX_VALUE, Double.MAX_VALUE)
		variables.add(var)
		delta_hint.addInitialDelta(var,1.0)
		#-------- solve the fitting problem
		scorer = CavAmpPhaseScorer(self,variables)
		maxSolutionStopper = SolveStopperFactory.maxEvaluationsStopper(120) 
		self.solver = Solver(SimplexSearchAlgorithm(),maxSolutionStopper)
		problem = ProblemFactory.getInverseSquareMinimizerProblem(variables,scorer,0.0001)
		problem.addHint(delta_hint)
		self.solver.solve(problem)
		#------- get results
		trial = self.solver.getScoreBoard().getBestSolution()
		err2 = scorer.score(trial,variables)	
		[self.eKin_in,self.cav_amp,self.cav_phase_shift] = scorer	.getTrialParams(trial)	
		self.active_cav_wrapper.eKin_in = self.eKin_in
		self.active_cav_wrapper.designPhase = makePhaseNear(self.active_cav_wrapper.livePhase - self.cav_phase_shift,0.)
		self.active_cav_wrapper.eKin_err = math.sqrt(err2)
		cav_phase = self.active_cav_wrapper.livePhase
		self.active_cav_wrapper.eKin_out = self.getModelEnergyOut(self.eKin_in,self.cav_amp,cav_phase,self.cav_phase_shift)
		#print "debug cav=",self.active_cav_wrapper.alias," shift=",self.cav_phase_shift," amp=",self.cav_amp," err2=",	math.sqrt(err2)," ekinOut=",	self.active_cav_wrapper.eKin_out		
		#----- this defenition of the avg. gap phase will be replaced by another with self.model_eKin_in
		self.active_cav_wrapper.avg_gap_phase = self.getAvgGapPhase()
		self.active_cav_wrapper.designAmp = self.cav_amp
		self.solver = null
		#----make theory graph plot
		x_arr = []
		y_arr = []
		for i in range(self.scan_gd.getNumbOfPoints()):
			phase = self.scan_gd.getX(i)
			y = self.scan_gd.getY(i)
			x_arr.append(phase)
			y_arr.append(y)
		self.active_cav_wrapper.eKinOutPlotTh.addPoint(x_arr,y_arr)			
		
	def stopFitting(self):
		if(self.solver != null):
			self.solver.stopSolving()
	def __init__(self,scl_long_tuneup_controller, run_to_end = true):
		self.scl_long_tuneup_controller = scl_long_tuneup_controller
		self.run_to_end = run_to_end
		self.harmonicsAnalyzer = HarmonicsAnalyzer(2)
class PhaseAnalysis_Runner(Runnable):
	# main thread runner for the anlysis
	def __init__(self,scl_long_tuneup_controller, run_to_end = true):
		self.scl_long_tuneup_controller = scl_long_tuneup_controller
		self.run_to_end = run_to_end
		self.harmonicsAnalyzer = HarmonicsAnalyzer(2)
	
	def run(self):
		cav_wrappers = self.scl_long_tuneup_controller.cav_wrappers	
		# this is a guess energy here
		cav_wrappers[0].eKin_in = 185.6
		n_cavs = len(cav_wrappers)
		messageTextField = self.scl_long_tuneup_controller.getMessageTextField()
		if(messageTextField != null):
			messageTextField.setText("")	
		scl_long_tuneup_phase_analysis_controller = self.scl_long_tuneup_controller.scl_long_tuneup_phase_analysis_controller
		scl_one_cavity_tracker_model = scl_long_tuneup_phase_analysis_controller.scl_one_cavity_tracker_model
		analysis_state_controller = scl_long_tuneup_phase_analysis_controller.analysis_state_controller
		analysis_state_controller.setIsRunning(true)
		cavs_table = scl_long_tuneup_phase_analysis_controller.cavs_table
		analysis_status_text = scl_long_tuneup_phase_analysis_controller.start_stop_analysis_panel.analysis_status_text
		#---------start deal with selected cavities
		cav_selected_inds = cavs_table.getSelectedRows()
		if(len(cav_selected_inds) < 1 or cav_selected_inds[0] < 0): 
			if(messageTextField != null):
				messageTextField.setText("Select one or more cavities to start Phase Analysis!")
				analysis_state_controller.setIsRunning(false)
			return
		# these are the table model indexes
		cav_wrapper = null
		start_ind = cav_selected_inds[0]
		last_ind = cav_selected_inds[len(cav_selected_inds)-1]
		if(self.run_to_end): last_ind = n_cavs - 1
		#----- set isAnalyzed=false for all downstream cavities
		cav_wrapper = cav_wrappers[start_ind]
		cav_wrapper.isAnalyzed = false
		for cav_table_ind in range(start_ind+1,n_cavs):
			cav_wrapper = cav_wrappers[cav_table_ind]
			cav_wrapper.isAnalyzed = false
			cav_wrapper.eKin_err = 0.
			cav_wrapper.model_eKin_out = 0.
			cav_wrapper.bpm_eKin_out = 0.
			cav_wrapper.real_scanPhaseShift = 0.
			cav_wrapper.eKinOutPlot.removeAllPoints()
			cav_wrapper.eKinOutPlotTh.removeAllPoints()
		cavs_table.getModel().fireTableDataChanged()
		#-------start loop over cavities in the table
		time_start = time.time()
		n_total = last_ind - start_ind + 1
		n_count = 0
		for cav_table_ind in range(start_ind,last_ind+1):
			#print "debug cav_table_index=",cav_table_ind
			cav_wrapper = cav_wrappers[cav_table_ind]
			if(cav_wrapper.eKin_in == 0.):
				if(messageTextField != null):
					messageTextField.setText("Cavity "+cav_wrapper.alias+" has 0. inpit energy. Fix it!")
					analysis_state_controller.setIsRunning(false)
				return					
			if(not cav_wrapper.isGood):
				cav_wrapper.eKin_out = cav_wrapper.eKin_in
				cav_wrapper.model_eKin_out = cav_wrapper.eKin_out
				if(cav_table_ind != 0):
					cav_wrapper.model_eKin_out = cav_wrappers[cav_table_ind-1].model_eKin_out
				#-----set the eKin_in  for the next cavity
				if(cav_table_ind != len(cav_wrappers)-1):
					cav_wrappers[cav_table_ind+1].eKin_in = cav_wrapper.eKin_out						
				continue
			if(not cav_wrapper.isMeasured):
				if(messageTextField != null):
					messageTextField.setText("Cavity "+cav_wrapper.alias+" does not have measured data! Stop analysis.")
					analysis_state_controller.setIsRunning(false)
				return				
			cavs_table.setRowSelectionInterval(cav_table_ind,cav_table_ind)
			txt = "Analysis is running! Cavity="+cav_wrapper.alias
			if(start_ind != last_ind): txt = txt + " to Cavity="+cav_wrappers[last_ind-1].alias
			if(n_count > 1):
				run_time = time.time() - time_start
				run_time_sec = int(run_time % 60)
				run_time_min = int(run_time/60.)
				eta_time = ((run_time/n_count)*(n_total - n_count))
				eta_time_sec = int(eta_time % 60)
				eta_time_min = int(eta_time/60.)
				txt = txt + "  ETA= %3d min  %2d sec "%(eta_time_min,eta_time_sec)
				txt = txt + "  Elapse= %3d min  %2d sec "%(run_time_min,run_time_sec)
			analysis_status_text.setText(txt)
			if(analysis_state_controller.getShouldStop()): break
			#calculate the out energy vs. cav. phase
			bpm_wrappers_good_arr = []
			for bpm_ind in range(len(cav_wrapper.bpm_wrappers)):
				bpm_wrapper = cav_wrapper.bpm_wrappers[bpm_ind]
				# make array of BPMs already having offsets and good for phase analysis
				is_wanted = bpm_wrapper.isGood and bpm_wrapper.pos > cav_wrapper.pos
				is_wanted = is_wanted and cav_wrapper.bpm_wrappers_useInPhaseAnalysis[bpm_ind]
				if(is_wanted):
					if(bpm_wrapper.final_phase_offset.isReady):
						bpm_wrappers_good_arr.append(bpm_wrapper)
			#print "debug start E(rf phase) calculation"
			if(len(bpm_wrappers_good_arr) < 3):
				if(messageTextField != null):
					n_good_bpms = len(bpm_wrappers_good_arr)
					messageTextField.setText("Cavity "+cav_wrapper.alias+" does not enough BPMs with offsets! Stop analysis. N BPMs="+str(n_good_bpms))
					analysis_state_controller.setIsRunning(false)
				return						
			calculateEneregyVsPhase(cav_wrapper,self.scl_long_tuneup_controller,bpm_wrappers_good_arr)
			#print "debug stop E(rf phase) calculation"
			if(analysis_state_controller.getShouldStop()): break
			#fit the harmonics function to the energy gain
			cav_wrapper.eKin_err = self.harmonicsAnalyzer.analyzeData(cav_wrapper.eKinOutPlot)
			harm_function = self.harmonicsAnalyzer.getHrmonicsFunction()
			#-----check fitting quality - remove bad points
			bad_point_ind = 0
			bad_points_count = 0
			while(bad_point_ind >= 0):
				bad_point_ind = -1
				for ibp in range(cav_wrapper.eKinOutPlot.getNumbOfPoints()):
					exp_val = cav_wrapper.eKinOutPlot.getY(ibp)
					harm_val = harm_function.getValue(cav_wrapper.eKinOutPlot.getX(ibp))
					diff = math.fabs(exp_val-harm_val)
					if(math.fabs(exp_val-harm_val) > 2.8*cav_wrapper.eKin_err):
						bad_point_ind = ibp
						break
				if(bad_point_ind >= 0):
					bad_points_count += 1 
					cav_wrapper.eKinOutPlot.removePoint(bad_point_ind)
					cav_wrapper.eKin_err = self.harmonicsAnalyzer.analyzeData(cav_wrapper.eKinOutPlot)
					harm_function = self.harmonicsAnalyzer.getHrmonicsFunction()
				if(bad_points_count > int(0.2*cav_wrapper.eKinOutPlot.getNumbOfPoints())):
					analysis_status_text.setText("Analysis stopped! Bad scan! Cav="+cav_wrapper.alias)
					return
			cav_wrapper.bpm_eKin_out = harm_function.getValue(cav_wrapper.livePhase)
			cav_wrapper.real_scanPhaseShift =  makePhaseNear(cav_wrapper.livePhase - harm_function.findMax(),0.)
			cav_wrapper.energy_guess_harm_funcion.setParamArr(harm_function.getParamArr())
			if(analysis_state_controller.getShouldStop()): break
			# put model based analysis here
			scl_one_cavity_tracker_model.setActiveCavity(cav_wrapper)
			scl_one_cavity_tracker_model.harmonicsAnalysisStep()
			scl_one_cavity_tracker_model.fit()
			model_eKin_in = cav_wrapper.eKin_in
			if(cav_table_ind != 0):
				model_eKin_in = cav_wrappers[cav_table_ind-1].model_eKin_out
			cav_amp = scl_one_cavity_tracker_model.cav_amp
			cav_phase = cav_wrapper.livePhase
			cav_phase_shift = scl_one_cavity_tracker_model.cav_phase_shift
			cav_wrapper.model_eKin_out = scl_one_cavity_tracker_model.getModelEnergyOut(model_eKin_in,cav_amp,cav_phase,cav_phase_shift)
			cav_wrapper.avg_gap_phase = scl_one_cavity_tracker_model.getAvgGapPhase()
			if(analysis_state_controller.getShouldStop()): break
			cav_wrapper.isAnalyzed = true
			cavs_table.getModel().fireTableDataChanged()
			#-----set the eKin_in  for the next cavity
			if(cav_table_ind != len(cav_wrappers)-1):
				cav_wrappers[cav_table_ind+1].eKin_in = cav_wrapper.eKin_out			
			n_count += 1
		#------end of cavities loop
		txt = ""
		if(cav_wrapper != null):
			txt = " The last cavity was "+cav_wrapper.alias+" ."
		run_time = time.time() - time_start
		run_time_sec = int(run_time % 60)
		run_time_min = int(run_time/60.)
		txt = txt + "  Total time= %3d min  %2d sec "%(run_time_min,run_time_sec)
		if(analysis_state_controller.getShouldStop()):
			analysis_status_text.setText("Analysis was interrupted!"+txt)
		else:
			analysis_status_text.setText("Analysis finished!"+txt)
		analysis_state_controller.setIsRunning(false)
		scl_one_cavity_tracker_model.restoreInitAmpPhases()
class PhaseScan_Runner(Runnable):
	def __init__(self,scl_long_tuneup_controller, run_to_end = true):
		self.scl_long_tuneup_controller = scl_long_tuneup_controller
		self.run_to_end = run_to_end
		self.harmonicsAnalyzer = HarmonicsAnalyzer(2)
		#--- fake scan boolean variable
		scl_long_tuneup_phase_scan_controller = self.scl_long_tuneup_controller.scl_long_tuneup_phase_scan_controller
		set_phase_shift_panel = scl_long_tuneup_phase_scan_controller.set_phase_shift_panel
		self.fake_scan = set_phase_shift_panel.scanSim_RadioButton.isSelected()
		self.useTrigger = set_phase_shift_panel.beamTrigger_RadioButton.isSelected()
		self.keepCavPhases = set_phase_shift_panel.keepLiveCavPhases_RadioButton.isSelected()
		self.wrapPhases = set_phase_shift_panel.wrapPhases_RadioButton.isSelected()
	
	def run(self):
		messageTextField = self.scl_long_tuneup_controller.getMessageTextField()
		if(messageTextField != null):
			messageTextField.setText("")	
		scl_long_tuneup_phase_scan_controller = self.scl_long_tuneup_controller.scl_long_tuneup_phase_scan_controller
		scan_state_controller = scl_long_tuneup_phase_scan_controller.scan_state_controller
		cavs_table = scl_long_tuneup_phase_scan_controller.cavs_table
		cav_wrappers = self.scl_long_tuneup_controller.cav_wrappers
		n_cavs = len(cav_wrappers)
		phase_step = scl_long_tuneup_phase_scan_controller.start_stop_scan_panel.phase_step_text.getValue()
		time_wait = scl_long_tuneup_phase_scan_controller.set_phase_shift_panel.time_wait_text.getValue()
		scan_status_text = scl_long_tuneup_phase_scan_controller.start_stop_scan_panel.scan_status_text
		scl_long_tuneup_init_controller = self.scl_long_tuneup_controller.scl_long_tuneup_init_controller
		if(not scl_long_tuneup_init_controller.allPairsSet()):
			if(messageTextField != null):
				messageTextField.setText("You should Initialize the scan first! Go to the Init tab!")		
			return
		scl_long_tuneup_init_controller.connectAllBPMs()
		beamTrigger = self.scl_long_tuneup_controller.beamTrigger
		bpmBatchReader = self.scl_long_tuneup_controller.bpmBatchReader
		bpm_amp_min_limit = scl_long_tuneup_phase_scan_controller.post_scan_panel.amp_limit_text.getValue()
		#------------------------------- CA START
		# ?????? For live CA
		if(beamTrigger == null):
			if(messageTextField != null):
				messageTextField.setText("You should Initialize the scan first! Go to the Init tab!")		
			return
		else:
			beamTrigger.setFakeScan(self.fake_scan)
			beamTrigger.setUseTrigger(self.useTrigger)
		beamTrigger.setSleepTime(time_wait)
		beamTrigger.scan_state_controller = scan_state_controller
		bpmBatchReader.setBeamTrigger(beamTrigger)
		#------------------------------- CA END
		#---------start deal with selected cavities
		cav_selected_inds = cavs_table.getSelectedRows()
		if(len(cav_selected_inds) < 1 or cav_selected_inds[0] < 0): 
			if(messageTextField != null):
				messageTextField.setText("Select one or more cavities to start Phase Scan!")	
				beamTrigger.setFakeScan(false)
			return
		# these are the table model indexes
		cav_wrapper = null
		start_ind = cav_selected_inds[0]
		last_ind = cav_selected_inds[len(cav_selected_inds)-1]
		if(self.run_to_end): last_ind = n_cavs
		#----- blank and clean scan data for all downstream cavities
		cav_wrapper = self.scl_long_tuneup_controller.cav0_wrapper
		if(start_ind != 0):
			cav_wrapper = cav_wrappers[start_ind-1]
		cav_wrapper.clean()
		for cav_table_ind in range(start_ind+1,n_cavs+1):
			cav_wrapper = cav_wrappers[cav_table_ind-1]
			if(cav_wrapper.isGood):
				# ?????? should be tested with CA
				if(not self.fake_scan): cav_wrapper.setBlankBeam(true)
				cav_wrapper.clean()
		cavs_table.getModel().fireTableDataChanged()
		#-------start loop over cavities in the table
		result = true
		time_start = time.time()
		n_total = last_ind - start_ind + 1
		n_count = 0
		for cav_table_ind in range(start_ind,last_ind+1):
			cavs_table.setRowSelectionInterval(cav_table_ind,cav_table_ind)
			cav_wrapper = self.scl_long_tuneup_controller.cav0_wrapper
			if(cav_table_ind != 0):
				cav_wrapper = cav_wrappers[cav_table_ind-1]
			if(not cav_wrapper.isGood): continue
			if(cav_table_ind != 0):
				# ?????? should be tested with CA
				if(not self.fake_scan): cav_wrapper.setBlankBeam(false)
			txt = "Scan is running! Cavity="+cav_wrapper.alias
			if(start_ind != last_ind): txt = txt + " to Cavity="+cav_wrappers[last_ind-1].alias
			if(n_count > 1):
				run_time = time.time() - time_start
				run_time_sec = int(run_time % 60)
				run_time_min = int(run_time/60.)
				eat_time = ((run_time/n_count)*(n_total - n_count))
				eat_time_sec = int(eat_time % 60)
				eat_time_min = int(eat_time/60.)
				txt = txt + "  ETA= %3d min  %2d sec "%(eat_time_min,eat_time_sec)
				txt = txt + "  Elapse= %3d min  %2d sec "%(run_time_min,run_time_sec)
			scan_status_text.setText(txt)
			if(scan_state_controller.getShouldStop()): break
			cav_phase = -180.
			while(cav_phase <= 180.):
				#debug
				#print "debug cav=",cav_wrapper.alias," phase=",cav_phase
				#--------set cavity phase
				if(cav_table_ind != 0):
					# ?????? should be tested with CA
					if(not self.fake_scan): cav_wrapper.cav.setCavPhase(cav_phase)
				if(cav_wrapper == self.scl_long_tuneup_controller.cav0_wrapper):
					scan_status_text.setText("Scan running  cavity= "+cav_wrapper.alias+" phase="+str(cav_phase))
				if(scan_state_controller.getShouldStop()): break
				time.sleep(time_wait)
				if(scan_state_controller.getShouldStop()): break
				# ?????? For live CA
				result = false
				if(not self.fake_scan):
					result = bpmBatchReader.makePhaseScanStep(cav_phase,cav_wrapper,bpm_amp_min_limit)
				else:
					result = self.fakeMakePhaseScanStep(cav_phase,cav_wrapper)
				if(scan_state_controller.getShouldStop()): break
				if(result == false):
					scan_status_text.setText("Scan stopped. Could not get BPM data. Please check!")
					if(messageTextField != null):
						messageTextField.setText("")
						beamTrigger.setFakeScan(false)
					return 
				if(cav_table_ind != 0):
					cav_wrapper.addScanPointToPhaseDiffData()			
				cav_phase += phase_step
			#----end of phase loop
			if(scan_state_controller.getShouldStop()): break
			#set up the Cavity phase according to scan
			if(cav_table_ind != 0):
				res_phase_set = self.setUpCavityPhase(cav_wrapper)
				time.sleep(time_wait)
				if(not res_phase_set):
					scan_status_text.setText("Scan stopped! Bad scan! Cannot set up phase for cavity="+cav_wrapper.alias)
					beamTrigger.setFakeScan(false)
					return
			cav_wrapper.isMeasured = true
			cavs_table.getModel().fireTableDataChanged()
			n_count += 1
		#------end of cavities loop
		txt = ""
		if(cav_wrapper != null):
			txt = " The last cavity was "+cav_wrapper.alias+" ."
		run_time = time.time() - time_start
		run_time_sec = int(run_time % 60)
		run_time_min = int(run_time/60.)
		txt = txt + "  Total time= %3d min  %2d sec "%(run_time_min,run_time_sec)
		if(scan_state_controller.getShouldStop()):
			scan_status_text.setText("Scan was interrupted!"+txt)
		else:
			scan_status_text.setText("Scan finished!"+txt)
		#restore the beam trigger fake scan state
		beamTrigger.setFakeScan(false)
	
	def setUpCavityPhase(self,cav_wrapper):
		#--- wrap all BPMs phase scans at once
		if(self.wrapPhases): 
			res_phase_wrap = self.allBPMs_PhaseWrapper(cav_wrapper)	
			if(not res_phase_wrap): return false
		max_bad_points_count = 2
		gd = cav_wrapper.phaseDiffPlot
		gdTh = cav_wrapper.phaseDiffPlotTh
		gdTh.removeAllPoints()
		if(gd.getNumbOfPoints() < 8): return false
		err = self.harmonicsAnalyzer.analyzeData(gd)	
		harm_function = self.harmonicsAnalyzer.getHrmonicsFunction()
		#-----remove bad points
		bad_points_count = 0
		bad_index = 1
		while(bad_index >= 0):
			bad_index = -1
			for i in range(gd.getNumbOfPoints()):
				phase = gd.getX(i)
				y_appr = harm_function.getValue(phase)
				y = gd.getY(i)
				if(math.fabs(y-y_appr) > 3.0*err):
					bad_index = i
					bad_points_count += 1
					break
			if(bad_index >= 0):
				gd.removePoint(bad_index)
				bpm_wrappers = cav_wrapper.bpm_wrappers
				for bpm_wrapper in bpm_wrappers:				
					if(cav_wrapper.bpm_amp_phase_dict.has_key(bpm_wrapper)):
						(graphDataAmp,graphDataPhase) = cav_wrapper.bpm_amp_phase_dict[bpm_wrapper]
						graphDataAmp.removePoint(bad_index)
						graphDataPhase.removePoint(bad_index)
			# we should stop if we have too many bad points
			if(bad_points_count > max_bad_points_count):
				return false
		if(bad_points_count > 0):
			err = self.harmonicsAnalyzer.analyzeData(gd)
			harm_function = self.harmonicsAnalyzer.getHrmonicsFunction()
		#----find a new cavity phase
		min_phase = self.harmonicsAnalyzer.getPositionOfMin()
		new_phase = cav_wrapper.initLivePhase
		if(self.keepCavPhases):
			cav_wrapper.scanPhaseShift = makePhaseNear(new_phase - min_phase,0.)
		else:
			new_phase = makePhaseNear(min_phase + cav_wrapper.scanPhaseShift,0.)
		# ?????? should be tested with CA
		cav_wrapper.livePhase = new_phase
		if(not self.fake_scan):
			cav_wrapper.cav.setCavPhase(cav_wrapper.livePhase)
		cav_wrapper.livePhase = new_phase
		cav_wrapper.phase_scan_harm_amp = harm_function.getParamArr()[1]
		cav_wrapper.phase_scan_harm_err = err
		cav_wrapper.phase_scan_harm_funcion.setParamArr(self.harmonicsAnalyzer.getHrmonicsFunction().getParamArr())
		#----make theory graph plot
		x_arr = []
		y_arr = []
		for i in range(73):
		 phase = -180.0 + 5.0*i
		 y = harm_function.getValue(phase)
		 x_arr.append(phase)
		 y_arr.append(y)
		gdTh.addPoint(x_arr,y_arr)
		return true
	
	def fakeMakePhaseScanStep(self,cav_phase,cav_wrapper):
		cav_wrappers = self.scl_long_tuneup_controller.cav_wrappers
		mass = self.scl_long_tuneup_controller.mass/1.0e+6
		bpm_freq = self.scl_long_tuneup_controller.bpm_freq
		c = self.scl_long_tuneup_controller.c_light	
		cav_pos0 = cav_wrappers[0].pos
		max_pos = cav_wrappers[len(cav_wrappers)-1].pos - cav_pos0
		cav_pos = cav_wrapper.pos
		eKin_in = 185.6+650.0*(cav_pos-cav_pos0)/max_pos
		cav_phase_offset = 30.
		phase = makePhaseNear(cav_phase + cav_phase_offset,0.)
		eKin = eKin_in
		if(self.scl_long_tuneup_controller.cav0_wrapper != cav_wrapper):
			eKin +=  8.0*math.cos(2.0*math.pi*phase/360.)
		else:
			eKin = 185.6
		gamma = (eKin+mass)/mass
		beta = math.sqrt(1.0 - 1.0/gamma**2)
		c = 2.99792458e+8
		freq = 402.5e+6
		bpm_phase_coef = 360.0*freq/(c*beta)
		#print "debug cav_phase=",cav_phase," beta=",beta," eKin=",eKin," cav_pos=",cav_pos," coeff=",bpm_phase_coef
		bpm_wrappers = cav_wrapper.bpm_wrappers
		for bpm_wrapper in bpm_wrappers:				
			if(cav_wrapper.bpm_amp_phase_dict.has_key(bpm_wrapper)):
				(graphDataAmp,graphDataPhase) = cav_wrapper.bpm_amp_phase_dict[bpm_wrapper]
				if(bpm_wrapper.pos < cav_pos):
					graphDataAmp.addPoint(cav_phase,10.0)
					graphDataPhase.addPoint(cav_phase,20.0)
					continue
				bpm_phase = makePhaseNear(bpm_phase_coef*(bpm_wrapper.pos - cav_pos),0.)
				bpm_phase += 1.0*(random.random()-0.5)
				bpm_amp = 25.0*1./(1.+(bpm_wrapper.pos-cav_pos)/20.)
				graphDataAmp.addPoint(cav_phase,bpm_amp)
				old_bpm_phase = 0.
				if(graphDataPhase.getNumbOfPoints() > 0):
					old_bpm_phase = graphDataPhase.getY(graphDataPhase.getNumbOfPoints() - 1)
				graphDataPhase.addPoint(cav_phase,makePhaseNear(bpm_phase,old_bpm_phase))
		return true
		
	def allBPMs_PhaseWrapper(self,cav_wrapper):
		# it will wrap all BPM phases for the cvity by iteration from the BPM closest to cavity
		if(not cav_wrapper.isGood): return
		cav_pos = cav_wrapper.pos
		bpm_wrappers = []
		for bpm_ind in range(len(cav_wrapper.bpm_wrappers)):
			bpm_wrapper = cav_wrapper.bpm_wrappers[bpm_ind]
			res_bool = cav_wrapper.bpm_amp_phase_dict.has_key(bpm_wrapper)
			res_bool = res_bool and bpm_wrapper.isGood
			res_bool = res_bool and (bpm_wrapper.pos > cav_pos)
			if(res_bool):
				bpm_wrappers.append(bpm_wrapper)
		for bpm_ind in range(len(bpm_wrappers)-1):
			(graphDataAmp0,graphDataPhase0) = cav_wrapper.bpm_amp_phase_dict[bpm_wrappers[bpm_ind]]
			(graphDataAmp1,graphDataPhase1) = cav_wrapper.bpm_amp_phase_dict[bpm_wrappers[bpm_ind+1]]
			if(graphDataPhase0.getNumbOfPoints() < 1): break
			if(graphDataPhase0.getNumbOfPoints() != graphDataPhase1.getNumbOfPoints()):
				txt = "Phase Wrapper BPM=",bpm_wrappers[bpm_ind].alias
				txt += " and BPM=",bpm_wrappers[bpm_ind+1].alias
				txt += " have different number of RF phase points n1=",graphDataPhase0.getNumbOfPoints()
				txt += " n2=",graphDataPhase1.getNumbOfPoints()
				self.scl_long_tuneup_controller.getMessageTextField().setText(txt)
				print "debug ==================="
				print txt
				time.sleep(10.)
				return false
			y_arr = []
			for ip in range(graphDataPhase1.getNumbOfPoints()):
				y_arr.append(graphDataPhase1.getY(ip))
			base_phase_diff = y_arr[0] - graphDataPhase0.getY(0)
			for ip in range(1,graphDataPhase0.getNumbOfPoints()):
				y0 = graphDataPhase0.getY(ip)
				y_arr[ip] = makePhaseNear(y_arr[ip],y0+base_phase_diff)
				base_phase_diff = y_arr[ip] - y0
			#move all data by 360. to make the avg close to 0.
			y_avg = 0.
			for y in y_arr:
				y_avg += y
			if(len(y_arr) > 1): y_avg /= len(y_arr)
			y_shift = int(y_avg/360.)*360.
			for ip in range(len(y_arr)):
				y_arr[ip] -= y_shift
			#--- update all bpm phases
			graphDataPhase1.updateValuesY(y_arr)	
		# recreate phase difference
		cav_wrapper.recalculatePhaseDiffData()
		return true