/*******************************************************************************
*
* McStas, the neutron ray-tracing package: Vitess_output.comp
*         Copyright 1997-2001 Risoe National Laboratory, Roskilde, Denmark
*
* Component: Vitess_output
*
* %I
* Written by: Kristian Nielsen
* Date: June 6, 2000
* Origin: Risoe/ILL
* Modified by: E. Farhi, Sep 28th, 2001: added spin
*
* Write neutron state parameters to VITESS neutron filename.
*
* %D
* Detector-like component writing neutron state parameters to a
* VITESS neutron filename. Used to interface McStas components or
* simulations into VITESS. Each neutron is 104 bytes.
*
* Note that when standard output is used, as is the default, no
* monitors or other components that produce terminal output must be
* used, or the neutron output from this component will become
* corrupted.
*
* Example: Vitess_output(filename="MySource.vit", bufsize = 10000, progress = 1)
*
* %BUGS
* This component will NOT work with parallel execution (MPI).
*
* %P
* INPUT PARAMETERS
*
* filename: [string]  Filename of neutron file to write. Default is standard output 
* bufsize: [records]  Size of neutron output buffer 
* progress: [flag]    If not zero, output dots as progress indicator 
*
* %E
*******************************************************************************/


DEFINE COMPONENT Vitess_output
DEFINITION PARAMETERS ()
SETTING PARAMETERS (string filename = 0, int bufsize = 10000, int progress = 0)
OUTPUT PARAMETERS ()
/* Neutron parameters: (x,y,z,vx,vy,vz,t,sx,sy,sz,p) */
SHARE
%{
%include "general"
%include "vitess-lib"
%}

DECLARE
%{
char *file;			/* path + filename             */
FILE *hfile;			/* Neutron output filename handle  */
Neutron *obuf;			/* Neutron output buffer       */
int pos;			/* Current position in buffer  */
double p_out;                   /* sum of output weight        */
double p2_out;                  /* square sum of output weight */
%}

INITIALIZE
%{
file=NULL;
hfile=NULL;

#if defined (USE_MPI)
    if (mpi_node_count > 1) {
      exit(printf("Vitess_output: %s: ERROR: This component can not be used in parallel execution mode (MPI). Abort.\n", NAME_CURRENT_COMP));
    }
#endif

  /* Open neutron output filename. */
  if (!filename || !strcmp(filename,"NULL") || !strcmp(filename,"0") || !strcmp(filename,"stdout"))
  {
    hfile = stdout;
  }
  else if (!strlen(filename) || !strcmp(filename, "no_filename"))
  {
    hfile = NULL;
  }
  else
  {
    hfile = fopen((file=FullParName(filename)), "wb");
    if(!hfile)
    {
      fprintf(stderr, "Vitess_output: Error: Cannot open output filename %s.\n", file);
      exit(1);
    }
  }
#ifdef WIN32
  if(hfile==stdout)
  { if(_setmode(_fileno( stdout ), _O_BINARY ) == -1)
    { fprintf(stderr,"Can't set stdout to binary mode\n");
      exit(1);
    }
  }
#endif

  /* Allocate neutron output buffer. */
  obuf = calloc(bufsize, sizeof(Neutron));
  if(!obuf)
  {
    fprintf(stderr, "Vitess_output: Error: Cannot allocate neutron buffer.\n");
    exit(1);
  }
  /* Initialize buffer. */
  pos = 0;
%}

TRACE
%{
  int count;

  /* Flush output buffer if full. */
  if(hfile && pos >= bufsize)
  { count = fwrite(obuf, sizeof(Neutron), bufsize, hfile);
    if(progress)
    {
      fputc('.', stderr);	/* Output progress indicator. */
      fflush(stderr);
    }
    if(count != bufsize)
    {
      fprintf(stderr, "Vitess_output: Error during write of neutron filename.\n");
      exit(1);
    }
    else
    {
      pos = 0;			/* Reposition at start of buffer */
    }
  }
  obuf[pos] = mcstas2vitess(x, y, z, vx, vy, vz, t, sx, sy, sz, p);
  /* The following three lines have references to things that are no longer
     in the McStas vitess libs */
  /* obuf[pos].Color   = vitess_col;
     obuf[pos].ID.IDNo = vitess_ID.IDNo;
     memcpy(obuf[pos].ID.IDGrp, vitess_ID.IDGrp, 2); */

  p_out  += p;
  p2_out += p*p;
  ++pos;
%}
FINALLY
%{
  int count;

  /* Flush output buffer if necessary. */
  if(hfile && pos > 0)
  { count = fwrite(obuf, sizeof(Neutron), pos, hfile);
    if(count != pos)
    {
      fprintf(stderr, "Vitess_output: Error during write of neutron file %s.\n", file);
      exit(1);
    }
  }
  if(progress)
    fprintf(stderr, ".\n");	/* Output final progress indicator. */
  if(obuf)
    free(obuf);
  if(hfile && filename)
    fclose(hfile);
%}
MCDISPLAY
%{
  /* Invisible component. */
%}

END
