/* 
 * Copyright (C) 1997, Alexander Pukhov 
 * Add boost to any rest frames, Slava Bunichev Mar.4 2007.
 * Copyright (C) 2001-2007, CompHEP Collaboration
 *------------------------------------------------------
 * $Id: phys_val.c,v 1.5 2003/06/25 18:46:41 kryukov Exp $
 *
 * $Log: phys_val.c,v $
 * Revision 1.5  2003/06/25 18:46:41  kryukov
 * *** empty log message ***
 *
 * Revision 1.4  2003/04/22 09:01:19  kryukov
 * Apply indent to improve readability of files
 *
 * Revision 1.3  2003/04/20 17:55:02  kryukov
 * Clean up warnings during make
 *
*/

#include <math.h>
#include <ctype.h>

#include "out_ext.h"

#include "4_vector.h"
#include "subproc.h"
#include "kinaux.h"
#include "userFun.h"
#include "const.h"
#include "phys_val.h"


static void lorenc(double *mom, double *p_frame, double *p_trans)
{
  double v_frame[4];
  double mod_v_frame;
  double G;
  double coef;
  double p_v;

  v_frame[1]= p_frame[1]/p_frame[0];
  v_frame[2]= p_frame[2]/p_frame[0];
  v_frame[3]= p_frame[3]/p_frame[0];

  mod_v_frame= sqrt(v_frame[1]*v_frame[1]+
                    v_frame[2]*v_frame[2]+
                    v_frame[3]*v_frame[3]);

  p_v = mom[1]*v_frame[1]+
        mom[2]*v_frame[2]+
        mom[3]*v_frame[3];
 
  G = 1./sqrt(1.-mod_v_frame*mod_v_frame);

  coef = G *( (G*p_v)/(G+1.) -mom[0]);

  p_trans[1]= mom[1] +v_frame[1]*coef;
  p_trans[2]= mom[2] +v_frame[2]*coef;
  p_trans[3]= mom[3] +v_frame[3]*coef;
  p_trans[0]= G*(mom[0] -p_v);
}

