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 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 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 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 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