/* -*- tab-width: 4 -*-
 *
 * Electric(tm) VLSI Design System
 *
 * File: Diode.java
 *
 * Copyright (c) 2003, Static Free Software. All rights reserved.
 *
 * Electric(tm) is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Electric(tm) is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.sun.electric.tool.simulation.interval;

import com.sun.electric.util.math.MutableInterval;

/**
 * This class contains a set of expressions which defines model equations
 * of diode.
 */

public class Diode
{
    final static double CHARGE = 1.6021918e-19;
    final static double CONSTboltz  = 1.3806226e-23;
    final static double REFTEMP = 300.15;

    ExprEval ev = new ExprEval();
    ExprEval.DoubleConstExpr is = ev.newConst(1e-14);
    ExprEval.DoubleConstExpr gmin = ev.newConst(0.0);
    //ExprEval.DoubleConstExpr gmin = ev.newConst(1e-12);
    ExprEval.DoubleConstExpr vt = ev.newConst(CONSTboltz * REFTEMP / CHARGE);
    ExprEval.DoubleConstExpr vd = ev.newConst();
    ExprEval.DoubleExpr cd;
    ExprEval.DoubleExpr gd;
    //ExprEval.DoubleConstExpr rs;
    //ExprEval.DoubleConstExpr n;
    //ExprEval.DoubleConstExpr tt;
    //ExprEval.DoubleConstExpr cjo;
    //ExprEval.DoubleConstExpr wj;
    //ExprEval.DoubleConstExpr m;
    //ExprEval.DoubleConstExpr fc;
    //ExprEval.DoubleConstExpr temp;

    Diode() {
		is.setName("is");
		gmin.setName("gmin");
		vt.setName("vt");
		vd.setName("vd");
		// evd = exp(vd/vt)
		ExprEval.DoubleExpr evd = vd.divide(vt).exp(); evd.setName("evd");
		// cdp = is*(evd-1)
		ExprEval.DoubleExpr cdp = is.multiply(evd.subtract(ev.newConst(1.0))); cdp.setName("cdp");
		// gdp = (is/vt)*evd
		ExprEval.DoubleExpr gdp = is.divide(vt).multiply(evd); gdp.setName("gdp");
		// arg = vt*(3/e)/vd
		ExprEval.DoubleExpr arg = vt.multiply(ev.newConst(3.0/Math.E)).divide(vd); arg.setName("arg");
		// arg3 = arg*arg*arg
		ExprEval.DoubleExpr arg3 = arg.multiply(arg).multiply(arg); arg3.setName("arg3");
		// cdm = -is*(1 + arg3)
		ExprEval.DoubleExpr cdm = is.negate().multiply(ev.newConst(1.0).add(arg3)); cdm.setName("cdm");
		// gdm = is*3*arg3/vd
		ExprEval.DoubleExpr gdm = is.multiply(ev.newConst(3)).multiply(arg3).divide(vd); gdm.setName("gdm");
		// direct = (vd >= -3*vt)
		ExprEval.BooleanExpr direct = vd.ge(ev.newConst(-3).multiply(vt)); direct.setName("direct");
		// cd0 = (direct ? cdp : cdm)
		ExprEval.DoubleExpr cd0 = direct.ite(cdp,cdm); cd0.setName("cd0");
		// gd0 = (direct ? gdp : gdm)
		ExprEval.DoubleExpr gd0 = direct.ite(gdp,gdm); gd0.setName("gd0");
		// cd = cd0 + gmin*vd
		cd = cd0.add(gmin.multiply(vd)); cd.setName("cd");
		// gd = gd0 +gmin
		gd = gd0.add(gmin); gd.setName("gd");
    }

    /**
     * Test program plots in raw file diode current versus voltage:
     * at interval [v-delta,v+delta],
     * and at 3 point of this interval - ceneter and borders
     */
    public static void plotDiode(String filePath) {
		System.out.println("Plotting Diode graph to file " + filePath);
		Diode d = new Diode();
		//d.ev.printAll(false);

		double delta = 0.001;
		int numPoints = 10000;
		int numVars = 11;
		RawFile raw = new RawFile(numPoints + 1, numVars);
		raw.setVar(0, "vd", "voltage");
		raw.setVar(1, "j",  "current");
		raw.setVar(2, "g",  "conductance");
		raw.setVar(3, "jm", "current");
		raw.setVar(4, "gm", "conductance");
		raw.setVar(5, "jp", "current");
		raw.setVar(6, "gp", "conductance");
		raw.setVar(7, "jl", "current");
		raw.setVar(8, "gl", "conductance");
		raw.setVar(9, "jh", "current");
		raw.setVar(10,"gh", "conductance");

		for (int k = 0; k <= numPoints; k++)
		{
			double vd = -0.2 + 0.3 / numPoints * k;
			raw.set(k, 0, vd);

			d.vd.setV(vd);
			d.ev.calcAll();
			raw.set(k, 1, d.cd.v());
			raw.set(k, 2, d.gd.v());
	    
			d.vd.setV(vd-delta);
			d.ev.calcAll();
			raw.set(k, 3, d.cd.v());
			raw.set(k, 4, d.gd.v());
	    
			d.vd.setV(vd+delta);
			d.ev.calcAll();
			raw.set(k, 5, d.cd.v());
			raw.set(k, 6, d.gd.v());

			d.vd.setInterval(vd-delta,vd+delta);
			d.ev.calcIntervalAll();
			raw.set(k, 7, d.cd.inf());
			raw.set(k, 8, d.gd.inf());
			raw.set(k, 9, d.cd.sup());
			raw.set(k, 10, d.gd.sup());
	    
		}
		raw.write(filePath);
		//raw.writeBinary(filePath, null);
    }

    
    public static void main (String argv[])
    {
		plotDiode("diode.raw");
    }
}