/*
double 
calcPhysVal (char key, char *lv)
{
  double p1, p2, p3, q1, q2, q3, mp, mq, cs, dl;
  int j;


  int np1 = 4 * (lv[0] - 1), np2 = 4 * (lv[1] - 1);
  double s = 0;
  int i = 0;
  double pp[4] = {0, 0, 0, 0};

  switch (key)
    {
    case 'A':
    case 'C':
      p1 = pvect[np1 + 1];
      p2 = pvect[np1 + 2];
      p3 = pvect[np1 + 3];

      q1 = pvect[np2 + 1];
      q2 = pvect[np2 + 2];
      q3 = pvect[np2 + 3];

      cs = (p1 * q1 + p2 * q2 + p3 * q3) /
	sqrt ((p1 * p1 + p2 * p2 + p3 * p3) * (q1 * q1 + q2 * q2 + q3 * q3));
      if (key == 'A')
	return acos (cs) * 180 / M_PI;
      return cs;
    case 'J':
      p1 = pvect[np1 + 1];
      p2 = pvect[np1 + 2];
      p3 = pvect[np1 + 3];
      mp = sqrt (p1 * p1 + p2 * p2 + p3 * p3);

      q1 = pvect[np2 + 1];
      q2 = pvect[np2 + 2];
      q3 = pvect[np2 + 3];
      mq = sqrt (q1 * q1 + q2 * q2 + q3 * q3);

      cs = (p1 * q1 + p2 * q2) / sqrt ((p1 * p1 + p2 * p2) * (q1 * q1 + q2 * q2));
      cs = acos (cs);

      dl = (mp + p3) * (mq - q3) / (mp - p3) / (mq + q3);
      dl = 0.5 * log (dl);

      return sqrt (dl * dl + cs * cs);

    case 'P':
      {
	double mtot, mtot2, ms, md, pcm, p;

	pinf_ (proces_1.nsub, lv[0], NULL, &mp);
	pinf_ (proces_1.nsub, lv[1], NULL, &mq);

	for (j = 0; j < 4; j++)
	  pp[j] += pvect[np1 + j] + pvect[np2 + j];

	p = pp[1] * pp[1] + pp[2] * pp[2] + pp[3] * pp[3];
	mtot2 = pp[0] * pp[0] - p;
	mtot = sqrt (mtot2);

	ms = mp + mq;
	md = mp - mq;

	pcm = sqrt ((mtot2 - ms * ms) * (mtot2 - md * md)) / (2 * mtot);
	s = pp[1] * pvect[np1 + 1] + pp[2] * pvect[np1 + 2] + pp[3] * pvect[np1 + 3];

	return (s * pp[0] - pvect[np1] * p) / (sqrt (p) * mtot * pcm);

      }
    case 'E':
      while (lv[i] != 0)
	s += pvect[(lv[i++] << 2) - 4];
      return s;

    case 'T':
      {
	i = 0;
	do
	  for (j = 1; j < 3; j++)
	    pp[j] += pvect[4 * (lv[i] - 1) + j];
	while (lv[++i]);
	return sqrt (pp[1] * pp[1] + pp[2] * pp[2]);
      }
    case 'S':
    case 'M':
      {
	do
	  {
	    if (lv[i] > nin_)
	      for (j = 0; j < 4; j++)
		pp[j] += pvect[4 * (lv[i] - 1) + j];
	    else
	      for (j = 0; j < 4; j++)
		pp[j] -= pvect[4 * (lv[i] - 1) + j];
	  }
	while (lv[++i]);
	s = pp[0] * pp[0];
	for (j = 1; j < 4; j++)
	  s -= pp[j] * pp[j];
	if (key == 'M')
	  return sqrt (s);
	return s;
      }
    case 'Y':
      do
	for (j = 0; j < 4; j += 3)
	  pp[j] += pvect[4 * (lv[i] - 1) + j];
      while (lv[++i]);
      return log ((pp[0] + pp[3]) / (pp[0] - pp[3])) / 2;
    case 'N':
      do
	for (j = 0; j < 4; j++)
	  pp[j] += pvect[4 * (lv[i] - 1) + j];
      while (lv[++i]);
      mp = sqrt (pp[1] * pp[1] + pp[2] * pp[2] + pp[3] * pp[3]);
      return log ((mp + pp[3]) / (mp - pp[3])) / 2;

    case 'U':
      return userFunction (lv);
    }
  return 0;
}
*/

