/*******************************************************************************
*
* McStas, neutron ray-tracing package
* Copyright 1997-2002, All rights reserved
* Risoe National Laboratory, Roskilde, Denmark
* Institut Laue Langevin, Grenoble, France
*
* Component: Virtual_input
*
* %I
* Written by: E. Farhi
* Date: Sep 28th, 2001
* Version: $Revision: 1.16 $
* Origin: ILL
* Release: McStas 1.6
* Modified by: EF, Oct 2002. make use of shared read-table library.
*
* Source-like component that generates neutron events from an ascii/binary
* 'virtual source' file.
*
* %D
* This component reads neutron events stored from a file, and sends them into
* the instrument. It thus replaces a Source component, using a previously
* computed neutron set. The 'source' file type may be either of text or binary
* format. The component may recognize its format automatically, but you may
* force the file type ('type' parameter). The number of neutron events for the
* simulation is set to the length of the 'source' file times the
* repetition parameter 'repeat_count' (1 by default).
* It is particularly useful to generate a virtual source at a point that few
* neutron reach. A long simulation will then only be performed once, to create
* the 'source' file. Further simulations are much faster if they start from
* this low flux position with the 'source' file.
*
* Possible file formats are:
* 1- text column formatted with lines containing 11 values in the order:
* p x y z vx vy vz t sx sy sz stored into about 83 bytes/n.
* 2- float or double binary files stored into 44 and 88 bytes/n
* (with the 11 values 'p x y z vx vy vz t sx sy sz') for float/double resp.
*
* EXAMPLE:
* To create a 'source' file collecting all neutron states, use:
* COMPONENT MySourceCreator = Virtual_output(file = "MySource.list")
* at the position where will be the Virtual_input.
* Then unactivate the part of the simulation description before (and including)
* the component MySourceCreator. Put the new instrument source:
* COMPONENT Source = Virtual_input(file="MySource.list")
* at the same position as 'MySourceCreator'.
* A Vitess file may be obtained from the 'Vitess_output' component or from a
* Vitess simulation (104 bytes per neutron) and read with Vitess_input.
*
* %P
* INPUT PARAMETERS
* file: Name of the neutron input file [str]
*
* Optional input parameters
* repeat_count: Number of times the source must be generated [1]
* type: May be "text", "float" or "double" to force file type.
* default is text file [str]
* verbose: Display additional information about source, recommanded [0/1]
*
* %E
*******************************************************************************/
DEFINE COMPONENT Virtual_input
DEFINITION PARAMETERS (file=0, type=0)
SETTING PARAMETERS (verbose=0,repeat_count=1)
OUTPUT PARAMETERS (read_block,pos,nrows,Offset,rTable,repeat_number,file_ncount,
mean_vx, mean_vy, mean_vz, mean_dx, mean_dy, mean_dz, n_neutrons,
min_x, min_y, min_z, max_x, max_y, max_z, min_vx, min_vy, min_vz,
max_vx, max_vy, max_vz, first_block, mean_x, mean_y, mean_z)
STATE PARAMETERS (x,y,z,vx,vy,vz,t,s1,s2,p)
POLARISATION PARAMETERS (sx, sy, sz)
SHARE
%{
%include "read_table-lib"
long Virtual_input_Read_Input(char *aFile, char *aType, t_Table *aTable, long *aOffset)
{
long max_lines = 50000;
long length=0;
char bType[32];
if (!aFile) return (0);
if (aType) strcpy(bType, aType);
else strcpy(bType, "???");
Table_Free(aTable);
/* Try to Open neutron input text file. */
if((aFile && aType == NULL) || !strcmp(bType,"text")) {
Table_Read_Offset(aTable, aFile, 0, aOffset, max_lines); /* read data from file into rTable */
strcpy(bType, "text");
}
if (!aTable->data && aType && aType[0] != 't')
Table_Read_Offset_Binary(aTable, aFile, aType, aOffset, max_lines, 11);
return(aTable->rows);
}
%}
DECLARE
%{
int repeat_number=1; /* Neutron repeat of the file */
long pos=0; /* current pos in block */
long nrows=0; /* total nrows in block */
long Offset=0; /* offset in file */
double file_ncount=0; /* total number of neutrons in file */
double n_neutrons=0;
char read_block=1; /* flag to start by reading block */
char first_block=1;
t_Table rTable;
/* statistics on first block */
double mean_x =0, mean_y =0, mean_z =0;
double mean_vx=0, mean_vy=0, mean_vz=0;
double mean_dx=0, mean_dy=0, mean_dz=0;
double min_x = FLT_MAX, min_y = FLT_MAX, min_z = FLT_MAX;
double max_x =-FLT_MAX, max_y =-FLT_MAX, max_z =-FLT_MAX;
double min_vx= FLT_MAX, min_vy= FLT_MAX, min_vz= FLT_MAX;
double max_vx=-FLT_MAX, max_vy=-FLT_MAX, max_vz=-FLT_MAX;
%}
INITIALIZE
%{
Table_Init(&rTable, 0, 0);
if (!file || !repeat_count)
{
fprintf(stderr,"Virtual_input: %s: please give me a file name (file) to read (repeat_count>0).\n", NAME_CURRENT_COMP);
exit(-1);
}
if (type && strstr(type, "Vitess"))
{ fprintf(stderr, "Virtual_input: %s: Vitess files may be read using the Vitess_input component\n", NAME_CURRENT_COMP); exit(-1); }
if (verbose)
printf("Virtual_input: %s: Reading neutron events from file '%s'. Repeat %g time(s)\n", NAME_CURRENT_COMP, file, repeat_count);
%}
TRACE
%{
while (read_block) {
/* read block and increase Offset for next reading */
nrows = Virtual_input_Read_Input(file, type, &rTable, &Offset);
if (!nrows) { /* nrows is 0 if end of file/no file */
if (!file_ncount) {
file_ncount = mcget_run_num(); /* ncount in file */
if (verbose)
printf("Virtual_input: %s: file '%s' contains %g events\n", NAME_CURRENT_COMP, file, file_ncount);
}
Offset = 0; /* reposition to begining of file */
repeat_number++; /* we start a new repeat_count loop */
/* end of simulation if ... */
if (repeat_number > repeat_count) {
if (verbose)
printf("Virtual_input: %s: Ending after %g events (%i repeat count)\n", NAME_CURRENT_COMP, mcget_run_num(), (long)repeat_count);
read_block=0; mcset_ncount(mcget_run_num()); ABSORB;
}
/* else continue reading blocks */
} else { /* block at Offset could be read */
pos = 0; /* position at begining of new block */
read_block = 0;
}
}
/* &p, &x, &y, &z, &vx, &vy, &vz, &t, &sx, &sy, &sz */
mcrestore_neutron(rTable.data,pos, &x, &y, &z, &vx, &vy, &vz, &t, &sx, &sy, &sz, &p);
if (first_block) {
double v;
mean_x += p*x; mean_y += p*y; mean_z += p*z;
mean_vx += p*vx; mean_vy += p*vy; mean_vz += p*vz;
v = sqrt(vx*vx+vy*vy+vz*vz);
if (v)
{ mean_dx += p*fabs(vx/v); mean_dy += p*fabs(vy/v); mean_dz += p*fabs(vz/v); }
if (x < min_x) min_x = x;
if (y < min_y) min_y = y;
if (z < min_z) min_z = z;
if (vx < min_vx) min_vx = vx;
if (vy < min_vy) min_vy = vy;
if (vz < min_vz) min_vz = z;
if (x > max_x) max_x = x;
if (y > max_y) max_y = y;
if (z > max_z) max_z = z;
if (vx > max_vx) max_vx = vx;
if (vy > max_vy) max_vy = vy;
if (vz > max_vz) max_vz = z;
n_neutrons += p;
}
pos++;
p /= repeat_count;
SCATTER;
if (pos >= nrows) { /* reached end of block */
read_block = 1;
if (first_block) {
double n_count_extrapolated=0, mean_v;
/* display statitics for 1st block */
mean_x /= n_neutrons;
mean_y /= n_neutrons;
mean_z /= n_neutrons;
mean_vx /= n_neutrons;
mean_vy /= n_neutrons;
mean_vz /= n_neutrons;
mean_dx /= n_neutrons;
mean_dy /= n_neutrons;
mean_dz /= n_neutrons;
/* now estimates total ncount */
mean_v = sqrt(mean_vx*mean_vx+mean_vy*mean_vy+mean_vz*mean_vz);
n_count_extrapolated = (double)nrows*rTable.filesize/Offset;
if (verbose) {
double mean_k, mean_w=0, mean_L=0;
mean_k = V2K*mean_v;
if (mean_k) mean_L = 2*PI/mean_k;
mean_w = VS2E*mean_v*mean_v;
printf("McStas Virtual Source file %s\nContains about %g neutrons\n", file, n_count_extrapolated);
if (n_count_extrapolated > mcget_ncount())
printf(" (will use only %.3g %% of file)\n", 100*mcget_ncount()/n_count_extrapolated);
printf(" Source size (full width in [m]): ");
printf(" dX=%g dY=%g dZ=%g\n", max_x-min_x, max_y-min_y, max_z-min_z);
printf(" Source center (in [m]): ");
printf(" X0=%g Y0=%g Z0=%g\n", mean_x, mean_y, mean_z);
printf(" Beam divergence (full width in [deg]):");
printf(" dVx=%g dVy=%g dVz=%g\n",
atan(mean_dx)*RAD2DEG,
atan(mean_dy)*RAD2DEG,
atan(mean_dz)*RAD2DEG);
printf(" Beam speed (in [m/s]): ");
printf(" Vx=%g Vy=%g Vz=%g\n", mean_vx, mean_vy, mean_vz);
printf(" Beam mean energy:\n");
printf(" speed=%g [m/s] energy=%g [meV]\n wavelength=%g [Angs] wavevector=%g [Angs-1]\n", mean_v, mean_w, mean_L, mean_k);
}
}
first_block= 0;
}
%}
FINALLY
%{
Table_Free(&rTable);
if (!file_ncount) {
printf("Warning: Virtual_input: %s: file '%s' was not used entirely.\n"
" Intensities may be wrong. Increase ncount value\n",
NAME_CURRENT_COMP, file);
} else {
double tmp;
tmp = mcget_run_num()/file_ncount;
if (fabs(rint(tmp)/tmp-1) > 0.02)
printf("Warning: Virtual_input: %s: simulation finished in the middle of file '%s'\n"
" ncount=%g but file contains %g events\n"
" Intensities may be wrong.\n"
" Increase ncount value to %g or higher.\n",
NAME_CURRENT_COMP, file, mcget_run_num(), file_ncount, file_ncount*repeat_count);
if (mcget_run_num() < file_ncount*repeat_count)
printf("Warning: Virtual_input: %s: not all source %s repetitions were generated.\n"
" Intensities may be wrong.\n"
" Increase ncount value to %g or higher.\n",
NAME_CURRENT_COMP, file, file_ncount*repeat_count);
}
%}
MCDISPLAY
%{
/* A bit ugly; hard-coded dimensions. */
magnify("");
line(0,0,0,0.1,0,0);
line(0,0,0,0,0.1,0);
line(0,0,0,0,0,0.1);
%}
END