/*
 * Copyright (C) 1997, Slava Ilyin
 * changes by V.Ilyin for #-mdl, 6 Sept 2000.
 * Add Comphep-ROOT interface and 
 * parameter dependence for cross sec., Slava Bunichev Mar.4 2007.
 * Copyright (C) 2001-2007, CompHEP Collaboration
 *------------------------------------------------------
 * $Id: runVegas.c,v 1.12 2004/05/10 12:48:15 kryukov Exp $
 *
 * $Log: runVegas.c,v $
 * Revision 1.12  2004/05/10 12:48:15  kryukov
 * This version is equal to 4.4.1
 *
 * Revision 1.11.2.1  2004/04/30 15:09:37  sherstnv
 * Block q_kin.c has been replaced. I took it from old CompHEP_41.10.
 *
 * Revision 1.11  2003/08/25 09:31:10  sherstnv
 * drandXX.c/h files move to service2, so all pathes is changed
 *
 * Revision 1.10  2003/07/20 14:34:37  kryukov
 * Change width menu. Remove rwidth global vars.
 * gwidth=0(fix), 1(overall), 2(running).
 *
 * Revision 1.9  2003/06/25 18:46:41  kryukov
 * *** empty log message ***
 *
 * Revision 1.8  2003/04/22 09:01:19  kryukov
 * Apply indent to improve readability of files
 *
 * Revision 1.7  2003/04/21 16:11:47  kryukov
 * Remove misprint: Gev -> GeV
 *
 * Revision 1.6  2003/04/20 08:54:39  kryukov
 * Remove some misprints
 *
 * Revision 1.5  2003/04/08 11:18:17  kryukov
 * Change algorithm for counting negPoints: if(fabs(ret_val)<computer_eps)...
*/
#include <unistd.h>
#include <stdarg.h>
#include <math.h>

#include "chep_crt/include/crt_util.h"
#include "service2/include/files.h"
#include "service2/include/tptcmac.h"
#include "service2/include/drandXX.h"
#include "service2/include/os.h"
#include "out_ext.h"

#include "cut.h"
#include "4_vector.h"
#include "q_kin.h"
#include "regul.h"
#include "rw_sess.h"
#include "subproc.h"
#include "vegas.h"
#include "strfun.h"
#include "alphas2.h"
#include "histogram.h"
#include "evnt_menu.h"
#include "runVegas.h"
#include "num_serv.h"
#include "roothisto.h"

extern double computer_eps;

int nSess = 1;
double rapidity = 0;
mcintr_ mcintr_1 = { 10000, 5, 0 };

static vegasGrid *veg_Ptr = NULL;
static int hFill = 0;
vegas_integral integral = { 0, 0, 0, 0, 0, 0 };

int
WriteVegasGrid (FILE * f)
{
  if (veg_Ptr)
    {
      int i, j;
      double *x = veg_Ptr->x_grid;
      fprintf (f, " Vegas_grid: dim=%d  size=%d\n", veg_Ptr->ndim,
	       veg_Ptr->ndmx);
      for (i = 0; i < veg_Ptr->ndim; i++)
	{
	  for (j = 0; j <= veg_Ptr->ndmx; j++)
	    fprintf (f, " %.15E", *(x++));
	  fprintf (f, "\n");
	}
    }
  else
    fprintf (f, " Vegas_grid: dim=%d  size=%d\n", 0, 0);
  return 0;
}

int
ReadVegasGrid (FILE * f)
{
  int i, j, ndim, ndmx;
  double *x;

  if (veg_Ptr)
    {
      vegas_finish (veg_Ptr);
      veg_Ptr = NULL;
    }
  fscanf (f, " Vegas_grid: dim=%d  size=%d\n", &ndim, &ndmx);
  if (ndim && ndmx)
    {
      veg_Ptr = vegas_init (ndim, ndmx);
      x = veg_Ptr->x_grid;
      for (i = 0; i < ndim; i++)
	for (j = 0; j <= ndmx; j++)
	  fscanf (f, " %lf", (x++));
    }
  return 0;
}

static int nCall;
/*$Log */
static double badPoints;
static double negPoints;

static void
printLn (FILE * iprt, int *line, char *format, ...)
{
  va_list args;
  char dump[STRSIZ];
  va_start (args, format);
  vsprintf (dump, format, args);
  va_end (args);

  goto_xy (1, *line);
  print ("%53s", "");
  goto_xy (1, *line);
  print ("%s\n", dump);
  (*line)++;
  if (*line >= maxRow () - 2)
    *line = 8;
  else
    {
      scrcolor (Blue, BGmain);
      print ("====================================================");
    }
  if (iprt)
    {
      fprintf (iprt, "%s\n", dump);
      fflush (iprt);
    }
}