double 
calcPhysVal (char key, char *lv, char *restframe)
{
  double p1, p2, p3, q1, q2, q3, mp, mq, cs, dl;
  int j;

  int np1 = 4 * (lv[0] - 1), np2 = 4 * (lv[1] - 1);
  double s = 0;
  int i = 0;
  int ii=0;
  double pp[4] = {0, 0, 0, 0};
  double newrf[4] = {0, 0, 0, 0};
  double lab[4] = {0, 0, 0, 0};
  double boost[4] = {0, 0, 0, 0};
  double pboost[400]={0};

/* ----- New Rest Frame -----------*/
   ii = 0;
   do
     { newrf[0] += pvect[4 * (restframe[ii] - 1) + 0];
       newrf[1] += pvect[4 * (restframe[ii] - 1) + 1];
       newrf[2] += pvect[4 * (restframe[ii] - 1) + 2];
       newrf[3] += pvect[4 * (restframe[ii] - 1) + 3];
     } 
   while (restframe[++ii]);

   for(ii=0;ii<100;ii++)
     { lab[0] = pvect[4*ii + 0];
       lab[1] = pvect[4*ii + 1];
       lab[2] = pvect[4*ii + 2];
       lab[3] = pvect[4*ii + 3];

       if(restframe[0]==0)
         { boost[0] = lab[0];
           boost[1] = lab[1];
           boost[2] = lab[2];
           boost[3] = lab[3];
         } 
        else {
          lorenc(lab,newrf,boost);
        }

       pboost[4*ii + 0] = boost[0];
       pboost[4*ii + 1] = boost[1];
       pboost[4*ii + 2] = boost[2];
       pboost[4*ii + 3] = boost[3];
     } 
/*---------------------------------*/

  switch (key)
    {
    case 'A':
    case 'C':
      p1 = pboost[np1 + 1];
      p2 = pboost[np1 + 2];
      p3 = pboost[np1 + 3];

      q1 = pboost[np2 + 1];
      q2 = pboost[np2 + 2];
      q3 = pboost[np2 + 3];

      cs = (p1 * q1 + p2 * q2 + p3 * q3) /
	sqrt ((p1 * p1 + p2 * p2 + p3 * p3) * (q1 * q1 + q2 * q2 + q3 * q3));
      if (key == 'A')
	return acos (cs) * 180 / M_PI;
      return cs;
    case 'J':
      p1 = pboost[np1 + 1];
      p2 = pboost[np1 + 2];
      p3 = pboost[np1 + 3];
      mp = sqrt (p1 * p1 + p2 * p2 + p3 * p3);

      q1 = pboost[np2 + 1];
      q2 = pboost[np2 + 2];
      q3 = pboost[np2 + 3];
      mq = sqrt (q1 * q1 + q2 * q2 + q3 * q3);

      cs = (p1 * q1 + p2 * q2) / sqrt ((p1 * p1 + p2 * p2) * (q1 * q1 + q2 * q2));
      cs = acos (cs);

      dl = (mp + p3) * (mq - q3) / (mp - p3) / (mq + q3);
      dl = 0.5 * log (dl);

      return sqrt (dl * dl + cs * cs);

    case 'P':
      {
	double mtot, mtot2, ms, md, pcm, p;

	pinf_ (proces_1.nsub, lv[0], NULL, &mp);
	pinf_ (proces_1.nsub, lv[1], NULL, &mq);

	for (j = 0; j < 4; j++)
	  pp[j] += pboost[np1 + j] + pboost[np2 + j];

	p = pp[1] * pp[1] + pp[2] * pp[2] + pp[3] * pp[3];
	mtot2 = pp[0] * pp[0] - p;
	mtot = sqrt (mtot2);

	ms = mp + mq;
	md = mp - mq;

	pcm = sqrt ((mtot2 - ms * ms) * (mtot2 - md * md)) / (2 * mtot);
	s = pp[1] * pboost[np1 + 1] + pp[2] * pboost[np1 + 2] + pp[3] * pboost[np1 + 3];

	return (s * pp[0] - pboost[np1] * p) / (sqrt (p) * mtot * pcm);

      }
    case 'E':
      {
       while (lv[i] != 0)
       	s += pboost[(lv[i++] << 2) - 4];
      return s;
      } 
    case 'T':
      {
	i = 0;
	do
	  for (j = 1; j < 3; j++)
	    pp[j] += pboost[4 * (lv[i] - 1) + j];
	while (lv[++i]);
	return sqrt (pp[1] * pp[1] + pp[2] * pp[2]);
      }
    case 'S':
    case 'M':
      {
	do
	  {
	    if (lv[i] > nin_)
	      for (j = 0; j < 4; j++)
		pp[j] += pboost[4 * (lv[i] - 1) + j];
	    else
	      for (j = 0; j < 4; j++)
		pp[j] -= pboost[4 * (lv[i] - 1) + j];
	  }
	while (lv[++i]);
	s = pp[0] * pp[0];
	for (j = 1; j < 4; j++)
	  s -= pp[j] * pp[j];
	if (key == 'M')
	  return sqrt (s);
	return s;
      }
    case 'Y':
      do
	for (j = 0; j < 4; j += 3)
	  pp[j] += pboost[4 * (lv[i] - 1) + j];
      while (lv[++i]);
      return log ((pp[0] + pp[3]) / (pp[0] - pp[3])) / 2;
    case 'N':
      do
	for (j = 0; j < 4; j++)
	  pp[j] += pboost[4 * (lv[i] - 1) + j];
      while (lv[++i]);
      mp = sqrt (pp[1] * pp[1] + pp[2] * pp[2] + pp[3] * pp[3]);
      return log ((mp + pp[3]) / (mp - pp[3])) / 2;

    case 'U':
      return userFunction (lv);
    }
  return 0;
}

