import csv
import numpy as np
from numpy import sin, cos, tan, pi, exp
import sys
from matplotlib import pyplot as plt


# physical parameeters
e  = 1.60218e-19      # C";
kB = 1.380658e-23     # JK<sup>-1</sup>";


# circuit parameters
I0 = 1.0e-12
ndiode = 1.0
R = 1.0
T = 300.0
ekBT = e / kB / T / ndiode

# V range to be calculated
Vmin = 0.0
Vmax = 0.7
Vstep = 0.01

# self-consistent parameters
Iini   = 0.0
kmix   = 0.2
eps    = 1.0e-10
nmaxiter = 200
iprintiterval = 10


argv = sys.argv
n = len(argv)
if n >= 2:
    Vmin = float(argv[1])
if n >= 3:
    Vmax = float(argv[2])
if n >= 4:
    Vstep = float(argv[3])
if n >= 5:
    kmin = float(argv[4])

def current(V, I):
    global I0, ekVT, R
    Vd = V - R * I
    return I0 * (exp(ekBT * Vd) - 1.0)


def main():
    global Iini, kmix, eps, nmaxiter, iprintinterval

    print("Solution of diode circuit current by self-consistent method")

    print("")
    xV = []
    yI = []
    for V in np.arange(Vmin, Vmax+1.0e-10, Vstep):
        print("V = {} V".format(V))
        I = Iini
        for i in range(nmaxiter):
            Inext  = current(V, Iini)
            dI = Inext - I
            if i % iprintiterval == 0:
                print("Iter {:5d}: I: {:>16.12f} => {:>16.12f}, dI = {:>10.4g}".format(i, I, Inext, dI))
            if abs(dI) < eps:
                print("  Success: Convergence reached: dI = {} < eps = {}".format(dI, eps))
                break
            I = (1.0 - kmix) * I + kmix * Inext
        else:
            print("  Failed: Convergence did not reach: dI = {} > eps = {}".format(dI, eps))
            return 0

        Iini = I
        xV.append(V)
        yI.append(I)


#=============================
# Plot graphs
#=============================
    fig = plt.figure()

    ax1 = fig.add_subplot(1, 1, 1)

    ax1.plot(xV, yI)
    ax1.set_xlabel("V (V)")
    ax1.set_ylabel("I (A)")

    plt.pause(0.1)
   
    print("Press ENTER to exit>>", end = '')
    input()

    print("")
    print("Usage: python {} Vmin Vmax Vstep kmin".format(argv[0]))
    print("")
    
    return 1


if __name__ == "__main__":
    main()