static double
func_ (double *x, double wgt)
{
  int err = 0;
  double ret_val = 0.;
  double factor_0;
  double q;

  double ytilda;

  nCall++;
/* ** call kinematics preparation of scalar products */
/*  mkmom (x, &factor_0);*/
  mkmom (x, &factor_0, &ytilda);
  if (!factor_0)
    goto exi;

/*  lorrot (rapidity, nin_ + nout_);*/
  lorrot (rapidity + ytilda, nin_ + nout_);
  factor_0 *= calcCutFactor ();
  if (!factor_0)
    goto exi;

/* ** call for 'running strong coupling constant' */
  q = qcd_Scale_chep ();
  alf_ (q);

  ret_val = factor_0 * sqme_ (proces_1.nsub, pvect, &err);
  if (err)
    badPoints += (ret_val > 0 ? ret_val * wgt : -ret_val * wgt);
  if (fabs (ret_val) < computer_eps)
    negPoints += ret_val * wgt;
exi:

  if (hFill)
    fillHists (ret_val * wgt);

  return ret_val;
}

/*
static double
crosssec (void)
{
  int i;
  double sd;
  double avgi;
  int first = 1;
  int ndim = 0;
  double result;

  int init = 0;

  ndim = imkmom ();


  if (init && veg_Ptr)
    {
      vegas_finish (veg_Ptr);
      veg_Ptr = NULL;
    }
  if (!veg_Ptr)
    veg_Ptr = vegas_init (ndim, 50);

  correctHistList ();

  mcintr_1.ncall0 /= 2;
  generateVegasCubs (veg_Ptr, &mcintr_1.ncall0);
  mcintr_1.ncall0 *= 2;

// *** Main cycle 

  if (integral.n_it == 0)
    {
      integral.s0 = 0;
      integral.s1 = 0;
      integral.s2 = 0;
      integral.nCallTot = 0;
    }

  for (i = 1; i <= mcintr_1.itmx0; ++i)
    {
      nCall = 0;
      first = 0;
      negPoints = 0;
      badPoints = 0;
      hFill = 1;
      if (vegas_int (veg_Ptr, mcintr_1.ncall0, 1.5, func_, &avgi, &sd))
	break;
      integral.old = 1;
      negPoints /= nCall;
      badPoints /= nCall;
      integral.nCallTot += nCall;

      sd = 1 / (sd * sd);
      integral.s0 += sd;
      integral.s1 += avgi * sd;
      integral.s2 += avgi * avgi * sd;
    }

  result = integral.s1 / integral.s0;

  init = 0;

  integral.s0 = 0;
  integral.s1 = 0;
  integral.s2 = 0;
  integral.n_it = 0;
  integral.nCallTot = 0;
  clearHists ();

  vegas_finish (veg_Ptr);
  veg_Ptr = vegas_init (ndim, 50);

  integral.n_it = 0;
  clearHists ();
  integral.old = 0;
  nSess++;

  return (result);
}
*/

