def current_expectation_power_spectrum(x, params, return_freqs=False): """ Returns the power spectrum of a current based on the parameters and x :param x: U, a :param params: all parameters :return: power spectrum of J """ U, a = x lat = hhg(field=params.field, nup=params.nup, ndown=params.ndown, nx=params.nx, ny=0, U=U, t=params.t, F0=params.F0, a=a, pbc=params.pbc) cycles = 10 n_steps = 2000 start = 0 stop = cycles / lat.freq delta = np.linspace(start, stop, num=n_steps, endpoint=True, retstep=True)[1] J = current_expectation(x, params) if return_freqs: return spectrum(J, delta) else: return spectrum(J, delta)[1]
def get_spectra(params, x_vals, parameters): """ Saves spectra over a grid for processing :return: the spectra """ # the lat is for getting the pulse frequency so it does not depend on U lat = hhg(params.field, params.nup, params.ndown, params.nx, 0, 0, params.t) data_points = ((np.array(point), params) for point in x_vals) if __name__ == "__main__": # this saves the spectra for processing with Pool(100) as pool: results = pool.starmap(current_expectation_power_spectrum, data_points) results = np.array(results) print(results.shape) # scale frequencies in terms of omega0 scaled_results = [] for pair in results: freqs, spect = pair freqs = freqs / lat.freq scaled_results.append((freqs, spect)) scaled_results = np.array(scaled_results) print(scaled_results.shape) np.save("./Spectra/spectra" + parameters + ".npy", scaled_results) return scaled_results
def get_spectra(params, x_vals, parameters): """ Saves spectra over a grid for processing, slices spectra from 2 omega_0 to 30 omega_0 :return: the spectra """ # the lat is for getting the pulse frequency so it does not depend on U lat = hhg(params.field, params.nup, params.ndown, params.nx, 0, 0, params.t) data_points = ((np.array(point), params, True) for point in x_vals) if __name__ == "__main__": # this saves the spectra for processing with Pool(100) as pool: results = pool.starmap(current_expectation_power_spectrum, data_points) results = np.array(results) print(results.shape) # scale frequencies in terms of omega0 scaled_results = [] for pair in results: freqs, spect = pair freqs = freqs / lat.freq min_indx = np.searchsorted(freqs, 2) max_indx = np.searchsorted(freqs, 30) spect = spect[min_indx:max_indx] scaled_results.append(spect) scaled_results = np.array(scaled_results) np.save("./GridAnalysisData/Spectra" + parameters + ".npy", scaled_results) return scaled_results
def plot_response(params, xs, domain): """ Plots material response based on their Hubbard parameters. :param xs: list (or iterable) of points from which we can calculate the response :param domain: either "time" or "frequency", determines whether we plot in the spectra or actual response """ if domain == "time": outfile = "./DirectComparisons/TimeDomainComparison" for x in xs: times, current = current_expectation(x, params, return_time=True) plt.plot(times, current, label="$U = {} \cdot t_0, a = {}$".format( x[0] / params.t, x[1]), color=(np.random.random(), np.random.random(), np.random.random())) outfile += "-({},{})".format(x[0], x[1]) plt.xlabel("Time") plt.ylabel("Current Density Expectation") plt.legend(loc="upper right") plt.savefig(outfile + ".png") plt.show() elif domain == "frequency": # the lat is for getting the pulse frequency so it does not depend on U lat = hhg(params.field, params.nup, params.ndown, params.nx, 0, 0, params.t) fig, ax = plt.subplots() outfile = "./DirectComparisons/FrequencyDomainComparison" for x in xs: freqs, spect = current_expectation_power_spectrum(x, params) ax.semilogy(freqs / lat.freq, spect, label="$U = {} \cdot t_0, a = {}$".format( x[0] / params.t, x[1]), color=(np.random.random(), np.random.random(), np.random.random())) outfile += "-({},{})".format(x[0], x[1]) ax.set_xlabel("Harmonic Order") ax.set_ylabel("Power") # ax.set_xlim((0, 50)) for i in range(1, 100, 2): ax.axvline(i, linestyle="dashed", color="grey") ax.legend(loc="upper right") plt.savefig(outfile + ".png") plt.show() else: raise Exception("Invalid specifier for domain")
def spectrum_animation(U_over_t0, parameters, params): lat = hhg(params.field, params.nup, params.ndown, params.nx, 0, 0, params.t) a_values = np.linspace(1, 10, 50) x_ax = current_expectation_power_spectrum( (U_over_t0 * params.t, 1), params, True)[0] / lat.freq try: data = np.load( "./GridAnalysisData/CurrentSpectrumAnimationData-U_over_t{}". format(U_over_t0) + parameters + ".npy") except: data = np.array([ current_expectation_power_spectrum((U_over_t0 * params.t, a), params) for a in a_values ]) np.save( "./GridAnalysisData/CurrentSpectrumAnimationData-U_over_t{}". format(U_over_t0) + parameters + ".npy", data) writer = ani.PillowWriter() fig = plt.figure() ax = fig.add_subplot(111) ax.set_xlabel("Harmonic Order") ax.set_ylabel("Power") plot, = ax.semilogy(x_ax, data[0]) ax.set_xlim(0, 75) ax.set_ylim(data.min(), data.max()) def chart(i): plot.set_ydata(data[i]) # ax.set_ylim(data[i].min(), data[i].max()) ax.set_title( "Current Power Spectrum at $U = {}\\cdot t_0, a = {:.3f}$".format( U_over_t0, 1 + (9 / 49) * i)) animator = ani.FuncAnimation(fig, chart, frames=50, repeat=False) plt.show() # animator.save("./GridAnalysisData/CurrentSpectrumAnimation-U_over_t{}".format(U_over_t0) + parameters + ".gif", writer=writer) plt.close(fig)
def objective(x, J_target, params, graph=False, fname=None): """ Our objective function that we want to minimize: E(U,a) = int(JT - <J>)^2 :param x: input array [U,a] :param J_target: tuple of (frequencies, spectrum) :param params: an instance of Parameters class :param graph: if True, the target and calculated current will be graphed together :param fname: name of the file to save the graph to :return: The cost of the function """ # optimization parameters oU = x[0] oa = x[1] # unpack J_target target_freqs, target_spectrum = J_target # contains all important variables lat = hhg(field=params.field, nup=params.nup, ndown=params.ndown, nx=params.nx, ny=0, U=oU, t=params.t, F0=params.F0, a=oa, pbc=params.pbc) # gets times to evaluate at cycles = 10 n_steps = 2000 start = 0 stop = cycles / lat.freq times, delta = np.linspace(start, stop, num=n_steps, endpoint=True, retstep=True) no_checks = dict(check_pcon=False, check_symm=False, check_herm=False) int_list = [[1.0, i, i] for i in range(params.nx)] static_Hamiltonian_list = [["n|n", int_list] # onsite interaction ] # n_j,up n_j,down onsite = hamiltonian(static_Hamiltonian_list, [], basis=params.basis, **no_checks) hop = [[1.0, i, i + 1] for i in range(params.nx - 1)] if lat.pbc: hop.append([1.0, params.nx - 1, 0]) # c^dag_j,sigma c_j+1,sigma hop_left = hamiltonian([["+-|", hop], ["|+-", hop]], [], basis=params.basis, **no_checks) # c^dag_j+1,sigma c_j,sigma hop_right = hop_left.getH() H = -lat.t * (hop_left + hop_right) + lat.U * onsite """build ground state""" E, psi_0 = H.eigsh(k=1, which='SA') psi_0 = np.squeeze(psi_0) """evolve the system""" psi_t = evolution.evolve(psi_0, 0.0, times, evolve_psi, f_params=(onsite, hop_left, hop_right, lat, cycles)) psi_t = np.squeeze(psi_t) # get the expectation value of J J_expec = expec.J_expec(psi_t, times, hop_left, hop_right, lat, cycles) expec_freqs, J_expec_spectrum = spectrum(J_expec, delta) fval = np.linalg.norm( np.log10(target_spectrum) - np.log10(J_expec_spectrum)) # just some graphing stuff if graph: plt.plot(J_expec_spectrum, color='red', label='$\\langle\\hat{J}(t)\\rangle$') plt.plot(target_spectrum, color='blue', linestyle='dashed', label='$J^{T}(t)$') plt.legend(loc='upper left') plt.xlabel("Time") plt.ylabel("Current") plt.title("Target Current vs Best Fit Current") if fname is not None: plt.savefig(fname) plt.show() # print("Fval =", fval, "for x =", x) return fval
def current_expectation(x, params, return_time=False): U, a = x # contains all important variables lat = hhg(field=params.field, nup=params.nup, ndown=params.ndown, nx=params.nx, ny=0, U=U, t=params.t, F0=params.F0, a=a, pbc=params.pbc) # gets times to evaluate at cycles = 10 n_steps = 2000 start = 0 stop = cycles / lat.freq times, delta = np.linspace(start, stop, num=n_steps, endpoint=True, retstep=True) no_checks = dict(check_pcon=False, check_symm=False, check_herm=False) int_list = [[1.0, i, i] for i in range(params.nx)] static_Hamiltonian_list = [["n|n", int_list] # onsite interaction ] # n_j,up n_j,down onsite = hamiltonian(static_Hamiltonian_list, [], basis=params.basis, **no_checks) hop = [[1.0, i, i + 1] for i in range(params.nx - 1)] if lat.pbc: hop.append([1.0, params.nx - 1, 0]) # c^dag_j,sigma c_j+1,sigma hop_left = hamiltonian([["+-|", hop], ["|+-", hop]], [], basis=params.basis, **no_checks) # c^dag_j+1,sigma c_j,sigma hop_right = hop_left.getH() H = -lat.t * (hop_left + hop_right) + lat.U * onsite """build ground state""" # print("calculating ground state") E, psi_0 = H.eigsh(k=1, which='SA') psi_0 = np.squeeze(psi_0) # print("ground state calculated, energy is {:.2f}".format(E[0])) # evolve the system psi_t = evolution.evolve(psi_0, 0.0, times, evolve_psi, f_params=(onsite, hop_left, hop_right, lat, cycles)) psi_t = np.squeeze(psi_t) # get the expectation value of J J_expec = expec.J_expec(psi_t, times, hop_left, hop_right, lat, cycles) if return_time: return times, J_expec else: return J_expec
"""Hubbard model Parameters""" L = 12 # system size N_up = L // 2 + L % 2 # number of fermions with spin up N_down = L // 2 # number of fermions with spin down N = N_up + N_down # number of particles t0 = 0.52 # hopping strength U = 1 * t0 # interaction strength pbc = True """Laser pulse parameters""" field = 32.9 # field angular frequency THz F0 = 10 # Field amplitude MV/cm a = 4 # Lattice constant Angstroms """instantiate parameters with proper unit scaling""" lat = hhg(field=field, nup=N_up, ndown=N_down, nx=L, ny=0, U=U, t=t0, F0=F0, a=a, pbc=pbc) """System Evolution Time""" cycles = 10 # time in cycles of field frequency n_steps = 2000 start = 0 stop = cycles / lat.freq times, delta = np.linspace(start, stop, num=n_steps, endpoint=True, retstep=True) """set up parameters for saving expectations later""" parameters = f'-{L}sites-{t0}t0-{U}U-{a}a-{field}field-{F0}amplitude-{cycles}cycles-{n_steps}steps-{pbc}pbc' """create basis""" basis = spinful_fermion_basis_1d(L, Nf=(N_up, N_down), sblock=1, kblock=1) """Create static part of hamiltonian - the interaction b/w electrons"""
pbc = params.pbc2 t_max = params.t_max n_steps = params.n_steps times = params.times delta = params.delta rank = params.rank """instantiate parameters with proper unit scaling""" for gamma in [1, 1e-1, 1e-2, 1e-3]: gamma = gamma * t0 for rank in [16, 128]: for mu in [0.4, 0.6, 0.8, 1]: lat = hhg(nup=N_up, ndown=N_down, nx=L, ny=0, U=U, t=t0, pbc=pbc, gamma=gamma, mu=mu) outfile = './Data/Approx/expectations:{}sites-{}up-{}down-{}t0-{}U-{}t_max-{}steps-{}gamma-{}mu-{}rank-{}pbc.npz'.format( L, N_up, N_down, t0, U, t_max, n_steps, gamma, mu, rank, pbc) lat.gamma = lat.gamma """create basis""" # build spinful fermions basis. Note that the basis _cannot_ have number conservation as the leads inject and absorb # fermions. This is frankly a massive pain, and the only gain we get basis = spinless_fermion_basis_1d(L) #no symmetries # basis = spinful_fermion_basis_1d(L, sblock=1) # spin inversion symmetry # basis = spinful_fermion_basis_1d(L,Nf=(N_up, N_down)) #number symmetry # basis = spinful_fermion_basis_1d(L, Nf=(N_up, N_down),sblock=1) #parity and spin inversion symmetry # basis = spinful_fermion_basis_1d(L, Nf=(N_up, N_down),a=1,kblock=1) #translation symmetry
def compare_response(params, x1, x2, domain, normalized=False): """ Compares the response of two materials :param domain: either "time" or "frequency", determines whether we plot in the spectra or actual response """ if domain == "time": outfile = "./DirectComparisons/TimeDomainComparison-({},{})-({},{})".format( x1[0], x1[1], x2[0], x2[1]) times, current1 = current_expectation(x1, params, return_time=True) current2 = current_expectation(x2, params) if normalized: current1 /= current1.max() current2 /= current2.max() plt.plot(times, current1, label="$U = {} \cdot t_0, a = {}$".format( x1[0] / params.t, x1[1]), color="blue") plt.plot(times, current2, label="$U = {} \cdot t_0, a = {}$".format( x2[0] / params.t, x2[1]), color="red", linestyle="dashed") plt.xlabel("Time") plt.ylabel("Current Density Expectation") plt.legend(loc="upper right") plt.savefig(outfile + ".png") plt.show() elif domain == "frequency": # the lat is for getting the pulse frequency so it does not depend on U lat = hhg(params.field, params.nup, params.ndown, params.nx, 0, 0, params.t) fig, ax = plt.subplots() outfile = "./DirectComparisons/FrequencyDomainComparison-({},{})-({},{})".format( x1[0], x1[1], x2[0], x2[1]) freqs, spect1 = current_expectation_power_spectrum(x1, params) freqs, spect2 = current_expectation_power_spectrum(x2, params) if normalized: spect1 /= spect1.max() spect2 /= spect2.max() ax.semilogy(freqs / lat.freq, spect1, label="$U = {} \cdot t_0, a = {}$".format( x1[0] / params.t, x1[1]), color="blue") ax.semilogy(freqs / lat.freq, spect2, label="$U = {} \cdot t_0, a = {}$".format( x2[0] / params.t, x2[1]), color="red", linestyle="dashed") ax.set_xlabel("Harmonic Order") ax.set_ylabel("Power") # ax.set_xlim((0, 50)) for i in range(1, 100, 2): ax.axvline(i, linestyle="dashed", color="grey") ax.legend(loc="upper right") plt.savefig(outfile + ".png") plt.show() else: raise Exception("Invalid specifier for domain")
if n < partition2: U2.append(U_a2) else: U2.append(U_b2) U2 = np.array(U2) """Laser pulse parameters""" field2 = 32.9 # field angular frequency THz F02 = 10 # Field amplitude MV/cm a2 = 4 # Lattice constant Angstroms """instantiate parameters with proper unit scaling. In this case everything is scaled to units of t_0""" lat = hhg(field=field, nup=N_up, ndown=N_down, nx=L, ny=0, U=U, SO=SO, t=t0, F0=F0, a=a, pbc=pbc) lat2 = hhg(field=field2, nup=N_up2, ndown=N_down, nx=L2, ny=0, U=U, SO=SO2, t=t02, F0=F02, a=a2,
t0 = 0.52 # hopping strength U = 1 * t0 # interaction strength pbc = True """Laser pulse parameters""" field = 32.9 # field angular frequency THz F0 = 10 # Field amplitude MV/cm a = 4 # Lattice constant Angstroms """Parameters for approximating ground state""" delta_U = 0.0001 delta_a = 0.001 """instantiate parameters with proper unit scaling""" lat = hhg(field=field, nup=N_up, ndown=N_down, nx=L, ny=0, U=U, t=t0, F0=F0, a=a, pbc=pbc) # +- dU/2 lat_plus_dU = hhg(field=field, nup=N_up, ndown=N_down, nx=L, ny=0, U=U + (delta_U / 2), t=t0, F0=F0, a=a,
L = 10 # system size N_up = L // 2 + L % 2 # number of fermions with spin up N_down = L // 2 # number of fermions with spin down N = N_up + N_down # number of particles t0 = 0.52 # hopping strength pbc = True """Laser pulse parameters""" field = 32.9 # field angular frequency THz F0 = 10 # Field amplitude MV/cm # target parameters target_U = 1 * t0 target_a = 4 lat = hhg(field, N_up, N_down, L, 0, target_U, t0, F0=F0, a=target_a, pbc=pbc) cycles = 10 n_steps = 2000 start = 0 stop = cycles / lat.freq target_delta = np.linspace(start, stop, num=n_steps, endpoint=True, retstep=True)[1] # add all parameters to the class and create the basis params = Parameters(L, N_up, N_down, t0, field, F0, target_delta, pbc) params.set_basis() # bounds for variables U_upper = 10 * params.t U_lower = 0 a_upper = 10 a_lower = 0 bounds = ((U_lower, U_upper), (a_lower, a_upper))
J_scale = 1 #scaling J for tracking. L_track = L # system size N_up_track = L_track // 2 + L % 2 # number of fermions with spin up N_down_track = L_track // 2 # number of fermions with spin down N = N_up_track + N_down_track # number of particles t0_track = 0.52 # hopping strength # U = 0*t0 # interaction strength U_track = 10 * t0 # interaction strength pbc_track = pbc a_track = a * a_scale """instantiate parameters with proper unit scaling""" lat = hhg(field=field, nup=N_up, ndown=N_down, nx=L, ny=0, U=U, t=t0, F0=F0, a=a, pbc=pbc) lat_track = hhg(field=field, nup=N_up_track, ndown=N_down_track, nx=L_track, ny=0, U=U_track, t=t0_track, F0=F0, a=a_track, pbc=pbc_track) """This is used for setting up Hamiltonian in Quspin."""
def multiple_spectrum_animation(U_over_t0s, parameters, params): lat = hhg(params.field, params.nup, params.ndown, params.nx, 0, 0, params.t) a_values = np.linspace(1, 10, 50) x_ax = current_expectation_power_spectrum( (U_over_t0s[0] * params.t, 1), params, True)[0] / lat.freq data = [] for U_over_t0 in U_over_t0s: try: d = np.load( "./GridAnalysisData/CurrentSpectrumAnimationData-U_over_t{}". format(U_over_t0) + parameters + ".npy") except: d = np.array([ current_expectation_power_spectrum((U_over_t0 * params.t, a), params) for a in a_values ]) np.save( "./GridAnalysisData/CurrentSpectrumAnimationData-U_over_t{}". format(U_over_t0) + parameters + ".npy", d) data.append(d) scatterx = [] scattery = [] for i in range(len(a_values)): temp_time = [] temp_freq = [] for j in range(len(U_over_t0s)): for k in range(len(U_over_t0s)): if j <= k: both = (data[j][i], data[k][i]) temp_time.append(time_domain_objective(both)) temp_freq.append(objective_w_spectrum(both)) temp_time = np.array(temp_time) temp_freq = np.array(temp_freq) scatterx.append(temp_time / temp_time.max()) scattery.append(temp_freq / temp_freq.max()) scatterx = np.array(scatterx) scattery = np.array(scattery) data1, data2, data3 = data U_over_t01, U_over_t02, U_over_t03 = U_over_t0s writer = ani.PillowWriter() fig, axs = plt.subplots(2, 2) fig.set_figheight(9) fig.set_figwidth(12) title = plt.suptitle("$a = 0.000$") axs[0, 0].set_xlabel("Harmonic Order") axs[0, 0].set_ylabel("Power") axs[0, 0].set_title( "Current Power Spectrum at $U = {}\\cdot t_0$".format(U_over_t01)) plot1, = axs[0, 0].semilogy(x_ax, data1[0]) axs[0, 0].set_xlim(0, 75) axs[0, 0].set_ylim(data1.min(), data1.max()) axs[0, 1].set_xlabel("Harmonic Order") axs[0, 1].set_ylabel("Power") axs[0, 1].set_title( "Current Power Spectrum at $U = {}\\cdot t_0$".format(U_over_t02)) plot2, = axs[0, 1].semilogy(x_ax, data2[0]) axs[0, 1].set_xlim(0, 75) axs[0, 1].set_ylim(data2.min(), data2.max()) axs[1, 0].set_xlabel("Harmonic Order") axs[1, 0].set_ylabel("Power") axs[1, 0].set_title( "Current Power Spectrum at $U = {}\\cdot t_0$".format(U_over_t03)) plot3, = axs[1, 0].semilogy(x_ax, data3[0]) axs[1, 0].set_xlim(0, 75) axs[1, 0].set_ylim(data3.min(), data3.max()) axs[1, 1].set_xlabel("Time Domain Cost") axs[1, 1].set_ylabel("Frequency Domain Cost") sctr, = axs[1, 1].plot(scatterx[0], scattery[0], '.b') axs[1, 1].set_xlim(0, 1) axs[1, 1].set_ylim(0, 1) def chart(i): title.set_text("$a = {:.3f}$".format(1 + (9 / 49) * i)) plot1.set_ydata(data1[i]) plot2.set_ydata(data2[i]) plot3.set_ydata(data3[i]) sctr.set_xdata(scatterx[i]) sctr.set_ydata(scattery[i]) animator = ani.FuncAnimation(fig, chart, frames=50, repeat=False) plt.show() animator.save( "./GridAnalysisData/MultipleSpectrumAnimation-U_over_t{}-{}-{}".format( U_over_t01, U_over_t02, U_over_t03) + parameters + ".gif", writer=writer) plt.close(fig)