/*******************************************************************************
*
* McXtrace, X-ray tracing package
*         Copyright, All rights reserved
*         DTU Physics, Kgs. Lyngby, Denmark
*         Synchrotron SOLEIL, Saint-Aubin, France
*
* Component: Flex_monitor_3D
*
* %I
* Written by: Erik B Knudsen & Peter Willendrup
* Date: Oct '20
* Origin: DTU Physics
*
* Flexible monitor.
*
* %D
* A square 3D single monitor that measures intensity (or something else) as a function of three selectable variables or parameters.
* The 3D data is saved as a series of 2D datasets, which names are filename_index
*
* Example: Flex_monitor_3D(nU1=20, nU2=20, nU3=20, filename="Output", ustring1="x", ustring2="y", ustring1="z", Umin1=-.1, Umax1=.1, Umin2=-.1, Umax2=.1, Umin3=-.1, Umax3=.1)
*
* %P
* INPUT PARAMETERS:
*
* Umin1: []             Minimum U1 to detect
* Umax1: []             Maximum U1 to detect
* nU1: [1]              Number of U1 channels
* Umin2: []             Minimum U1 to detect
* Umax2: []             Maximum U1 to detect
* nU2: [1]              Number of U1 channels
* Umin3: []             Minimum U3 to detect
* Umax3: []             Maximum U3 to detect
* nU3: [1]              Number of U3 channels
* filename: [string]    Name of file in which to store the detector image
* restore_xray: [1]  If set, the monitor does not influence the particle state
* uid1: [1]             Integer index of uservar to be monitored. Overrides ustring1.
* uid2: [1]             Integer index of uservar to be monitored. Overrides ustring2.
* uid3: [1]             Integer index of uservar to be monitored. Overrides ustring3.
* ustring1: [string]    Name of variable U1 (user or particle state parameter as a string) to be monitored.
* ustring2: [string]    Name of variable U2 (user or particle state parameter as a string) to be monitored.
* ustring3: [string]    Name of variable U3 (user or particle state parameter as a string) to be monitored.
* signal: [string]      Name of variable to be used as an additive signal to be monitored. Default is intensity.
* nowritefile: [1]      Flag to indicate if monitor should not save any data.
*
* OUTPUT PARAMETERS:
*
* U_N: []               Array of particle counts
* U_p: []               Array of particle weight counts
* U_p2: []              Array of second moments
*
* %E
*******************************************************************************/
DEFINE COMPONENT Flex_monitor_3D

DEFINITION PARAMETERS ()

SETTING PARAMETERS (nU1=20, nU2=20, nU3=20, string filename=0,
 		    Umin1, Umax1, uid1=-1, string ustring1="", 
		    Umin2, Umax2, uid2=-1, string ustring2="", 
		    Umin3, Umax3, uid3=-1, string ustring3="", 
		    restore_xray=0, string signal="p", int nowritefile=0)
OUTPUT PARAMETERS ()

DECLARE
%{
  DArray3d U_N;
  DArray3d U_p;
  DArray3d U_p2;

  char username1[128];
  char username2[128];
  char username3[128];
  char signalname[128];
%}

INITIALIZE
%{

  U_N =  create_darr3d(nU3,nU1,nU2);
  U_p =  create_darr3d(nU3,nU1,nU2);
  U_p2 = create_darr3d(nU3,nU1,nU2);

  if(uid1!=-1){
    snprintf(username1,127,"uservar%d",uid1);
  }else{
    snprintf(username1,127,"%s",ustring1);
  }
  if(uid2!=-1){
    snprintf(username2,127,"uservar%d",uid2);
  }else{
    snprintf(username2,127,"%s",ustring2);
  }
  if(uid3!=-1){
    snprintf(username3,127,"uservar%d",uid3);
  }else{
    snprintf(username3,127,"%s",ustring3);
  }
  snprintf(signalname,127,"%s",signal);

  // Use instance name for monitor output if no input was given
  if (!strcmp(filename,"\0")) sprintf(filename,"%s",NAME_CURRENT_COMP);
%}

TRACE
%{
  double U1,U2,U3;
  int suc1,suc2,suc3,suc4;
  if(uid1!=-1){
    U1 = particle_getuservar_byid(_particle,uid1,&suc1);
  }else{
    U1 = particle_getvar(_particle,ustring1,&suc1);
  }
  if(uid2!=-1){
    U2 = particle_getuservar_byid(_particle,uid2,&suc2);
  }else{
    U2 = particle_getvar(_particle,ustring2,&suc2);
  }
  if(uid3!=-1){
    U3 = particle_getuservar_byid(_particle,uid3,&suc3);
  }else{
    U3 = particle_getvar(_particle,ustring3,&suc3);
  }
  
  int i = floor((U1-Umin1)*nU1/(Umax1-Umin1));
  int j = floor((U2-Umin2)*nU2/(Umax2-Umin2));
  int k = floor((U3-Umin3)*nU3/(Umax3-Umin3));
  if(!suc1 && i >= 0 && i < nU1)
    {
      if(!suc2 && j >= 0 && j < nU2)
	{
	  if(!suc3 && k >= 0 && k < nU3)
	    {
	      double pp=particle_getvar(_particle,signal,&suc4);
	      double p2 = pp*pp;
              #pragma acc atomic
	      U_N[k][i][j] = U_N[k][i][j] +1;
              #pragma acc atomic
	      U_p[k][i][j] = U_p[k][i][j] + pp;
              #pragma acc atomic
	      U_p2[k][i][j] = U_p2[k][i][j] + p2;
	      SCATTER;
	    }
	}
    }
  
  if (restore_xray) {
    RESTORE_XRAY(INDEX_CURRENT_COMP, x, y, z, kx, ky, kz, phi, t, Ex, Ey, Ez, p);
  }
%}

SAVE
%{
  if (!nowritefile) {
    int k;
    char filename_k[256];
    char label_k[128];
    for(k=0; k<nU3; k++) {
      sprintf(filename_k,"%s_%i",filename,k);
      sprintf(label_k,"Flex monitor 3D slice %i of %i",k,nU3);
      DETECTOR_OUT_2D(
        "Flex monitor 3D",
        username1, username2,
        Umin1, Umax1, Umin2, Umax2, nU1, nU2,
        &U_N[k][0][0],&U_p[k][0][0],&U_p2[k][0][0],
        filename_k);
    }
  }
%}

FINALLY
%{
  destroy_darr3d(U_N);
  destroy_darr3d(U_p);
  destroy_darr3d(U_p2);
%}

MCDISPLAY
%{
%}

END
