/****************************************************************************
				AIRSTART.C
				Version 1.0
				6 July 1995

AUTHOR:                         Larry Curcio
		   (Currently: Curcio@Telerama.lm.com)


PURPOSE:
Produces a single interpolated thrust curve from 1 or more piecewise -
linear, coarse thrust curves. If more than 1 curve is specified, then
the interpolated curve is the sum of the input curves. Input curves
may be assigned time offsets (ignition delays), to represent airstart
configurations.

Each input curve may also be assigned a multiplier, to represent
simultaneous ignition of several thrust curves. The multiplier need
not be integral. This feature may be used to mimic thrust curves from
motors with impulses varying from the mean - perhaps by one or two
standard deviations.

Resulting thrust curves are compatible with DIGITRAK or SIMLABV5.
Suitable curves for RASP.C may be obtained by transcribing, in
compatible format, points at the time values in the component curves.
These can also serve as piecewise linear (uninterpolated) DIGITRAK
curves. Future versions of this program will generate such curves
automatically upon request.
****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>

#define _DEBUG

#ifdef _DEBUG
#define Scaffold(a) printf(a)
#define Scaffold1(a, b)  printf(a, b)
#define Scaffold2(a, b, c) printf(a, b, c)
#else
#define Scaffold(a)
#define Scaffold1(a, b)
#define Scaffold2(a, b, c)
#endif


#define CURVE_SIZE 500
#define OUTPUT_SIZE 500
#define MAX_CURVES 50
#define STRLEN 150

#ifndef FALSE
#define FALSE 0
#define TRUE 1
#endif

#ifndef MISSING
#define MISSING -32767
#endif

#define _TURBODOS

#ifdef _TURBODOS
#define CLS clrscr()
#endif

#ifdef  _UNIX
#define CLS system("clear")
#endif

#ifdef _TURBOWIN
#define CLS clrscr()
#endif

static double TotalTb, TotalMp, TotalImpulse;



/*****************************************************************************/
void GetLine(int UpCase, char * cp)
{
  int c;

  for (;;) {
    c = getchar();
    if(UpCase)
      {
      if ((c >= 'a') && (c <= 'z'))
	  c = c + 'A' - 'a';
      }
    if (c == EOF || c == '\n') {
      *cp = 0;
      return;
    }
    *cp++ = c;
  }
}

/****************************************************************************/
int editnum(char * instring)
/* *** EDIT FOR VALID NUMERIC *** */
{
int  numpt=0, numblank=0, numneg=0, notblank=0;

while((*instring !='\0') &&(*instring != '\r'))
  {
  if((*instring < '0') || (*instring >'9'))
    {

    if(*instring == ' ')
      {
      if(notblank) ++numblank;
      else numblank=1;
      }
    else  /* (*instring == ' ') */
    if(*instring == '-')
      {
      ++numneg;
      if(notblank)return(FALSE);
      }
    else if(*instring == '.')++numpt;

    else return(FALSE); /* non-numeric character found */

    notblank=1;
    }
  else notblank=1;
  ++instring;
  }
  if(numblank > 2)return(FALSE);
  if(numpt > 1)   return(FALSE);
  if(numneg > 1)  return(FALSE);
  return(TRUE);
}
/***************************************************************************/
float get_val(char * cp)

/* *** ACCEPT NUMERIC FROM KEYBOARD, EDIT FOR VALIDITY, AND CONVERT *** */
{
  float res;

  if(!editnum(cp))return(MISSING);
  sscanf(cp, "%f", &res);
  return(res);
}

/***************************************************************************/
float Prompt(char * instring, float x)
/* *** PROMPT USER FOR NUMERIC VALUE AND ACCEPT *** */
/* *** NUMERIC VALUE IS FLOATING POINT, BUT MORE VERSATILE WITH CASTS *** */
{
int go_on;
float y;
char response[STRLEN];

go_on=TRUE;

while (go_on)
  {
  y=x;
  printf("%s (%9.4f) ",instring, x);
  GetLine((int) FALSE, response);
  if( response[0] != '\0') y = get_val(response);
  if (y > MISSING)
#ifndef _TURBODOS
     {
     go_on=FALSE;
     }
#else
    {
    go_on=FALSE;
    gotoxy(1,wherey()-1);
    clreol();
    printf("%s (%9.4f) \n\r",instring, y);
    }
  else
    {
    gotoxy(1,wherey()-1);
    clreol();
    }
#endif
  }

return(y);
}
/***************************************************************************/
char get_reply(legend)

