def find_gb_local(theta,phi,system, fm_width, n_orbitals=2, delta=0.01, omega=0, topo=True):
	"""
	Find localized Gilbert Damping as function of theta,phi for individual atomic sites.
	"""
	n_layers = system.n_layers
	u_theta = np.array([[np.cos(theta/2), 1*np.sin(theta/2)],[-1*np.sin(theta/2),np.cos(theta/2)]], dtype=np.complex_)
	u_phi = np.array([[np.exp(1.j*phi/2),0],[0,np.exp(-1.j*phi/2)]], dtype=np.complex_)
	u = np.dot(u_theta,u_phi)
	u_dag = calc.hermitian(u)
	v = sparse.kron(np.identity(n_orbitals*system.sites),np.dot(u_dag,np.dot(np.array([[0,1],[0,0]], dtype=np.complex_),u))).toarray()
	v_array = np.zeros((n_layers, n_layers), dtype=np.complex_)	
	for num in range(fm_width):
		v_array[num,num] = 1
	v_array = sparse.kron(v_array,v).toarray()
	img = (system.greens_ret - calc.hermitian(system.greens_ret)) / 2.j
	system.update_energy(system.energy+omega)
	img_2 =(system.greens_ret - calc.hermitian(system.greens_ret)) / 2.j 
	d = (delta**2)*np.diag(np.dot(img,np.dot(v_array,np.dot(img_2,calc.hermitian(v_array)))))
	if topo:
		lgb = d[1::4] + d[::4]+d[2::4]+d[3::4]
		dos = np.diag(img)
		ldos_maj = dos[::4] + dos[2::4]
		ldos_min = dos[1::4] + dos[3::4]
	else:
		lgb = d[1::2] + d[::2]
		dos = np.diag(img)
		ldos_maj = dos[::2]
		ldos_min = dos[1::2]
	return [np.real(lgb),np.real(ldos_maj),np.real(ldos_min),np.real(dos)]
