/* 
 * file:   ssman1d_ode.c 
 * author: Hinke Osinga and Reza Rokni --- University of Exeter
 * date:   April 2001
 */

/*
 * ssman_ode(struct Fixpt_DataS*, int)
 *
 * procedure to compute store and display a strong manifold using the
 * data stored in the fixed point data struct.  It requires
 * that the fixed point is in the memory and that eigenvalues and
 * eigenvectors have been computed.
 * The procedure works for vector fields only.
 */

/* The manifold computation can be requested up to a certain arclength 
 * Each time only one integration step is taken and we check the
 * arclength, instead of letting the integrator compute all points at
 * one stage. For this reason, We change the initial point of
 * integration fp->prop_cntl.state[] by the last computed point
 * fp->prop_cntl.traj_segment[1][]. In addition we use a new integer
 * object in the structure SSMan1D (SSMan1D.side) to control the
 * direction of computation "both=0","positive=1" and
 * "negative=2". 5/02/2002 
 */



#include <stdio.h>

#include "constants.h"
#include "defaults.h"
#include "pm.h"
#include "math_utils.h"
#include "flow.h"
#include "fixed.h"
#include <math.h>
#include "ssman1d.h"


int ssman1d_ode(struct Fixpt_DataS* fp, int us, int It)
{
  int     i, ii, jj, j, jc, status = 0, color[3];
  int     ic = 0;
  int     mn, semn;
  int     mx, semx;
  int     n = 0, m = 0;
  int     Iteration_steps = 1;
  int     I = 0;

  int     side = *((int *) pm(GET, "SSMan1D.Side", NULL));
  int     curve = *((int *) pm(GET, "SSMan1D.Curve", NULL));
  int     format = *((int *) pm(GET, "Defaults.Precision", NULL));
  int     tot_dim = fp->prop_cntl.ph_space_dim;
  int     var_dim = tot_dim - 1;
  int     recording = *((int *) pm (GET, "Defaults.Recording", NULL));

  double  State[tot_dim];
  double  arc_length=0;
  double  ARC;
  double  Buffer[2][tot_dim];
  double  delman = fp->eigen_dist;
  double  time_step = fp->prop_cntl.time_step;
  double  arc_length_max;
  

  /*fprintf(stdout,"\n*************It=%d*****************\n",It);*/

  if (us == 0){
    mn = 0;
    semn = 0;
    for (j = 1; j < var_dim; j++){
      if (fp->eval[0][j] < fp->eval[0][mn])  
	mn = j;
    }
    for (j = 0; j < var_dim; j++){
      if (fp->eval[0][j] == fp->eval[0][mn]) 
	semn++;
    }
	
    if (fp->eval[0][mn] < 0 && semn == 1){
      /* This is a strong stable manifold */
      ic = mn;
      fp->prop_cntl.sys_color = STAB_MAN_COLOR;
      fp->prop_cntl.symbol = STAB_MAN_SYMBOL;
      fp->prop_cntl.time_step = time_step / fp->stab_pts;
      fp->prop_cntl.direction = BACKWARD;
      /* require integrator to compute just one point */
      fp->prop_cntl.iter_request = 1; 
      Iteration_steps = fp->stab_steps*fp->stab_pts;
      fp->fptype = STAB_MAN;
      arc_length_max = *((double *) pm(GET, "SSMan1D.Stab_ARC", NULL));
    }
    else{
      /* fprintf(stdout,"\nNo One-Dimensional Strong Stable Manifold\n"); */
      return 0;
    }
  }
	
  if (us == 1){
    mx = 0;
    semx = 0;
    for (j = 1; j < var_dim; j++){
      if (fp->eval[0][j] > fp->eval[0][mx])  
	mx = j;
    }
    for (j = 0; j < var_dim; j++){
      if (fp->eval[0][j] == fp->eval[0][mx]) 
	semx++;
    }
	
    if (fp->eval[0][mx] > EVAL_TOLERANCE && semx == 1){
      /* This is a strong unstable manifold */
      ic = mx;
      fp->prop_cntl.sys_color = UNSTAB_MAN_COLOR;
      fp->prop_cntl.symbol = UNSTAB_MAN_SYMBOL;
      fp->prop_cntl.time_step = time_step / fp->unstab_pts;
      fp->prop_cntl.direction = FORWARD;
      /* require integrator to compute just one point */
      fp->prop_cntl.iter_request = 1;
      Iteration_steps = fp->unstab_steps*fp->unstab_pts;
      fp->fptype = UNSTAB_MAN;
      arc_length_max = *((double *) pm(GET, "SSMan1D.Unstab_ARC", NULL));
    }
    else{
      /* fprintf(stdout,"\nNo One-Dimensional Strong Unstable Manifold\n"); */
      return(-1);
    }
  }

  if (fp->prop_cntl.iter_request > 0){
    if (us == 0)
      fprintf(stdout, "Computing strong stable manifold: ");
    else
      fprintf(stdout, "Computing strong unstable manifold: ");
    fprintf(stdout, "Ev = %.*g\n", format, fp->eval[0][ic]);
    fprintf(stdout, "  Eigenvector: ");
    for (i=0; i<var_dim; i++) 
      fprintf(stdout, "%.*g ", format, fp->evectors[i][ic]);
    fprintf(stdout, "\n");

    /* here we decide which direction should be computed +,-, or both */
    switch (side){
    case 0 :
      n=0, m=2, delman = fp->eigen_dist;
      break;
    case 1 :
      n=0, m=1, delman = fp->eigen_dist;
      break;
    case 2 :
      n=1, m=2, delman = -fp->eigen_dist;
      break;
    default:
      break;
    }

    /* now compute manifold up to arclength given in SSMan1D menu */

    for (jc = n; jc < m  && status >= 0 ; jc++){

      fp->prop_cntl.state[var_dim] = fp->x1[var_dim];
      for (i = 0; i < var_dim; i++){
	State[i] = fp->x1[i] + delman*fp->evectors[i][ic];
	Buffer[0][i] = fp->x1[i] + delman*fp->evectors[i][ic];
      }
      State[var_dim] = fp->x1[var_dim];
      Buffer[0][var_dim] = fp->x1[var_dim];

      arc_length=0; /*initially the arclength of manifold is zero!*/
      for (ii = 0; ii < var_dim; ii++) 
	arc_length += pow((State[ii]-fp->x1[ii]),2);
      arc_length = sqrt(arc_length);


      /*fp->x1[i] is the fixed point
	and fp->prop_cntl.state[i] is the initial point for integration 
	which is in the linear eigenspace at this moment*/

      project(var_dim, fp->prop_cntl.state, fp->prop_cntl.manifold);
      
      i=0;
      /* here we consider both arclength and number of iterations
	 provided in SSMan1D menu */ 

      while (arc_length < arc_length_max && i < Iteration_steps){
	for (ii = 0; ii < tot_dim; ii++) 
	  /* the initial point for integration is State[] */
	  fp->prop_cntl.state[ii] = State[ii];
	i++;
	status = prop_cntl_orbit(&fp->prop_cntl);/* the original integrator*/
	/* growing the arclength */
	ARC = 0;
	for (ii = 0; ii < var_dim; ii++) 
	  ARC += pow(State[ii]-fp->prop_cntl.traj_segment[1][ii],2);
	arc_length += sqrt(ARC);
	/* next initial point for integration is the last computed point */
	for (ii = 0; ii < tot_dim; ii++) {
	  State[ii] = fp->prop_cntl.traj_segment[1][ii];
	  if(i == 1)
	    Buffer[i][ii] = fp->prop_cntl.traj_segment[1][ii];
	  else
	    fp->prop_cntl.traj_segment[i][ii] = 
	      fp->prop_cntl.traj_segment[1][ii];
	}
	/* go to the next integration */
      }
      fprintf(stdout,
	      "\narclength %g is achieved by %d integration steps\n",
	      arc_length,i);
      /* now we are temporally saving the Buffer as computed manifold */
      for (jj = 0; jj < tot_dim; jj++){
	fp->prop_cntl.traj_segment[0][jj] = Buffer[0][jj];
	fp->prop_cntl.traj_segment[1][jj] = Buffer[1][jj];
      }
      /* Here we are doing curvature on fp->prop_cntl.traj_segment[][] */
      if(curve == 0){
	fprintf(stdout,"\nPoint reduction by curvature in processing");
	I = curvature_proc(fp,i,arc_length);
	fprintf(stdout,"\nPoint reduction by curvature finished\n");
	if(I > i)
	  fprintf(stdout,"\nI am confused!!!! I = %d > i = %d\n", I,i);
      }
      else {
	I = i+1;
	fprintf(stdout,"\nPoint reduction by curvature is bypassed\n");
      }
      if (recording && (I > 0)){
	memory_start_new_flow(fp->memory, 1, 0, 0, 
			      I, 0, 1);
	color[0] = fp->prop_cntl.table_color;
	color[1] = fp->prop_cntl.sys_color;
	color[2] = fp->prop_cntl.symbol;
	memory_add_point(fp->memory, NULL, fp->prop_cntl.parameters, color,
			 NULL, NULL, NULL, &(fp->fptype));
	memory_add_points(fp->memory, I,
			  fp->prop_cntl.traj_segment, NULL, NULL, NULL, NULL);
      }
      delman = -delman;  /* so we do both directions ! */      
    }
  }
  
  fp->prop_cntl.time_step = time_step;
  
  return(status);
}
