/* *** ACCEPT SINGLE CHARACTER REPLY AND PUT INTO UPPER CASE *** */

char legend[];
{
char reply;
char linein[10];
printf("%s ", legend);

do{
  GetLine((int) TRUE, linein);
  reply = linein[0];
  }while (strlen(linein) != 1);

#ifdef _TURBODOS
gotoxy(1,wherey()-1);
printf("%s %c \r", legend, reply);
#endif

return(reply);
}
/***************************************************************************/
int ReadIn(char infilename[], double tin[], double fin[])
{
int i, inlen, NumInt, nin;
char linein[STRLEN], outfilename[STRLEN];
FILE *ifp, *fopen();
double Impulse, Tb, Mp;

CLS;

ifp=fopen(infilename, "r");

fgets(linein, STRLEN, ifp);

Scaffold1("<%s>\n", linein);

fscanf(ifp,"%lf %lf %lf %d", &Impulse, &Mp, &Tb, &NumInt);

Scaffold2("Impulse = %lf, NumInt = %i\n", Impulse, NumInt);
for(nin=0; nin<=NumInt; nin++)
  {
  fscanf(ifp,"%lf %lf ", &tin[nin], &fin[nin]);
  }
  fclose(ifp);
return(NumInt + 1);
}

/****************************************************************************/
void WriteOut(char outfilename[],
	      double Fout[],
	      int nout,
	      double Tout[],
	      double TotalMp
	     )
{
int i, inlen, numint;
char linein[STRLEN];
FILE *ofp, *fopen();
double Impulse, Tb;

CLS;

ofp=fopen(outfilename, "w");

Impulse = (double) 0.0;

Tb = Tout[nout -1];

/* Impulse is known from component curves, but this is best evidence */
for(i=1; i < nout; i++)
   {
   Impulse += (Tout[i] - Tout[i-1]) * (double) 0.5 * (Fout[i] + Fout[i-1]);
   }

nout --;

	  /* Title Line */
fprintf(ofp,"Airstart Configuration\n");
	 /* Summary Line */
fprintf(ofp,"%lf %lf %lf %i \n",Impulse, TotalMp, Tb, nout);


/* Interpolated Data - F, T Reversed, Extra (nonsense) Column Added */
for(i=0; i < nout; i++)
  {
  fprintf(ofp,"%lf %lf 1\n", Fout[i], Tout[i]);
  }
  fprintf(ofp,"%lf %lf 1\n", (double)0.0, (double) Tb);
fclose(ofp);

return;
}
/****************************************************************************/
double Interpolate0(double X[], double Y[], double MidX, int N)
{
int i;

	  /* Find One Interpolated Point */

for(i = 0; (i < N) && (X[i + 1] < MidX); i++);

/*printf("i = %i, F = %lf, T = %lf\n", i, Y[i], X[i]);*/

if(X[i + 1] == MidX) return(Y[i + 1]);
return((MidX - X[i]) * (Y[i+1] - Y[i]) / (X[i+1] - X[i]) + Y[i]);

}
/*****************************************************************************/
int Interpolate(double T[], double F[],
		   double OutF[],
		   double IgnitionDelay, double Factor,
		   int N, double DeltaT, double TimeMultiplier)
{
int j;
double Time, MaxTime;

/* Interpolate Entire Curve and Add to Output Curve */

for(j = 0; j < N; j++) T[j] *= TimeMultiplier;

MaxTime = T[N-1] + IgnitionDelay;

for(Time = IgnitionDelay, j =(int) ((IgnitionDelay / DeltaT) + (double) 0.5) ;
	     Time <= MaxTime;
			       j++, Time += DeltaT)
   {
   OutF[j] += Factor * Interpolate0(T, F, (Time - IgnitionDelay), N);
   }

return(j);


}
/*****************************************************************************/
double GetBurningTime(char FileName[])
{
double Impulse, Mp, Tb;
int NumInt;
FILE * Fp, * fopen();
char Buffer[STRLEN];



Scaffold1("File Name in GBT = <%s>\n", FileName);

Fp=fopen(FileName, "r");
if(Fp != (FILE *) NULL)
  {
  fgets(Buffer, STRLEN, Fp);
  fscanf(Fp,"%lf %lf %lf %i", &Impulse, &Mp, &Tb, &NumInt);
  TotalImpulse += Impulse;
  TotalMp += Mp;

  Scaffold1("Burning Time in GBT = %lf\n",Tb);

  fclose(Fp);
  }
else
  {
  printf("File <%s> not found \n", FileName);
  exit(-1);
  }
return((double) Tb);

}
/*****************************************************************************/
double GetClusterBurningTime(
			     char * FileName[],
			     double IgnitionDelay[],
			     double TimeMultiplier[]
			    )
{
double TotalTb = 0.0, CutoffTime;
int i;

/* Determine Burning time from component curve summary lines */
/* TotalTb = MAX(IgnitionDelay + Tb) */

TotalTb = TotalMp = TotalImpulse = (double) 0.0;

for (i=0; FileName[i] != (char *) NULL; i++)
    {
    if((CutoffTime = TimeMultiplier[i] * GetBurningTime(FileName[i]) + IgnitionDelay[i]) > TotalTb)
      {
      TotalTb = CutoffTime;
      }

    }
return(TotalTb);
}
/*****************************************************************************/