int 
checkPhysVal (char *name, char *key, char *plist)
{
  int i = 0;
  int j = 0;
  int n, k;

  while (name[i] == ' ' && name[i] != 0)
    i++;
  *key = name[i++];

  if (*key == 0)
    return 0;
  *key = toupper (*key);
  if (strchr ("ACEJMPSTUYN", *key) == NULL)
    return 0;


  if (*key == 'U')
    {
      for (; name[i] && name[i] != ' ' && i < 6; i++)
	plist[j++] = name[i];
      plist[j] = 0;
      for (; name[i]; i++)
	if (name[i] != ' ')
	  return 0;
      return 1;
    }


  for (; name[i] && name[i] != ' '; i++)
    {
      n = name[i] - '0';
      if (n <= 0 || n > nin_ + nout_)
	return 0;
      for (k = 0; k < j; k++)
	if (plist[k] == n)
	  return 0;
      plist[j++] = n;
    }
  plist[j] = 0;
  for (; name[i]; i++)
    if (name[i] != ' ')
      return 0;


  if (strchr ("CAJP", *key) != NULL && strlen (plist) != 2)
    return 0;

  if (strchr ("MS", *key) != NULL && strlen (plist) < 2)
    return 0;

  if (strchr ("JPT", *key) != NULL)
    for (i = 0; i < strlen (plist); i++)
      {
	if (plist[i] <= nin_)
	  return 0;
      }

  if (strchr ("MNY", *key) && !spole_ (plist))
    return 0;

  if (nin_ == 1)
    {
      if (strchr ("TYN", *key))
	return 0;
      if (strchr ("ACP", *key) && (plist[0] == 1 || plist[1] == 1))
	return 0;
    }

  return 1;
}

void 
xName (char key, char *plist, char *xname, char *units)
{
  int i;

  switch (key)
    {
    case 'A':
      sprintf (units, "Deg");
      sprintf (xname, "Angle(p%d,p%d)", (int) labs (plist[0]), (int) labs (plist[1]));
      break;
    case 'C':
      strcpy (units, "");
      sprintf (xname, "Cosine(p%d,p%d)", (int) labs (plist[0]), (int) labs (plist[1]));
      break;
    case 'E':
      sprintf (units, "GeV");
      sprintf (xname, "Energy E%d", (int) labs (plist[0]));
      i = 1;
      while (plist[i])
	sprintf (xname + strlen (xname), "+E%d", (int) labs (plist[i++]));
      break;
    case 'J':
      strcpy (units, "");
      sprintf (xname, "J(p%d,p%d)", (int) labs (plist[0]), (int) labs (plist[1]));
      break;
    case 'M':
      sprintf (units, "GeV");
      sprintf (xname, "Mass{p%d", (int) labs (plist[0]));
      i = 1;
      while (plist[i])
	sprintf (xname + strlen (xname), "+p%d", (int) labs (plist[i++]));
      strcat (xname, "}");
      break;
    case 'P':
      strcpy (units, "");
      sprintf (xname, "S.M.Cosine(p%d,p%d)", (int) labs (plist[0]), (int) labs (plist[1]));
      break;
    case 'S':
      sprintf (units, "GeV^2");
      sprintf (xname, "(p%d", plist[0]);
      i = 1;
      while (plist[i])
	sprintf (xname + strlen (xname), "+p%d", (int) labs (plist[i++]));
      strcat (xname, ")^2");
      break;
    case 'T':
      sprintf (units, "GeV");
      sprintf (xname, "Transverse momentum Pt%d", (int) labs (plist[0]));
      i = 1;
      while (plist[i])
	sprintf (xname + strlen (xname), "+Pt%d", (int) labs (plist[i++]));
      break;
    case 'Y':
      strcpy (units, "");
      sprintf (xname, "Rapidity_");
      for (i = 0; plist[i]; i++)
	sprintf (xname + strlen (xname), "%d", (int) labs (plist[i]));
      break;
    case 'N':
      strcpy (units, "");
      sprintf (xname, "pseudo-rapidity_");
      for (i = 0; plist[i]; i++)
	sprintf (xname + strlen (xname), "%d", (int) labs (plist[i]));
      break;
    case 'U':
      sprintf (units, "?");
      strcpy (xname, plist);
      break;
    }
}
