/* tr_reviw.c  94.08.23
 * Copyright 1983-1992   Albert Davis
 * review the solution after solution at a time point
 * Set up events, evaluate logic inputs, truncation error.
 * Recommend adjusted step size. (tr->approxtime)
 * and say why (tr->control)
 */
#include "ecah.h"
#include "branch.h"
#include "error.h"
#include "mode.h"
#include "options.h"
#include "status.h"
#include "tr.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
	void	tr_review(transient_t*);
	double	tr_review_rl(branch_t*);
	double	tr_review_ll(branch_t**);
/*--------------------------------------------------------------------------*/
extern const struct options opt;
extern	     struct status stats;
extern const int sim_phase;	/* simulation phase (init_dc, tran, ...)    */
/*--------------------------------------------------------------------------*/
void tr_review(transient_t *tr)
{
 static double rtime;	/* next time by iteration count and smoothing */
 double tetime;		/* next time by device dependent recommendations */
 			/* (usually truncation error) */
 
 time_start(&(stats.review));
 ++stats.iter[iTOTAL];
 if (sim_phase == pINIT_DC){
    rtime = tr->dtmax/ 100.;	/* set (guess) initial internal step */
    rtime = tr->time0 + MAX(rtime, tr->dtmin);
    tr->control = scITER_A;
 }else{
    double adt; 	/* actual dt most recently used */ 
    double rdt;		/* review dt was recommended by PREVIOUS review */
    rdt = rtime - tr->time1;
    adt = tr->time0 - tr->time1;
    if (adt > rdt + tr->dtmin)
       error(bDANGER, "internal error: step control (%g,%g)\n", adt, rdt);

    if (stats.iter[iSTEP] > opt.itl[4]){	/* too many iterations */
       rtime = tr->time1 + adt / opt.trstepshrink;  /* try again, smaller step */
       tr->control = scITER_R;
    }else if (stats.iter[iSTEP] > opt.itl[3]){	/* too many iterations */
       rtime = tr->time0 + adt;			/* no growth */
       tr->control = scITER_A;
    }else{					/* too few iterations */
       rtime = tr->time0 + tr->dtmax;		/* ok to use bigger steps */
       tr->control = scSKIP;
       if (rtime > tr->time0 + rdt * opt.trstepgrow){
	  rtime = tr->time0 + rdt * opt.trstepgrow; /* limit to rdt*2 */
	  tr->control = scRDT;
       }
       if (rtime > tr->time0 + adt*opt.trstepgrow  &&  rtime > tr->time0 + rdt){
	  if (rdt > adt * opt.trstepgrow)
	     rtime = tr->time0 + rdt;
	  else					/* limit to max(rdt,adt*2) */
	     rtime = tr->time0 + adt * opt.trstepgrow;
	  tr->control = scADT;
       }
    }
 }
 tetime = tr_review_rl(firstbranch_dev());	/* trunc error, etc. */
 if (tetime < rtime){
    tr->control = scTE;
    tr->approxtime = tetime;
 }else{
    tr->approxtime = rtime;
 }
 time_stop(&(stats.review));
}
/*--------------------------------------------------------------------------*/
double tr_review_rl(branch_t *brh)
{
 double devicetime, worsttime;
 const branch_t *stop;

 worsttime = BIGBIG;
 if (exists(brh)){
    stop = brh;
    do {
       devicetime = tr_review_branch(brh);
       if (devicetime < worsttime){
          worsttime = devicetime;
       }
    } while (brh=nextbranch_dev(brh),  brh != stop);
 }
 return worsttime;
}
/*--------------------------------------------------------------------------*/
double tr_review_ll(branch_t **bl)
{
 double devicetime, worsttime;
 branch_t *brh;

 worsttime = BIGBIG;
 if (bl){
    for (brh = *bl;  exists(brh);  ++bl){
       devicetime = tr_review_branch(brh);
       if (devicetime < worsttime)
          worsttime = devicetime;
    }
 }
 return worsttime;
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