def inf_rashba_integrand(k,energy,layers=20,so_strength=0.0, theta=0.0, randomize=False,rando_strength=0.0, collector=[]):
	"""
	Integrand function for infinite Rashba plane k-integration.
	"""
	sigma_0 = 1.e-4+1.e-4j
	sites = 1
	mag = 100
	ener = energy
	delt = 0.1
	on_site = -0.067+0.j
	rashba_sys = build_rashba(on_site,1,1,so_strength,sigma_0, 500, 0.5, sites, 1,ener+0.j)
	ras = rashba_sys[0]
	if randomize:
		ras = gd.randomize_hamil(ras,rando_strength,orbitals=1)
	t_x = rashba_sys[1]
	hamil_new = ras.hamil + ras.t_y * np.exp((k)*1.j) + calc.hermitian(ras.t_y) * np.exp((-k)*1.j)
	hamil_se = sparse.kron(on_site,np.identity(2)) + ras.t_y * np.exp((k)*1.j) + calc.hermitian(ras.t_y) * np.exp((-k)*1.j)
	hamil_new = calc.build_fm_island(calc.make_hamil_layers(hamil_new, layers, t_x,sites),theta,0,delt+0.j,sites,layers,padding=False,topo=False)
	off_diag = np.diag(hamil_new,1)
	print(off_diag)
	ras.update_hamil_2(hamil_new, sites, layers,no_mag_leads = True, hamil_sub = hamil_se)
	gb = gd.find_gb_local(theta,0,ras,fm_width=layers,n_orbitals=1,topo=False,delta=delt)
	gil = gb[0]
	s = 0
	for i in range(gil.shape[0]):
		s+=gil[i]
	print("k = " + str(k))
	print("s = " + str(s))
	if randomize:
		collector.append(s)	
	return s	
	def update_energy(self, E_new):
		self.energy = E_new
		self.e_array = sparse.kron(np.identity(self.hamil.shape[0]), E_new).toarray()
		self.self_energy_l = calc.self_energy(E_new, self.hamil_l, self.t_x, self.sigma_0, self.mixing, self.iterations, self.sites)
		self.self_energy_r = calc.self_energy(E_new, self.hamil_r, calc.hermitian(self.t_x), self.sigma_0, self.mixing, self.iterations, self.sites)
		self.sigma_l = calc.construct_sigma_l(self.self_energy_l, self.n_layers)
		self.sigma_r = calc.construct_sigma_r(self.self_energy_r, self.n_layers)
		self.greens_ret = self.combine(self.hamil, self.e_array, self.sigma_l, self.sigma_r, self.sites, self.n_layers)
		self.greens_adv = calc.hermitian(self.greens_ret)
		self.cond = self.conductance(self.sigma_l,self.sigma_r,self.greens_ret,self.greens_adv)
	def conductance(self, sigma_l, sigma_r, greens_ret, greens_adv):
		"""
		Finds the conductance of the system using the retarded and advanced Green's functions
		and the sigma_l and sigma_r self-energy matrix elements.
		"""		
		sigma_l_diff = sigma_l - calc.hermitian(sigma_l)
		sigma_r_diff = sigma_r - calc.hermitian(sigma_r)
		l_side = np.dot(greens_ret, sigma_l_diff)
		r_side = np.dot(greens_adv, sigma_r_diff)
		final = np.dot(l_side,r_side)
		return np.trace(final)
	def update_hamil_layers(self,hamil_layers,num_on_site):
		self.hamil_layers = hamil_layers
		self.hamil_l = hamil_layers[:num_on_site*self.sites,:num_on_site*self.sites]
		self.hamil_r = hamil_layers[num_on_site*self.sites*(self.n_layers-1):,num_on_site*self.sites*(self.n_layers-1):]
		self.e_array = sparse.kron(np.identity(self.hamil_layers.shape[0]), self.energy).toarray()		
		self.self_energy_l = calc.self_energy(self.energy, self.hamil_l, self.t_x, self.sigma_0, self.mixing, self.iterations, self.sites)
		self.self_energy_r = calc.self_energy(self.energy, self.hamil_r, calc.hermitian(self.t_x), self.sigma_0, self.mixing, self.iterations, self.sites)
		if np.array_equal(self.self_energy_l,self.self_energy_r):
			print("equal self energies")
		self.sigma_l = calc.construct_sigma_l(self.self_energy_l, self.n_layers)
		self.sigma_r = calc.construct_sigma_r(self.self_energy_r, self.n_layers)
		self.greens_ret = self.combine(self.hamil_layers, self.e_array, self.sigma_l, self.sigma_r, self.sites, self.n_layers)
		self.greens_adv = calc.hermitian(self.greens_ret)
		self.cond = self.conductance(self.sigma_l,self.sigma_r,self.greens_ret,self.greens_adv)
def gb_integrand(energy, omega, system, efermi, temp):
	"""
	Gilbert damping as function of energy & omega
	"""	
	result_list = []
	system.update_energy(energy)
	greens_up = system.greens_ret[::2,::2]
	img_1 = (greens_up - calc.hermitian(greens_up)) / 1.j
	system.update_energy(energy+omega)
	greens_down = system.greens_ret[1::2,1::2]
	img_2 = (greens_down - calc.hermitian(greens_down)) / 1.j
	r_side = np.trace(np.dot(img_1,img_2))
	l_side = fermi_dist(energy+omega,efermi,temp) - fermi_dist(energy,efermi,temp)
	integrand = np.dot(l_side,r_side)
	return integrand
	def update_hamil_mr(self,hamil_l_new,hamil_r_new,t_x):
		self.hamil = hamil_l_new
		self.n_layers = 2.
		self.hamil_layers = calc.make_hamil_layers_2([hamil_l_new,hamil_r_new], t_x,self.sites)
		self.hamil_r = hamil_r_new
		self.hamil_l = hamil_l_new
		self.e_array = sparse.kron(np.identity(self.hamil_layers.shape[0]), self.energy).toarray()		
		self.self_energy_l = calc.self_energy(self.energy, hamil_l_new, self.t_x, self.sigma_0, self.mixing, self.iterations, self.sites)
		self.self_energy_r = calc.self_energy(self.energy, hamil_r_new, calc.hermitian(self.t_x), self.sigma_0, self.mixing, self.iterations, self.sites)
		if np.array_equal(self.self_energy_l,self.self_energy_r):
			print("equal self energies")
		self.sigma_l = calc.construct_sigma_l(self.self_energy_l, self.n_layers)
		self.sigma_r = calc.construct_sigma_r(self.self_energy_r, self.n_layers)
		self.greens_ret = self.combine(self.hamil_layers, self.e_array, self.sigma_l, self.sigma_r, self.sites, self.n_layers)
		self.greens_adv = calc.hermitian(self.greens_ret)
		self.cond = self.conductance(self.sigma_l,self.sigma_r,self.greens_ret,self.greens_adv)