main()
{
int i, ClusterNumber = 1;
double * Curves;
double OutPutCurve[OUTPUT_SIZE];
char * FileName[MAX_CURVES];
char OutFileName[STRLEN];
double Offset[MAX_CURVES], TimeDelay[MAX_CURVES], TimeMultiplier[MAX_CURVES];
double N[MAX_CURVES];
int Nin;
double InBufF[CURVE_SIZE], OutBufF[CURVE_SIZE];
double InBufT[CURVE_SIZE], OutBufT[CURVE_SIZE];
double IgnitionDelay, DeltaT, Time;
CLS;

for(i=0; i < MAX_CURVES; i++)
   {
   N[i] = TimeMultiplier[i] = 1.0;
   Offset[i] = TimeDelay[i] = (double) 0.0;
   }



TotalTb = TotalMp = TotalImpulse = (double) 0.0;

printf("\nEnter Output File Name ");
GetLine((int) FALSE, OutFileName);

printf("\nA Homogeneous Cluster is a collection of like motors");
printf(" ignited simultaneously\n");


ClusterNumber = (int) Prompt("\n\nHow many motor clusters? ",
		   (float) ClusterNumber);

/*printf("\n");   */
for(i=0; i < ClusterNumber; i++)
   {
   if((FileName[i]=malloc(STRLEN))== (char *) NULL)
     {
     printf("SEVERE ERROR!!! CANNOT ALLOCATE FILENAME SPACE. TERMINATING!!\n");
     exit(-5);
     }
   printf("\nEnter Motor (Input) File Name <%i> ", i+1);
   GetLine((int) FALSE, FileName[i]);

   N[i] = (double) Prompt("Number of Motors in Cluster ", (float) N[i]);
   TimeDelay[i] = (double) Prompt("Ignition Delay for Cluster  ", (float) TimeDelay[i]);
   TimeMultiplier[i] = (double) Prompt("Time Multiplier for Cluster ", (float) TimeMultiplier[i]);
   }

   FileName[ClusterNumber] = (char *) NULL;

TotalTb = GetClusterBurningTime(FileName, TimeDelay, TimeMultiplier);

DeltaT = TotalTb / ((double) CURVE_SIZE - (double) 1.0);

Scaffold1("TotalTb = %lf\n", TotalTb);

for(i=0, Time = (double) 0.0; i < CURVE_SIZE; Time += DeltaT, i++)
   {
   OutBufF[i] = (double) 0.0;
   OutBufT[i] = Time;
   }

for(i = 0; i < ClusterNumber; i++)
   {
   Nin = ReadIn(FileName[i], InBufT, InBufF);

   (void) Interpolate(InBufT, InBufF,
		      OutBufF,
		      TimeDelay[i], N[i],
		      Nin, DeltaT, TimeMultiplier[i]);
   }

WriteOut(
	OutFileName,
	OutBufF,
	(int) CURVE_SIZE,
	OutBufT,
	TotalMp
	 );

}
/*****************************************************************************/
