def _calculate_matrix(self): self.matrix_2_values = self._matrix_2_values_default() # clear matrix data my_reset_values=self.return_reset_values() # store the values to reset them at the end try: startTime = timing() self.state = 'calculating matrix data' self.x_data = self.generate_frequency() myfield = np.arange(self.begin, self.end, self.delta) self.matrix_dimension = len(myfield) # adjust matrix lines here for i,value in enumerate(myfield): self.state = 'calculating' if i==0: self.old_data = [self.return_hstacked(self.return_spec_data())]#save all old calculated data here if self.bfield_bool : self.bfield = value self.matrix_2_label = 'B-Field[Gauss]' if self.temp1_bool : self.temp1 = value self.matrix_2_label = 'Temperature 1 ['+self.degree+'C]' if self.temp2_bool : self.temp2 = value self.matrix_2_label = 'Temperature 2 ['+self.degree+'C]' if self.length_bool : self.length = value self.matrix_2_label = 'Cell Length [mm]' if self.inputpol_bool: self.inputpol = value self.matrix_2_label = 'Input polarization ['+self.degree+']' if self.detpol_bool : self.detpol = value self.matrix_2_label = 'Output polarization [%]' self.new_data = [self.return_hstacked(self.return_spec_data())] self.old_data = np.vstack((self.new_data,self.old_data)) self.matrix_2_values = np.vstack( (self.y_data, self.matrix_2_values[:-1,:]) ) cutted_data = self.old_data[:-1,:,:]#one entry has to be removed self.matrix_dictionary = self.create_2D_spectra_dict(cutted_data)#for plotting self.matrix_dictionary2= self.create_2D_spectra_dict(cutted_data[::-1,:,:])#reverse it for saving self.state = 'done' self.last_calc_time = 1000*(timing()-startTime) file_prefix = self.return_file_prefix() self.filename = file_prefix+str(self.element).lower()+'_'+str(self.line).lower()+'_'+str(self.spectype).lower()+'_'+str(self.bfield)+'_'+str(self.temp1)+'_matrix.txt' self.matrix_image_filename= file_prefix+str(self.element).lower()+'_'+str(self.line).lower()+'_'+str(self.spectype).lower()+'_'+self.matrix_2_label+'_'+str(self.begin)+'_'+str(self.end) self.matrix_data_filename = file_prefix+str(self.element).lower()+'_'+str(self.line).lower()+'_'+self.matrix_2_label+'_'+str(self.begin)+'_'+str(self.end) except: self.state = 'error' print 'uups....something went wrong in _calculate_matrix()' self.reset_values(my_reset_values) # reset iterated values to start value finally: self.state = 'done' self.reset_values(my_reset_values)
def test1(): ### 1. Fig 3 of Generalised treatment ... Rotondaro JOSAB 2015 paper ### Normal Faraday spectrum import os import time if hasattr(time, 'process_time'): from time import process_time as timing # Python 3.3 elif os.name == 'posix': from time import time as timing #Timing for linux or apple else: from time import clock as timing #Timing for windows d = np.arange(-10000, 10000, 10) #Voigt p_dict = { 'Bfield': 300, 'rb85frac': 1, 'Btheta': 0, 'lcell': 75e-3, 'T': 58, 'Dline': 'D2', 'Elem': 'Cs' } #timing: st = timing() TF = get_spectra2(d, [1, 0, 0], p_dict, outputs=['Iy']) et = timing() - st print(('E-field - Elapsed time (s):', et)) #check vs old elecsus from elecsus.libs import spectra as old_spec st = timing() TF_old = old_spec.get_spectra(d, p_dict, outputs=['Iy']) et = timing() - st print(('Old elecsus - Elapsed time (s):', et)) index = 0 # Iy fig = plt.figure("Faraday comparison") ax1 = fig.add_subplot(111) ax1.plot(d, TF[index], 'r', lw=2, label='Faraday') ax1.plot(d, TF_old[0], 'k--', lw=2, label='Vanilla ElecSus') ax1.legend(loc=0) ax1.set_xlabel('Detuning (MHz)') ax1.set_ylabel('Transmission') plt.show()
def _calculate(self): try: startTime = timing() self.state = 'calculating' self.x_data = self.generate_frequency() self.y_data = self.return_spectrum(self.x_data) self.state = 'done' self.last_calc_time = 1000*(timing()-startTime) file_prefix = self.return_file_prefix() except: self.state = 'error' finally: self.state = 'done'
def _calculate_all(self): """calculates all spetra and sets their values""" try: startTime = timing() self.state='calculating' self.x_data = self.generate_frequency() S0,S1,S2,S3,Ix,Iy,RIp,RIm,GIm,GIp,Tm,Tp,Rot = self.return_spectrum_all(self.x_data) self.S0_spec,self.S1_spec,self.S2_spec,self.S3_spec,self.Ix_spec,self.Iy_spec,self.RIp_spec,self.RIm_spec,self.GIm_spec,self.GIp_spec,self.Tm_spec,self.Tp_spec,self.Rot_spec = S0,S1,S2,S3,Ix,Iy,RIp,RIm,GIm,GIp,Tm,Tp,Rot self.set_y_data() # thats for the matrix plot data setting self.State = 'done' self.last_calc_time = 1000*(timing()-startTime) self.estimate_calc_time() file_prefix = self.return_file_prefix() self.filename = file_prefix+str(self.element).lower()+'_'+str(self.line).lower()+'_'+str(self.bfield)+'_'+str(self.temp1)+'.fits' except: self.state = 'error' print 'some error occured in calculation, check: _calculate_all()' finally: self.state = 'done'
def fit_data(data, parameters, paramBoolList, experimental_datatype='S0', fit_algorithm='ML', **kw): """ Blurb about this: data is a 2-element list containing x and y data 1-d arrays. parameters (and parameter order) is same as for the calculate() method. paramBoolList is ... experimental_datatype is ... fit_algorith is ... keywords are """ ## alter the parameter order. again. ## Really need to rewrite the fitting modules for a more sensible parameter order ## but it's a pain and doesn't add any functionality, so ## it is therefore on the 'to do' list! ## Order as given in the 'parameters' argument ## Element, Dline, B, T, L, Rb85, DoppT, Theta0, Pol, shift, ## GammaBuf, Constrain, K40, K41 ## Order required by Fitting routines: ## Element, OutputType, B, T, L, Rb85%, DoppT, Theta0, Pol, Shift, ## GammaBuf, Constrain, Dline, Precision, K40%, K41% parameters_new = [None] * 16 parameters_new[0] = parameters[0] parameters_new[1] = experimental_datatype parameters_new[2:12] = parameters[2:12] parameters_new[12] = parameters[1] parameters_new[13] = 10 parameters_new[14:] = parameters[12:] #print parameters_new startTime = timing() xdata, ydata = data #print xdata, ydata #print type(xdata), type(ydata) # Call different fitting routines if fit_algorithm == 'Marquardt-Levenberg': print '\nPerfoming Marquardt-Levenberg fitting routine.' optParams, Spec = ML.MLfit(xdata, ydata, parameters_new, paramBoolList, **kw) elif fit_algorithm == 'Simulated Annealing': print '\nPerforming fitting by simulated annealing.' optParams, Spec = SA.SAFit(xdata, ydata, parameters_new, paramBoolList, **kw) else: print '\nPerforming fitting by Random-Restart hill climbing method.' #The more parameters to fit, the more evaluations we need to do. factor = sum(paramBoolList) evaluationNumber = factor**2 + 5 #integer optParams, Spec = RR.RRFit(xdata, ydata, parameters_new, paramBoolList, evaluationNumber, **kw) RMS = sqrt(((ydata - Spec)**2).sum() / float(len(ydata))) # Write the fit parameters to a file parameterLabels = [ 'Magnetic field in Gauss =', 'Reservoir temperature in Celsius =', 'Cell Length in mm =', 'Rb85 percentage =', 'Doppler temperature in Celsius =', 'Theta0 in degrees =', 'Initial sigma minus polarisation percentage = ', 'Shift in MHz =', 'Extra Lorentzian width broadening (MHz) =', 'Potassium-40 percentage =', 'Potassium-41 percentage =' ] #f_Parameters = open(os.path.join(outputDirectory,DAT+'_Parameters.txt') # ,'w') #optParams[2] = optParams[2] #optParams[3] = optParams[3] #optParams[6] = optParams[6] #optParams[5] = optParams[5] ## re-order the optimal params back to the way they were given in the 'parameters' argument.... ## this is getting pretty tedious... optParams_out = [0] * len(parameters) optParams_out[0] = optParams[0] optParams_out[1] = optParams[12] optParams_out[2:12] = optParams[2:12] optParams_out[12:] = optParams[14:] print 'Optimum parameters found !' return optParams_out, RMS
def main(argv): """ Main method. Imports specified runcard.py file from the second system argument. Program behaviour is then determined by contents of the runcard.py file. See runcard documentation for more information on program options. Usage examples: From command line / terminal: >> python elecsus_runcard.py path_to/runcard_file.py Within python interpreter: > python >>> import elecsus_runcard as er >>> er.main([None,'path_to/runcard_file.py']) !!! NOTE:: Use forward slashes to separate directories, even on Windows !!! """ initialFiles = os.listdir('.') #List files existing before program started # Try to import runcard if (len(argv) > 1): #If user specifies a run card name. runcardPath = argv[1] # if user has entered filename in another directory, check if any backslashes are used in string # try to convert string to raw string - replace backslashes (directories) with forward slashes # this doesn't work when there are escape sequences in the string, # so warn user of errors and exit if found. runcardPath = runcardPath.replace("\\", "/") if any(es in runcardPath for es in esc_seq): print 'There are escape characters in the runcard file name string.\ \nUse Forward slashes (/) to separate directories instead of back slashes.' sys.exit(1) # if file is in other directory, add to sys.path runcardDir = os.path.dirname(runcardPath) sys.path.append(runcardDir) # get only the file name runcardFilename = os.path.split(runcardPath)[1] RCFNstripped = runcardFilename.rstrip('.py') code1 = 'import ' + RCFNstripped + ' as G' try: exec code1 in globals()#Import user specified run card except: print 'Run card file not recognised.' sys.exit(1) else: print 'Run card file name must be specified. Exiting Python...' sys.exit(1) print '\n' banner = open(os.path.join(cmd_subfolder,'NOTICE'),'r') for line in banner: #This loop prints the banner to the terminal print line, print '\n\n' banner.close() #run user inputs through the run card checker ELE,NDT,NDTB,CB,DT,DTB,BF,BFB,R85,R85B,K40,K41,T0,T0B,CL,CLB,POL,POLB,SHI,\ SHIB,GAM,GAMB,PRE,TRA,SPE,DAT,SMB,SMF,FT,DStart,DStop,PB,SB,PFT =\ runcardCheck.sanity_check( G.element,G.NdenTemp,G.NdenTempBool,G.ConstrainBool,G.DoppTemp, G.DoppTempBool,G.Bfield,G.BfieldBool,G.Rb85,G.Rb85Bool,G.K40,G.K41, G.Theta0,G.Theta0Bool,G.CellLength,G.CellLenBool,G.Polar,G.PolarBool, G.Shift,G.ShiftBool,G.Gamma,G.GammaBool,G.Precision,G.Transition, G.Spectrum,G.DataFilename,G.SmoothBool,G.SmoothFactor,G.FitType, G.DetStart,G.DetStop,G.PlotBool,G.SavePlotBool,G.PlotFileType ) if TRA == 'D1': #If specified D-line is D1. print 'Calculating D1 spectrum...\n' #Tell user program is running. elif TRA == 'D2': print 'Calculating D2 spectrum...\n' #Stop warnings about casting complex numbers warnings.simplefilter("ignore") #Create results output directory tryDir = os.path.join(os.getcwd(),DAT+"_output") while True: outputDirectory = tryDir try: os.makedirs(outputDirectory) break except: tryDir = tryDir + "1" #Copy runcard to output directory for user reference try: copyfile(runcardPath,os.path.join( outputDirectory,runcardFilename)) except: copyfile('runcard.py',os.path.join(outputDirectory,'runcard.py')) if FT == 'No fit, just theory': startTime = timing() GHzPrecision = PRE/1000.0 #Detuning in GHz X = arange(DStart,DStop+GHzPrecision,GHzPrecision) XMHz = X*1.0e3 #Detuning in MHz Spec = spectra.spectrum(XMHz,ELE,SPE,BF,NDT,CL,R85,DT,T0,POL,SHI,GAM, CB,TRA,PRE,K40,K41) print 'Calculation complete.' else: #If a fit to experimental data was requested try: xdata, ydata = read_in_twoColumn(DAT) file_read_success = True except: try: xdata, ydata = read_in_twoColumn(os.path.join(runcardDir,DAT)) file_read_success = True except: print 'Data file not found. Check file exists in specified location with name: ', runcardFilename sys.exit(1) startTime = timing() if SMB: print '\nData binned for faster fitting.\n' #Take average of local points (low pass filter). xdata, ydata = smoother(xdata,ydata,SMF) X = xdata*1e-3 #Convert back to GHz for plotting #Generate parameter lists paramBoolList = [BFB,NDTB,CLB,R85B,DTB,T0B,POLB,SHIB,GAMB] parameters = [ELE,SPE,BF,NDT,CL,R85,DT,T0,POL,SHI,GAM,CB,\ TRA,PRE,K40,K41] # Call different fitting routines if FT == 'Marquardt-Levenberg': import MLFittingRoutine as FR print '\nPerfoming Marquardt-Levenberg fitting routine.' optParams, Spec = FR.MLfit(xdata,ydata,parameters, paramBoolList) elif FT == 'Simulated annealing': import SAFittingRoutine as FR print '\nPerforming fitting by simulated annealing.' optParams, Spec = FR.SAFit(xdata,ydata,parameters, paramBoolList) else: import RRFittingRoutine as FR print '\nPerforming fitting by random-restart hill climbing method.' #The more parameters to fit, the more evaluations we need to do. factor = sum(paramBoolList) evaluationNumber = factor**2 + 5 #integer optParams, Spec = FR.RRFit(xdata,ydata,parameters,paramBoolList, evaluationNumber) optParams = optParams[2:] # compatibility with newer fitting routine (elecsus >V2.0.0) # Write the fit parameters to a file parameterLabels = ['Magnetic field in Gauss =', 'Reservoir temperature in Celsius =', 'Cell Length in mm =','Rb85 percentage =', 'Doppler temperature in Celsius =', 'Theta0 in degrees =', 'Initial sigma minus polarisation percentage = ', 'Shift in MHz =', 'Extra Lorentzian width broadening (MHz) =', 'Potassium-40 percentage =', 'Potassium-41 percentage ='] f_Parameters = open(os.path.join(outputDirectory,os.path.split(DAT)[1]+'_Parameters.txt') ,'w') i = 0 for par in parameterLabels: if i == 2: optParams[i] = optParams[i]*1000.0 print >> f_Parameters, parameterLabels[i], optParams[i] elif (i==3 and ELE=='Rb') or i==6: optParams[i] = optParams[i]*100.0 print >> f_Parameters, parameterLabels[i], optParams[i] elif i == 4 and CB: print >> f_Parameters, parameterLabels[i],\ "Reservoir temperature (constrained)" elif i == 5 and (SPE in ['Ix','Iy','S1','S2']): optParams[i] = optParams[i]*180.0 print >> f_Parameters, parameterLabels[i], optParams[i] elif (i in [0,1,4,7,8]): print >> f_Parameters, parameterLabels[i], optParams[i] elif (i in [9,10]) and ELE == 'K': print >> f_Parameters, parameterLabels[i], parameters[i+5] i += 1 numDenVal = numDenRb(optParams[1]+273.15)/1.0e18 #Find root mean square deviation RMS = sqrt(((ydata - Spec)**2).sum()/float(len(ydata))) print >> f_Parameters, 'Number density of vapour =', numDenVal,\ 'x 10^12 cm^-3' print >> f_Parameters, "\n\n" print >> f_Parameters, "RMS deviation of experimental data and theory =", RMS f_Parameters.close() #Print parameters to screen os.system('cls' if os.name == 'nt' else 'clear') #Clear the terminal print '' i=0 for Boolian in paramBoolList: if Boolian: print parameterLabels[i], optParams[i] i+=1 # Output theory to csv file fileDirectory = os.path.join(outputDirectory,os.path.split(DAT)[1]+'_theory.csv') fileOutput(fileDirectory,X,Spec) # Calculate and output residuals if FT != 'No fit, just theory': residuals = ydata - Spec fileOutput(os.path.join(outputDirectory,os.path.split(DAT)[1]+'_residuals.csv'), X,residuals) print '\n\nTime taken:', timing() - startTime if SB: PlotName = os.path.join(outputDirectory,os.path.split(DAT)[1]+'_output'+PFT) else: PlotName = False # Plot results if FT == 'No fit, just theory': plotOutput(X,Spec,SPE,0,PBool=PB,path=PlotName) else: plotOutput(X,Spec,SPE,ydata,PB,True,residuals,PlotName) #Clean up pyc files if os.path.isfile("elecsus.pyc"): os.remove("elecsus.pyc") if os.path.isfile("runcard.pyc"): os.remove("runcard.pyc") if (len(argv) > 1): NewruncardFilename = runcardFilename + "c" BOOL1 = os.path.isfile(NewruncardFilename) BOOL2 = (NewruncardFilename in initialFiles) if BOOL1 and not BOOL2: os.remove(argv[1]+"c")
def fit_data(data,parameters,paramBoolList,experimental_datatype='S0',fit_algorithm='ML',**kw): """ Blurb about this: data is a 2-element list containing x and y data 1-d arrays. parameters (and parameter order) is same as for the calculate() method. paramBoolList is ... experimental_datatype is ... fit_algorith is ... keywords are """ ## alter the parameter order. again. ## Really need to rewrite the fitting modules for a more sensible parameter order ## but it's a pain and doesn't add any functionality, so ## it is therefore on the 'to do' list! ## Order as given in the 'parameters' argument ## Element, Dline, B, T, L, Rb85, DoppT, Theta0, Pol, shift, ## GammaBuf, Constrain, K40, K41 ## Order required by Fitting routines: ## Element, OutputType, B, T, L, Rb85%, DoppT, Theta0, Pol, Shift, ## GammaBuf, Constrain, Dline, Precision, K40%, K41% parameters_new = [None]*16 parameters_new[0] = parameters[0] parameters_new[1] = experimental_datatype parameters_new[2:12] = parameters[2:12] parameters_new[12] = parameters[1] parameters_new[13] = 10 parameters_new[14:] = parameters[12:] #print parameters_new startTime = timing() xdata, ydata = data #print xdata, ydata #print type(xdata), type(ydata) # Call different fitting routines if fit_algorithm == 'Marquardt-Levenberg': print '\nPerfoming Marquardt-Levenberg fitting routine.' optParams, Spec = ML.MLfit(xdata,ydata,parameters_new, paramBoolList,**kw) elif fit_algorithm == 'Simulated Annealing': print '\nPerforming fitting by simulated annealing.' optParams, Spec = SA.SAFit(xdata,ydata,parameters_new, paramBoolList,**kw) else: print '\nPerforming fitting by Random-Restart hill climbing method.' #The more parameters to fit, the more evaluations we need to do. factor = sum(paramBoolList) evaluationNumber = factor**2 + 5 #integer optParams, Spec = RR.RRFit(xdata,ydata,parameters_new,paramBoolList, evaluationNumber,**kw) RMS = sqrt(((ydata - Spec)**2).sum()/float(len(ydata))) # Write the fit parameters to a file parameterLabels = ['Magnetic field in Gauss =', 'Reservoir temperature in Celsius =', 'Cell Length in mm =', 'Rb85 percentage =', 'Doppler temperature in Celsius =', 'Theta0 in degrees =', 'Initial sigma minus polarisation percentage = ', 'Shift in MHz =', 'Extra Lorentzian width broadening (MHz) =', 'Potassium-40 percentage =', 'Potassium-41 percentage ='] #f_Parameters = open(os.path.join(outputDirectory,DAT+'_Parameters.txt') # ,'w') #optParams[2] = optParams[2] #optParams[3] = optParams[3] #optParams[6] = optParams[6] #optParams[5] = optParams[5] ## re-order the optimal params back to the way they were given in the 'parameters' argument.... ## this is getting pretty tedious... optParams_out = [0]*len(parameters) optParams_out[0] = optParams[0] optParams_out[1] = optParams[12] optParams_out[2:12] = optParams[2:12] optParams_out[12:] = optParams[14:] print 'Optimum parameters found !' return optParams_out, RMS
def fct(*args, **kwargs): before = timing() rv = func(*args, **kwargs) after = timing() print('elapsed', after - before) return rv
def solve_diel(chiL, chiR, chiZ, THETA, Bfield, verbose=False, force_numeric=False): ''' Solves the wave equation to find the two propagating normal modes of the system, for a given magnetic field angle THETA. For the general case, use symbolic python to solve for the roots of n-squared. (Escapes this slow approach for the two analytic cases for the Voigt and Faraday geometries) Returns the rotation matrix to transform the coordinate system into the normal mode basis, and returns the two refractive index arrays. Inputs: chiL, chiR, chiZ : 1D lists or numpy arrays, of length N, that are the frequency-dependent electric susceptibilities THETA : Float, Magnetic field angle in radians Bfield : Float, Magnitude of applied magnetic field (skips slow approach if magnetic field is very close to zero) Options: verbose : Boolean to output more print statements (timing reports mostly) force_numeric : If True, forces all angles to go through the numeric approach, rather than escaping for the analytic cases (THETA=0, THETA=pi/2...) Outputs: RotMat : Rotation matrix to transform coordinate system, dimensions (3, 3, N) n1 : First solution for refractive index, dimensions (N) n2 : Second solution for refractive index, dimensions (N) ''' if verbose: print(('B-field angle (rad, pi rad): ', THETA, THETA / np.pi)) stt = timing() # make chiL,R,Z arrays if not already chiL = np.array(chiL) chiR = np.array(chiR) chiZ = np.array(chiZ) #### Escape the slow loop for analytic (Faraday and Voigt) cases ## For these analytic cases we can use array operations and it is therefore ## much faster to compute if (abs(THETA % (2 * np.pi) - np.pi / 2) < 1e-4) and (not force_numeric): # ANALYTIC SOLNS FOR VOIGT if verbose: print('Voigt - analytic') # solutions for elements of the dielectric tensor: ex = 0.5 * (2. + chiL + chiR) exy = 0.5j * (chiR - chiL) ez = 1.0 + chiZ # refractive indices to propagate n1 = np.sqrt(ex + exy**2 / ex) n2 = np.sqrt(ez) ev1 = [np.zeros(len(ex)), ex / exy, np.ones(len(ex))] ev2 = [np.ones(len(ex)), np.zeros(len(ex)), np.zeros(len(ex))] ev3 = [np.zeros(len(ex)), np.zeros(len(ex)), np.ones(len(ex))] RotMat = np.array([ev1, ev2, ev3]) if verbose: print('Shortcut:') print((RotMat.shape)) print((n1.shape)) print((n2.shape)) elif ((abs(THETA) < 1e-4) or ((abs(THETA - np.pi)) < 1e-4) or abs(Bfield) < 1e-2) and ( not force_numeric ): ## Use Faraday geometry if Bfield is very close to zero # ANALYTIC SOLNS FOR FARADAY #if verbose: if verbose: print('Faraday - analytic TT') ex = 0.5 * (2. + chiL + chiR) exy = 0.5j * (chiR - chiL) e_z = 1.0 + chiZ n1 = np.sqrt(ex + 1.j * exy) n2 = np.sqrt(ex - 1.j * exy) ev1 = np.array( [-1.j * np.ones(len(ex)), np.ones(len(ex)), np.zeros(len(ex))]) ev2 = np.array( [1.j * np.ones(len(ex)), np.ones(len(ex)), np.zeros(len(ex))]) ev3 = [np.zeros(len(ex)), np.zeros(len(ex)), np.ones(len(ex))] if (abs(THETA) < 1e-4): RotMat = np.array([ev1, ev2, ev3]) else: #if anti-aligned, swap the two eigenvectors RotMat = np.array([ev2, ev1, ev3]) if verbose: print('Shortcut:') print((RotMat.shape)) print((n1.shape)) print((n2.shape)) else: if verbose: print('Non-analytic angle.. This will take a while...' ) ##### THIS IS THE ONE THAT's WRONG.... # set up sympy symbols theta = Symbol('theta', real=True) n_sq = Symbol('n_sq') e_x = Symbol('e_x') e_xy = Symbol('e_xy') e_z = Symbol('e_z') # General form of the dielectric tensor DielMat = Matrix(([(e_x - n_sq) * cos(theta), e_xy, e_x * sin(theta)], [-e_xy * cos(theta), e_x - n_sq, -e_xy * sin(theta)], [(n_sq - e_z) * sin(theta), 0, e_z * cos(theta)])) et1 = timing() - stt # Substitute in angle DielMat_sub = DielMat.subs(theta, pi * THETA / np.pi) et2 = timing() - stt # Find solutions for complex indices for a given angle solns = solve(det(DielMat_sub), n_sq) et3a = timing() - stt #print et3a # Find first refractive index DielMat_sub1 = DielMat_sub.subs(n_sq, solns[0]) n1 = np.zeros(len(chiL), dtype='complex') n1old = np.zeros(len(chiL), dtype='complex') # Find second refractive index DielMat_sub2 = DielMat_sub.subs(n_sq, solns[1]) n2 = np.zeros(len(chiL), dtype='complex') n2old = np.zeros(len(chiL), dtype='complex') et3b = timing() - stt Dsub1 = lambdify((e_x, e_xy, e_z), DielMat_sub1, 'numpy') Dsub2 = lambdify((e_x, e_xy, e_z), DielMat_sub2, 'numpy') nsub1 = lambdify((e_x, e_xy, e_z), solns[0], 'numpy') nsub2 = lambdify((e_x, e_xy, e_z), solns[1], 'numpy') # Initialise rotation matrix RotMat = np.zeros((3, 3, len(chiL)), dtype='complex') et3c = timing() - stt # populate refractive index arrays n1 = np.sqrt( nsub1(0.5 * (2. + chiL + chiR), 0.5j * (chiR - chiL), (1.0 + chiZ))) n2 = np.sqrt( nsub2(0.5 * (2. + chiL + chiR), 0.5j * (chiR - chiL), (1.0 + chiZ))) et3 = timing() - stt if verbose: print(('setup time:', et1, et1)) print(('solve nsq: (total/solve/sub in) ', et3a, et3a - et2, et2 - et1)) print(( 'get nsq arrays (tot time / populate ref. index / gen. lambdify / sub in): ', et3, et3 - et3c, et3c - et3b, et3b - et3a)) # loop over all elements of chiL,R,Z to populate eigenvectors # time-limiting step for arrays of length >~ 5000 for i, (cL, cR, cZ) in enumerate(zip(chiL, chiR, chiZ)): #if verbose: print 'Detuning point i: ',i #time diagnostics st = timing() ''' ## OLD and slow method:: # Sub in values of susceptibility DielMat_sub1a = DielMat_sub1.subs(e_x, 0.5*(2.+cL+cR)) DielMat_sub1a = DielMat_sub1a.subs(e_xy, 0.5j*(cR-cL)) DielMat_sub1a = DielMat_sub1a.subs(e_z, (1.0+cZ)) et1 = timing() - st # Evaluate and convert to numpy array DM = np.array(DielMat_sub1a.evalf()) DMa = np.zeros((3,3),dtype='complex') for ii in range(3): for jj in range(3): DMa[ii,jj] = np.complex128(DM[ii,jj]) et2 = timing() - st # use scipy to find eigenvector #ev1 = Matrix(DMa).nullspace() #print 'Sympy: ', ev1 ev1old = nullOld(DMa).T[0] #ev1 = null(DMaNP).T # sub in for ref. index n1soln = solns[0].subs(e_x, 0.5*(2.+cL+cR)) n1soln = n1soln.subs(e_xy, 0.5j*(cR-cL)) n1soln = n1soln.subs(e_z, (1.0+cZ)) # Populate the refractive index array n1old[i] = np.sqrt(np.complex128(n1soln.evalf())) ## /OLD method ''' # NEW method # Sub in values of susceptibility DMaNP = Dsub1(0.5 * (2. + cL + cR), 0.5j * (cR - cL), (1.0 + cZ)) #print DMa ev1 = null(DMaNP).T # Populate the refractive index array #n1[i] = np.sqrt(nsub1(0.5*(2.+cL+cR), 0.5j*(cR-cL), (1.0+cZ))) ''' ## METHOD COMPARISON print 'SymPy:' print DMa print DMa.shape, type(DMa) print 'Numpy' print DMaNP print DMaNP.shape, type(DMaNP) print 'Eigenvectors ...' print 'Old: ', ev1old print 'New: ',ev1 ''' #print '\n\n\n' #print 'scipy: ', ev1 et3 = timing() - st et4 = timing() - st # ## Now repeat the above for second eigenvector # ## NEW # Sub in values of susceptibility DMaNP = Dsub2(0.5 * (2. + cL + cR), 0.5j * (cR - cL), (1.0 + cZ)) # Find null eigenvector ev2 = null(DMaNP).T # Populate the refractive index array #n2[i] = np.sqrt(nsub2(0.5*(2.+cL+cR), 0.5j*(cR-cL), (1.0+cZ))) et5 = timing() - st ''' ## OLD # Evaluate and convert to numpy array DielMat_sub2a = DielMat_sub2.subs(e_x, 0.5*(2.+cL+cR)) DielMat_sub2a = DielMat_sub2a.subs(e_xy, 0.5j*(cR-cL)) DielMat_sub2a = DielMat_sub2a.subs(e_z, (1.0+cZ)) DM = np.array(DielMat_sub2a.evalf()) DMa = np.zeros((3,3),dtype='complex') for ii in range(3): for jj in range(3): DMa[ii,jj] = np.complex128(DM[ii,jj]) et6 = timing() - st # use scipy to find eigenvector ev2old = nullOld(DMa).T[0] et7 = timing() - st # sub in for ref. index n2soln = solns[1].subs(e_x, 0.5*(2.+cL+cR)) n2soln = n2soln.subs(e_xy, 0.5j*(cR-cL)) n2soln = n2soln.subs(e_z, (1.0+cZ)) # Populate the refractive index array n2old[i] = np.sqrt(np.complex128(n2soln.evalf())) ''' # Populate the rotation matrix RotMat[:, :, i] = [ev1, ev2, [0, 0, 1]] et_tot = timing() - stt if verbose: print(('Time elapsed (non-analytic angle):', et_tot)) if verbose: print('SD done') return RotMat, n1, n2