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]
Example #2
0
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
Example #3
0
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
Example #4
0
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")
Example #5
0
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
Example #8
0
"""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
Example #10
0
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")
Example #11
0
    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,
Example #13
0
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))
Example #14
0
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."""
Example #15
0
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)