def find_gb_theta_phi(theta,phi,system, fm_width=20, n_orbitals=2, delta=0.02, omega=0):
	"""
	Find Gilbert Damping as function of theta,phi. Turns entire system into a ferromagnet.
	"""
	n_layers = system.n_layers
	u_theta = np.array([[np.cos(theta/2), 1*np.sin(theta/2)],[-1*np.sin(theta/2),np.cos(theta/2)]], dtype=np.complex_)
	u_phi = np.array([[np.exp(1.j*phi/2),0],[0,np.exp(-1.j*phi/2)]], dtype=np.complex_)
	u = np.dot(u_theta,u_phi)
	u_dag = calc.hermitian(u)
	v = sparse.kron(np.identity(n_orbitals*system.sites),np.dot(u_dag,np.dot(np.array([[0,1],[0,0]], dtype=np.complex_),u))).toarray()
	v_array = np.zeros((n_layers, n_layers), dtype=np.complex_)	
	for num in range(fm_width):
		v_array[num,num] = 1
	v_array = sparse.kron(v_array,v).toarray()
	img = (system.greens_ret - calc.hermitian(system.greens_ret)) / 2.j
	return (delta**2)*np.trace(np.dot(img,np.dot(v_array,np.dot(img,calc.hermitian(v_array)))))
def generate_plot():
	h_bar = 6.582E-16
	q = 1
	a = 1E-10
	t = 1
	c = 3.0E8
	g = -2.002
	N = 1
	E = -1
	Ez = 1000
	eta = 0.01 + (0.01)*1.j
	sigma_x = np.array([[0,1],[1,0]])
	sigma_y = np.array([[0, -1.j],[1.j,0]])
	kxs = []
	alphas = []
	stxs = []
	stys = []
	for kx in pl.frange(0, 2*np.pi, 0.1):
		kxs.append(kx)
		kys = []
		alphas_row = []
		stxs_row = []
		stys_row = []
		for ky in pl.frange(0, 2*np.pi, 0.1):
			coeff = (-1)*g*q*(1/(h_bar**2))*(a**2)*(t**2)*(1/(2*c**2))
			#print(coeff)
			hamil = sparse.kron(np.identity(2, dtype=np.complex_), t*(np.cos(kx)+np.cos(ky)))
			hamil += coeff*(np.cos(kx) + np.cos(ky))*(Ez*np.sin(ky)*sigma_x - Ez*np.sin(kx)*sigma_y)
			E_arr = sparse.kron(np.identity(2, dtype=np.complex_),E).toarray()
			greens = linalg.inv(E_arr-hamil-eta)
			img = (greens - calc.hermitian(greens))/(2.j)
			stxs_row.append(np.trace(np.dot(img,sigma_x))/2)
			stys_row.append(np.trace(np.dot(img,sigma_y))/2)
			kys.append(ky)
			alpha = np.trace(img)/2
			alphas_row.append(alpha)
		#print(stxs_row)
		alphas.append(alphas_row)
		stxs.append(stxs_row)
		stys.append(stys_row)
		print(kx)
	print('loop over')	
	x, y = np.meshgrid(kxs, kys)
	print('here')
	#print(alphas)
	alphas = np.array(alphas)
	stxs = np.array(stxs)
	stys = np.array(stys)
	print(stxs)
	#print(alphas)
	#fig = plt.figure()
	plt.pcolormesh(x, y, alphas)
	#plt.pcolormesh(x,y,stxs)
	plt.quiver(x, y, stxs, stys, color='red', angles='xy', scale_units='xy', scale=1)
	#plt.quiver(x, y, stys, color='red', headlength=10)
	print('mesh complete')
	#plt.colorbar()
	plt.show()
