************************************************************************************
Equilibrium Semiconductor Homework Solution
************************************************************************************

Instructions
=================

Sample solutions are given below. Use the sample solution codes 
to generate reference plots.  Compare them with plots you have obtained yourself.
I have tried to show you how the codes we wrote earlier 
in "eqsemiv1.py" can be reused using ``import``.

I have a habit of providing default parameter values to all of my functions, but you
are not required to do this for homework codes.

You can start from reading the :func:`main` function which calls
the functions for solving the 4 homework problems. 
These functions are very similar
to the ones we created earlier, but each still requires a bit work.

A function is written for each homework problem, parameters can be 
changed. Default parameters are also provided inside the function.
An array is "mutable" - so it is best to not use an array as default. Instead, 
I use a special object "None" as default value, when it is None, it means no default 
array values are provided, so I will generate an array inside the function.

If you do not understand "mutable", you can ignore that part. All you have to do is
to not forget providing an array of a function call's argument that is an array.
    
You can change your background doping vale easily and observe
how the semiconductor type is changed from one type to its opposite type as 
doping is changed.


Sample solution
=================================

First make sure you have the "eqsemiv1.py" from our 
previous tutorial. Again, the name should not be changed. 
Download the file :download:`here <eqsemihw1.py>` and place 
it in the same directory. Run.