int
runVegas (int init)
{
  int i;
  double sd;
  double avgi;
  char mess[25];
  int first = 1;
  FILE *iprt = NULL;
  int mode;
  void *pscr = NULL;
  static int n_Line = 7;
  int ndim = 0;

  ndim = imkmom ();

  if (nin_ == 2)
    strcpy (mess, " Cross section [pb] ");
  else
    strcpy (mess, "  Width     [GeV]   ");

/* ** save current session parameters */
  w_sess__ (NULL);
/* ** open protocol and resulting files */

  {
    char fname[50];
    sprintf (fname, "%sprt_%d", outputDir, nSess);
    iprt = fopen (fname, "a");
    if (ftell (iprt) == 0)
      {
	fprintf (iprt,
		 "    CompHEP kinematics module \n The session parameters:\n");
	w_sess__ (iprt);
	fprintf (iprt, "===================================\n");
      }
  }

/* **  initkinematics */
  if (init && veg_Ptr)
    {
      vegas_finish (veg_Ptr);
      veg_Ptr = NULL;
    }
  if (!veg_Ptr)
    veg_Ptr = vegas_init (ndim, 50);

  correctHistList ();

  mcintr_1.ncall0 /= 2;
  generateVegasCubs (veg_Ptr, &mcintr_1.ncall0);
  mcintr_1.ncall0 *= 2;

/* *** Main cycle */
  if (!integral.old || n_Line == 7)
    {
      n_Line = 7;
      scrcolor (Blue, BGmain);
      printLn (iprt, &n_Line, " #IT  %20s Error %%    nCall   chi**2", mess);
    }

  for (;;)
    {
      char strmen[] = "\030"
	" Itmx   =    N2         "
	" nCall  =    N1         "
	" Set  Distributions     "
	" Start integration      "
/*	" Parameter dependence   "*/
	" Display Distributions  "
	" Combine ROOT-hist      "
	" Clear statistic        "
	" Clear  grid            " " Generate events        ";


      improveStr (strmen, "N1", "%d", mcintr_1.ncall0);
      improveStr (strmen, "N2", "%d", mcintr_1.itmx0);

      menu1 (54, 7, "", strmen, "n_veg_*", &pscr, &mode);
      switch (mode)
	{
	case 0:
	  if (iprt)
	    fclose (iprt);
	  return 0;
	case 1:
	  correctInt (50, 12, "Enter new value ", &mcintr_1.itmx0, 1);
	  break;
	case 2:
	  correctLong (50, 12, "Enter new value ", &mcintr_1.ncall0, 1);
	  mcintr_1.ncall0 /= 2;
	  generateVegasCubs (veg_Ptr, &mcintr_1.ncall0);
	  mcintr_1.ncall0 *= 2;
	  break;
	case 3:
	  editHist ();
	  break;
	case 4:
	  if (integral.n_it == 0)
	    {
	      integral.s0 = 0;
	      integral.s1 = 0;
	      integral.s2 = 0;
	      integral.nCallTot = 0;
	    }

	  for (i = 1; i <= mcintr_1.itmx0; ++i)
	    {
	      char errtxt[100] = "";

	      nCall = 0;
	      first = 0;
	      negPoints = 0;
	      badPoints = 0;
	      hFill = 1;
	      if (vegas_int
		  (veg_Ptr, mcintr_1.ncall0, 1.5, func_, &avgi, &sd))
		break;
	      integral.old = 1;
	      negPoints /= nCall;
	      badPoints /= nCall;
	      integral.nCallTot += nCall;
	      scrcolor (FGmain, BGmain);
	      printLn (iprt, &n_Line, "%3d    %12.4E     %10.2E %8d ",
		       ++integral.n_it, avgi, 100 * sd / ABS (avgi), nCall);
	      if (negPoints < 0)
		sprintf (errtxt, " Negative points %.1G%%;",
			 -100 * negPoints / (avgi - 2 * negPoints));
	      if (badPoints)
		sprintf (errtxt + strlen (errtxt),
			 "Bad Precision %.1G%%;",
			 100 * badPoints / (avgi - 2 * negPoints));

	      if (errtxt[0])
		{
		  scrcolor (Red, BGmain);
		  printLn (iprt, &n_Line, "%s", errtxt);
		}
	      sd = 1 / (sd * sd);
	      integral.s0 += sd;
	      integral.s1 += avgi * sd;
	      integral.s2 += avgi * avgi * sd;
	    }

	  if (integral.n_it > 1)
	    {
	      scrcolor (FGmain, BGmain);
	      printLn (iprt, &n_Line, " < >   %12.4E     %10.2E %8d %8.1G",
		       integral.s1 / integral.s0,
		       100 * sqrt (integral.s0) / ABS (integral.s1),
		       integral.nCallTot,
		       (integral.s2 -
			integral.s1 * integral.s1 / integral.s0) /
		       (integral.n_it - 1));
	    }
	  init = 1;
	  messanykey (54, 11, "Integration is over");
	  break;
/*
	case 5:
	  {
	    paramdependence (crosssec, processch, "Cross section [GeV]");

	    init = 0;

	    integral.s0 = 0;
	    integral.s1 = 0;
	    integral.s2 = 0;
	    integral.n_it = 0;
	    integral.nCallTot = 0;
	    clearHists ();
	    vegas_finish (veg_Ptr);
	    veg_Ptr = vegas_init (ndim, 50);

	    integral.n_it = 0;
	    clearHists ();
	    integral.old = 0;
	    nSess++;

	    first = 1;
	    ndim = 0;

	    ndim = imkmom ();
	    if (init && veg_Ptr)
	      {
		vegas_finish (veg_Ptr);
		veg_Ptr = NULL;
	      }
	    if (!veg_Ptr)
	      veg_Ptr = vegas_init (ndim, 50);

	    correctHistList ();
	    mcintr_1.ncall0 /= 2;
	    generateVegasCubs (veg_Ptr, &mcintr_1.ncall0);
	    mcintr_1.ncall0 *= 2;
	  }
	  break;
*/
	case 5:
	  showHist ();
	  break;

	case 6:
	  combine_root ();
	  break;

	case 7:
	  integral.s0 = 0;
	  integral.s1 = 0;
	  integral.s2 = 0;
	  integral.n_it = 0;
	  integral.nCallTot = 0;

	  clearHists ();
	  messanykey (54, 13, "Old results for integral\n"
		      "and distributions\nare deleted.\n"
		      "But grid is saved");
	  break;
	case 8:
	  vegas_finish (veg_Ptr);
	  veg_Ptr = vegas_init (ndim, 50);
	  init = 1;
	  messanykey (57, 11, "OK");
	  break;
	case 9:
	  {
	    char fname[50];

	    sprintf (fname, "%sevents_%d.txt", outputDir, nSess);

	    hFill = 0;
	    menu_EventGenerator (veg_Ptr, func_, fname, iprt, init);
	    init = 0;
	  }
	  break;
	}
    }
}