def inf_rashba_integrand_cond(k, energy, second=False,layers=20):
	"""
	Integrand for calculating conductance of infinite Rashba Plane
	"""	
	sigma_0 = 1.e-4+1.e-4j
	sites = 1
	so_strength = 0.00
	mag = 100
	delt = 0.1
	on_site = -0.067+0.j
	rashba_sys = build_rashba(on_site,1,1,so_strength,sigma_0, 500, 0.5, sites, 1,energy+0.j)
	ras = rashba_sys[0]
	t_x = rashba_sys[1]	
	hamil_new = ras.hamil + ras.t_y * np.exp((k)*1.j) + calc.hermitian(ras.t_y) * np.exp((-k)*1.j)
	hamil_se = sparse.kron(np.identity(2),on_site) + ras.t_y * np.exp((k)*1.j) + calc.hermitian(ras.t_y) * np.exp((-k)*1.j)
	hamil_new = calc.build_fm_island(calc.make_hamil_layers(hamil_new, layers, t_x,sites),np.radians(45),0,delt+0.j,sites,layers,padding=False,topo=False)
	ras.update_hamil_2(hamil_new, sites, layers,no_mag_leads = True, hamil_sub = hamil_se)
	cond = -ras.cond
	return cond
	def update_hamil_2(self, hamil_layers, N, n_layers, no_mag_leads=False,hamil_sub=[]):
		#self.hamil = hamil_new
		self.n_layers = n_layers
		self.hamil_layers = hamil_layers
		#self.hamil_sep = np.hsplit(np.vsplit(hamil_layers, N),N)
		if not no_mag_leads:		
			self.hamil_r = np.hsplit(np.vsplit(hamil_layers, self.n_layers)[-1],self.n_layers)[-1]
			self.hamil_l = np.hsplit(np.vsplit(hamil_layers, self.n_layers)[0],self.n_layers)[0]
		else:
			self.hamil_r = hamil_sub
			self.hamil_l = hamil_sub
		self.e_array = sparse.kron(np.identity(hamil_layers.shape[0]), self.energy).toarray()		
		self.self_energy_l = calc.self_energy(self.energy, self.hamil_l, self.t_x, self.sigma_0, self.mixing, self.iterations, self.sites)
		self.self_energy_r = calc.self_energy(self.energy, self.hamil_r, calc.hermitian(self.t_x), self.sigma_0, self.mixing, self.iterations, self.sites)
		self.sigma_l = calc.construct_sigma_l(self.self_energy_l, n_layers)
		self.sigma_r = calc.construct_sigma_r(self.self_energy_r, n_layers)
		self.greens_ret = self.combine(self.hamil_layers, self.e_array, self.sigma_l, self.sigma_r, self.sites, 1)
		self.greens_adv = calc.hermitian(self.greens_ret)
		self.cond = self.conductance(self.sigma_l,self.sigma_r,self.greens_ret,self.greens_adv)
	def __init__(self,E,h,t_y,sigma_0,a,iterations,N, n_layers, t_x):
		"""
		The Constructor class takes the inputs:
			int E 		-> energy
			int h 		-> value of Hamiltonian at each atomic site
			np.complex_ sigma_0 -> starting value for sigma convergence function
			int a 		-> mixing coefficient for sigma convergence
			int iterations 	-> number of iterations in sigma convergence loop
			int N 		-> number of sites in supercell
			int n_layers 	-> number of layers (supercells) in system
			int t_y		-> width of supercell (in y-direction)
			int t_x		-> hopping matrix for transport direction (x-direction)
		"""
		self.runtimes = []
		#hamil_time_i = time.time()		
		self.hamil = calc.hamiltonian(h,t_y,N)
		#hamil_time_o = time.time()
		self.hamil_layers = self.hamil
		self.hamil_l = self.hamil
		self.hamil_r = self.hamil
		self.t_y = t_y
		self.energy = E
		self.e_array = sparse.kron(np.identity(self.hamil.shape[0]), self.energy).toarray()
		self.sites = N
		self.n_layers = n_layers
		self.sigma_0 = sigma_0
		self.iterations = iterations
		self.mixing = a
		self.t_x = t_x
		#selfe_time_i = time.time()
		self.self_energy_l = calc.self_energy(self.energy, self.hamil_l, t_x, sigma_0, a, iterations, N)
		self.self_energy_r = calc.self_energy(self.energy, self.hamil_r, calc.hermitian(t_x), sigma_0, a, iterations, N)
		self.sigma_l = calc.construct_sigma_l(self.self_energy_l, self.n_layers)
		self.sigma_r = calc.construct_sigma_r(self.self_energy_r, self.n_layers)
		selfe_time_o = time.time()
		#greens_time_i = time.time()
		self.greens_ret = self.combine(self.hamil, self.e_array, self.sigma_l, self.sigma_r, self.sites, self.n_layers)
		self.greens_adv = calc.hermitian(self.greens_ret)
		greens_time_o = time.time()
		#cond_time_i = time.time()
		self.cond = self.conductance(self.sigma_l,self.sigma_r,self.greens_ret,self.greens_adv)