Alternatively, in the same folder, create a new file, 
copy the codes below and paste them into your own codes  ::

    '''
    Try writing a few function for each task below and call the functions from the main() function. 
    You can use my example functions as a starting point. Only minor changes are required in all cases.

    Plot out p and n versus Nd, Nd range is from 1e14 to 1e20. You have a background Na of 1e16.
    Plot out bands Ec, Ev, Ef, Ei versus Nd, Nd range is from 1e14 to 1e20. You have a background Na of 1e16.
    Plot out p and n versus Na, Na range is from 1e14 to 1e20. You have a background Nd of 0.
    Plot out bands Ec, Ev, Ef, Ei versus Na, Na range is from 1e14 to 1e20. You have a background Nd of 0.

    '''


    # use newer python3 print and 1/2=0.5 
    from __future__ import division, print_function


    # import what need from what we wrote earlier in eqsemiv1.py
    from eqsemiv1 import ni300k, nc300k, nv300k, eg300k, find_energies, find_pn
    from numpy import logspace, empty
    from myplot import myplot, show, new_ax, ColorCycler


    def plot_pn_vs_nd_with_na(nds = None, na=0):

        # make a plot of p/n versus nd
        
        # create an array of nd, on log scale, from 1e5 to 1e20
        if nds == None:
            nds = logspace(5, 20, 50)
        
        # create place holders for p and n arrays
        ps = empty(len(nds))
        ns = empty(len(nds))

        # iterate over array nds, we also need index, so use "enumerate"
        for idx, nd in enumerate(nds):
            # !!! Note indentation is used here to define body of the for loop
            solution = find_pn(nd=nd, na=na, ni=ni300k)
            # see how we get p and n by key (name) in dictionary
            ps[idx] = solution['p']
            ns[idx] = solution['n']
        
        ax = new_ax()
        
        linep, axpn, fig = myplot(ax=ax,
               x=nds,
               y=ns,
               xlog=True,
               ylog=True,
               color='r',
               label='n',
               xlabel='$N_d (/cm^3)$',
               ylabel='$p,n(/cm^3)$')
        
        # continue to plot p on the same ax
        linen, axpn, fig = myplot(ax=ax, x=nds, y=ps, color='b',
               label='p')
        
        # save figure to a PDF
        # fig is an object, and has a method savefig
        #fig.savefig('pnvsnd.pdf')
        fig.savefig('pnvsnd.png')
      
       


    def plot_bands_vs_nd_with_na(nds=None, na=0):

        solution = find_energies(nd=1e16, na=0, eg=eg300k, nc=nc300k, nv=nv300k, t=300)
        
        keys = solution.keys()
        
        bands = dict()


        if nds == None: # if nds is not provided, create one
            # create an array of nd, on log scale, from 1e5 to 1e20
            nds = logspace(5, 20, 50)
            
        num_nds = len(nds)
        
        
        for key in keys:
            bands[key] = empty(num_nds)
        
        for idx, nd in enumerate(nds):
            solution = find_energies(nd=nd, na=na, eg=eg300k, nc=nc300k, nv=nv300k, t=300)
            for key in keys:
                bands[key][idx] = solution[key]
        
        # now data is ready, let us plot them out
        
        cc = ColorCycler()
        
        axbands = new_ax()
        
        for key in keys:
            myplot(ax=axbands,
                   x=nds,
                   y=bands[key],
                   xlog=True,
                   color=cc.next(),
                   label=key)
        
        axbands.set_xlabel('$N_d(/cm^3)$')
        axbands.set_ylabel('$Energies (eV)$')
        
        # change bottom of y-axis so that ev=0 can be clearly seen
        axbands.set_ylim(bottom=-0.2)

    def plot_pn_vs_na_with_nd(nas = None, nd=0):

        # make a plot of p/n versus nd
        
        # create an array of na, on log scale, from 1e5 to 1e20
        if nas == None:
            nas = logspace(5, 20, 50)
        
        # create place holders for p and n arrays
        ps = empty(len(nas))
        ns = empty(len(nas))

        # iterate over array nds, we also need index, so use "enumerate"
        for idx, na in enumerate(nas):
            # !!! Note indentation is used here to define body of the for loop
            solution = find_pn(nd=nd, na=na, ni=ni300k)
            # see how we get p and n by key (name) in dictionary
            ps[idx] = solution['p']
            ns[idx] = solution['n']
        
        ax = new_ax()
        
        linep, axpn, fig = myplot(ax=ax,
               x=nas,
               y=ns,
               xlog=True,
               ylog=True,
               color='r',
               label='n',
               xlabel='$N_a (/cm^3)$',
               ylabel='$p,n(/cm^3)$')
        
        # continue to plot p on the same ax
        linen, axpn, fig = myplot(ax=ax, x=nas, y=ps, color='b',
               label='p')
        
        # save figure to a PDF
        # fig is an object, and has a method savefig
        #fig.savefig('pnvsnd.pdf')
        fig.savefig('pnvsnd.png')
        
        return axpn, fig
        


    def plot_bands_vs_na_with_nd(nas=None, nd=0):

        solution = find_energies(nd=1e16, na=0, eg=eg300k, nc=nc300k, nv=nv300k, t=300)
        
        keys = solution.keys()
        
        bands = dict()


        if nas == None: 
            # create an array of nd, on log scale, from 1e5 to 1e20
            nas = logspace(5, 20, 50)
            
        num_nas = len(nas)
        
        
        for key in keys:
            bands[key] = empty(num_nas)
        
        for idx, na in enumerate(nas):
            solution = find_energies(nd=nd, na=na, eg=eg300k, nc=nc300k, nv=nv300k, t=300)
            for key in keys:
                bands[key][idx] = solution[key]
        
        # now data is ready, let us plot them out
        
        cc = ColorCycler()
        
        axbands = new_ax()
        
        for key in keys:
            myplot(ax=axbands,
                   x=nas,
                   y=bands[key],
                   xlog=True,
                   color=cc.next(),
                   label=key)
        
        axbands.set_xlabel('$N_a(/cm^3)$')
        axbands.set_ylabel('$Energies (eV)$')
        
        # change bottom of y-axis so that ev=0 can be clearly seen
        axbands.set_ylim(bottom=-0.2)



    def main():
        
        # Homework 1 and 2  
        nds = logspace(14, 20, 200)
        na = 1e16

        plot_pn_vs_nd_with_na(nds=nds, na=na)
        
        plot_bands_vs_nd_with_na(nds=nds, na=na)
        

        # Homework 3 and 4

        nas = logspace(14, 20, 200)
        nd = 1e16

        plot_pn_vs_na_with_nd(nas=nas, nd=nd)
        
        plot_bands_vs_na_with_nd(nas=nas, nd=nd)
        
        

    if __name__ == '__main__':
        main()
        show()