/* tr_solve.c  94.04.06
 * Copyright 1983-1992   Albert Davis
 * solve one step or a transient analysis
 */
#include "ecah.h"
#include "array.h"
#include "error.h"
#include "io.h"
#include "mode.h"
#include "nodestat.h"
#include "options.h"
#include "status.h"
#include "tr.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
	int	tr_solve(int,int);
static	void	advance_time(void);
static	void	clear_arrays(void);
/*--------------------------------------------------------------------------*/
extern       struct ioctrl io;
extern const struct options opt;
extern       struct status stats;
extern 	     struct nodestuff ns;
extern double *reals, *imags;		/* big array allocation base	    */
extern const unsigned aspace;		/* non-zero array elements	    */
extern const double trtime0;		/* time at this iteration	    */
extern int inc_mode;	/* make incremental changes			    */
extern int sim_mode;	/* simulation type (AC, DC, ...)		    */
extern int bypass_ok;
/*--------------------------------------------------------------------------*/
int tr_solve(int itl, int trace)	/* solve one time step		    */
{
 int converged = NO;
 
 stats.iter[iSTEP] = 0;
 advance_time();

 inc_mode = (inc_mode == NO) ? BAD : inc_mode;
 if (opt.foooo == 201){
    if (inc_mode != BAD){
       error(bDANGER, "%u: inc_mode was %d, changed to %d\n",
       		stats.iter[sim_mode],  inc_mode, BAD);
    }
    inc_mode = BAD;
 }

 while (stats.iter[iSTEP] < itl){
    inc_mode = (inc_mode == BAD   ||   stats.iter[iSTEP] == opt.itl[3])
    		? NO : opt.incmode;
    if (trace >= tITERATION){
       tr_print((double)-stats.iter[iSTEP]);
    }
    ++stats.iter[iPRINTSTEP];
    ++stats.iter[iSTEP];
    ++stats.iter[sim_mode];
    ++stats.iter[iTOTAL];
    
    clear_arrays();
    converged = tr_fill();
    if (converged  &&  stats.iter[iSTEP] > 1)
       break;
    solve();
    if (stats.iter[iSTEP] >= opt.itl[8]){
       io.suppresserrors = NO;
    }
    bypass_ok = opt.bypass;
 }
 return converged;
}
/*--------------------------------------------------------------------------*/
static void advance_time(void)
{
 if (sim_mode == sTRAN){
    static double last_iter_time;	
    if (trtime0 > last_iter_time){	/* moving forward */
       int ii;
       for (ii = 1;  ii <= stats.total_nodes;  ii++){
          ns.vt1[ii] = ns.v0[ii];
       }
    }else{				/* moving backward or DC */
       /* don't save voltages.  They're wrong !*/
    }
    last_iter_time = trtime0;
 }
}
/* last_iter_time is initially 0 by C definition.
 * On subsequent runs it will start with an arbitrary positive value.
 * trtime0 starts at either 0 or the ending time of the last run.
 * In either case, (trtime0 > last_iter_time) is false on the first step.
 * This correctly results in "don't save voltages..."
 */
/*--------------------------------------------------------------------------*/
static void clear_arrays(void)
{
 if (!inc_mode){			/* Clear working array */
    int ii;
    (void)memset((void*)reals, 0, (size_t)aspace * sizeof(double));
    for (ii = 1;  ii <= stats.total_nodes;  ii++){
       *AAd(ii,ii) = opt.gmin;		/* gmin fudge */
       ns.i[ii] = 0.;			/* Clear new right side */
    }
 }
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