def self_energy_vs_location():
	"""
	Plot the self-energy of the system versus site location.
	"""
	sigma_0 = 1.e-4+1.e-4j
	sites = 5
	so_strength = 0.01
	mag = 100
	delt = 0.1
	on_site = -0.067+0.j
	layers = 20
	rashba_sys = build_rashba(on_site,1,1,so_strength,sigma_0, 500, 0.5, sites, 1,energy+0.j)
	ras = rashba_sys[0]
	t_x = rashba_sys[1]	
	hamil_new = ras.hamil + ras.t_y * np.exp((k)*1.j) + calc.hermitian(ras.t_y) * np.exp((-k)*1.j)
	hamil_se = sparse.kron(np.identity(2),on_site) + ras.t_y * np.exp((k)*1.j) + calc.hermitian(ras.t_y) * np.exp((-k)*1.j)
	hamil_new = calc.build_fm_island(calc.make_hamil_layers(hamil_new, layers, t_x,sites),np.radians(45),0,delt+0.j,sites,layers,padding=False,topo=False)
	ras.update_hamil_2(hamil_new, sites, layers,no_mag_leads = True, hamil_sub = hamil_se)
	greens = ras.greens_ret
	self_e = self_energy_integrand(greens, 0, 0, delta)
	print(self_e)
	def expand_y(self, t_y,E, k_y):
		"""
		Expands the conductance function in the y-direction using a Fourier Transform. t_y is the value
		assigned to the y-direction connection between layers.
		"""
		if t_y == 0:
			return self.cond
		else:
			t_y_array = np.zeros((self.sites,self.sites))
			t_y_array[0,self.sites-1] = 1.0
			t_y_array = sparse.kron(t_y_array,t_y)
			t_y_array_dag = calc.hermitian(t_y_array)
			exponent = (1j)*(k_y)
			hamil_y = self.hamil + np.multiply(t_y_array, np.exp(exponent)).toarray() + np.multiply(t_y_array_dag, np.exp((-1)*exponent)).toarray()
			self_energy_y = calc.self_energy(self.energy, hamil_y, t_y, self.sigma_0, self.mixing, self.iterations, self.sites)			
			sigma_l_y = calc.construct_sigma_l(self_energy_y, self.n_layers)
			sigma_r_y = calc.construct_sigma_r(self_energy_y, self.n_layers)		
			e_array_y = sparse.kron(np.identity(hamil_y.shape[0]), E).toarray()
			greens_ret_y = self.combine(hamil_y, e_array_y, sigma_l_y, sigma_r_y, self.sites, self.n_layers)			
			greens_adv_y = calc.hermitian(greens_ret_y)
			cond_y = self.conductance(sigma_l_y,sigma_r_y,greens_ret_y,greens_adv_y)
			return cond_y