/* Convert raw mountain profile created by 3DField into connected profile as
seen by an underground detector.  This program outputs the solid angle
described by the edges of the hill profile on the first line of labxyz.dat and
the coordinates of the lattice points of the the hill profile. 

author: Alfred Tang
Chinese University of Hong Kong 2005
Kansas State University         2007

***************************************************
Paramters:

delta        Orientation of the lab as measured from the northerly
             axis in the clock direction.  
OmegaX       Solid angles corresponding to the 4 edges of the 3D map.
             X=1,2,3,4.  OmegaX start from (1,1) and go around (nx,1), (nx,ny)
             and (1,ny) respectively.
zmin         z minimum
d            vertical offset
scl          scale factor for x-y coordiantes
indf         input filename of the raw data file generated by 3DField
labx         x coordinate of the detector on the 3DField raw map
laby         y coordiante of the detector on the 3DField raw map

Notes:
scl is determined by choosing 2 points on the 3DField output map and
correlating them to a physical distance according to the scale on the
original base map.  labx and laby are simply read out by pointing the
pointer in 3DField to the detector site.  A quick start guide for using
3DField can be found at http://www.phys.ksu.edu/personal/atang/3dfield.htm.

inputs and outputs:
==================

labxyz.dat     fixed output with weight (to be used with the MUSIC program)
hillxyz.dat    fixed output without weight
rawxyz.dat     unfixed output without weight

Compilation
===========
In UNIX/LINUX, type at prompt:
$ gcc -o fixdat fixdat.c -lm
To run, type:
$ ./fixdat

*/

#include <stdio.h>
#include <math.h>
#define NRANSI
#include "nrutil.h"
#include "nr.h"
#include "nrutil.c"
#define pi 3.1415926535897932384626433
#define zmin  0.
#define delta 0.
#define d     0.
#define scl   8.496595e5
#define indf  "rawxyz.dat"
#define labx  0.53523668375
#define laby  0.39781780625

void ra(double x, double y, double z, double *th, double *ph);
double costh(double *x, double *y, double **z, int i, int j, int nx, int ny);
double ncos(double the);

int main() {
  int i,j,l,nmax=0,nx=0,ny=1,ox=0,oy=0,px,py,bz,mx,my,itemp,jtemp;
  int m,n,count=0,**flag,x1,x2,y1,y2,cut,ns;
  float x0,y0,z0;
  double x,y,z,th,ph,tand,rmin=1.e20,depth,ctmin=1.,ctemp;
  double omega1,omega2,omega3,omega4,omega;
  double xtemp,ytemp,rtemp=1.e20,ztemp,r,zslope,islope,slope;
  double *xv,*yv,**zv,**the,**phi;
  FILE *fp1,*fp2,*fp3;

  fp1=fopen(indf,"r");
  fp2=fopen("labxyz.dat","w");
  fp3=fopen("border.dat","w");
  fscanf(fp1,"%f%f%f",&x0,&y0,&z0);
  x=(double)x0;
  y=(double)y0;
  z=(double)z0;
  ytemp=y;
  while(!feof(fp1)) {
    nx++;
    fscanf(fp1,"%f%f%f",&x0,&y0,&z0);
    x=(double)x0;
    y=(double)y0;
    z=(double)z0;
    if(y!=ytemp) {
      ny++;
      nx=0;
    }
    r=sqrt((x-labx)*(x-labx)+(y-laby)*(y-laby));
    depth=sqrt(r*scl*r*scl+(z*100.+d)*(z*100.+d));
    if(depth<rmin) rmin=depth;
    if(r<rtemp) {
      rtemp=r;
      ox=nx;
      oy=ny;
    }
    ytemp=y;
    nmax++;
  }
  oy=ny-oy;
  printf("relative coords of detector: %f\t%f\n",labx,laby);
  printf("number of x,y indices and grid points: %d\t%d\t%d\n",nx,ny,nmax);
  printf("indices of origin: %d\t%d\n",ox,oy);
  printf("relative distance between actual and indexed origin: %e\n",rtemp);
  printf("minimum r (cm): %f\n",rmin);
  printf("suggested E_mu cutoff (GeV) for simulation: %f\n",
	 500.*(exp(.35*rmin/100000.*2.65)-1.));
  fclose(fp1);

  xv=dvector(1,nx);
  yv=dvector(1,ny);
  zv=dmatrix(1,nx,1,ny);
  the=dmatrix(1,nx,1,ny);
  phi=dmatrix(1,nx,1,ny);
  flag=imatrix(1,nx,1,ny);

  fp1=fopen(indf,"r");
  fscanf(fp1,"%f%f%f",&x0,&y0,&z0);
  x=(double)x0;
  y=(double)y0;
  z=(double)z0;
  ytemp=y;
  px=1;
  py=ny;
  z=z*100.+d;
  if(z<0.) z=0.;
  zv[px][py]=z;
  while(!feof(fp1)) {
    px++;
    fscanf(fp1,"%f%f%f",&x0,&y0,&z0);
    x=(double)x0;
    y=(double)y0;
    z=(double)z0;
    if(y!=ytemp) {
      py--;
      px=1;
    }
    if(px==py) {
      xv[px]=(x-labx)*scl;
      yv[py]=(y-laby)*scl;
    }
    if (!feof(fp1)) {
      z=z*100.+d;
      if(z<0.) z=0.;
      zv[px][py]=z;
    }
    ytemp=y;
  }

  for(i=1;i<=nx;i++) {
    for(j=1;j<=ny;j++) {
      bz=1;
      if(zv[i][j]<zmin) bz=0;

      zslope=(zv[i][j]-zmin)/sqrt(xv[i]*xv[i]+yv[j]*yv[j]);

      mx=i-ox;
      slope=yv[j]/xv[i];
      if(mx>0) {
	for(l=1;(l<mx-1)&&(bz==1);l++) {
	  islope=(1.*(j-oy))/(1.*(i-ox));
	  jtemp=(int)(j*1.-islope*l);
	  ytemp=yv[j]-slope*(xv[i]-xv[i-l]);
	  ztemp=zv[i][j]-zslope*sqrt((xv[i]-xv[i-l])*(xv[i]-xv[i-l])
				     +ytemp*ytemp);
	  if(zv[i-l][jtemp]<ztemp) bz=0;
	}
      }
      if(mx<0) {
	for(l=1;(l<-mx-1)&&(bz==1);l++) {
	  islope=(1.*(j-oy))/(1.*(i-ox));
	  jtemp=(int)(j*1.-islope*l);
	  ytemp=yv[j]-slope*(xv[i]-xv[i+l]);
	  ztemp=zv[i][j]-zslope*sqrt((xv[i]-xv[i+l])*(xv[i]-xv[i+l])
				     +ytemp*ytemp);
	  if(zv[i+l][jtemp]<ztemp) bz=0;
	}
      }
      if((mx=0)&&(j>oy)) {
	for(l=1;(l<j-oy-1)&&(bz==1);l++) {
	  ztemp=zv[i][j]-zslope*sqrt(xv[i]*xv[i]+yv[j-l]*yv[j-l]);
	  if(zv[i][j-l]<ztemp) bz=0;
	}
      }
      if((mx=0)&&(j<oy)) {
	for(l=1;(l<-j+oy-1)&&(bz==1);l++) {
	  ztemp=zv[i][j]-zslope*sqrt(xv[i]*xv[i]+yv[j+l]*yv[j+l]);
	  if(zv[i][j+l]<ztemp) bz=0;
	}
      }

      ra(xv[i],yv[j],zv[i][j],&th,&ph);
      the[i][j]=th;
      phi[i][j]=ph;

      if((bz==1)&&(costh(xv,yv,zv,i,j,nx,ny)>0.)) flag[i][j]=1;
      else flag[i][j]=0;
    }
  }

  tand=tan(delta*pi/180.);
  x1=(int)(oy*tand);
  y1=(int)(ox*tand);
  x2=(int)((ny-oy)*tand);
  y2=(int)((nx-ox)*tand);
  if((ox-x1<=1)||(ny-y1<=oy)||(nx-x2<=ox)||(oy-y2<=1)) {
    printf("error: delta too large\n");
    return 0;
  }
  omega1=fabs(phi[1][2]-phi[2][1])*ncos(the[1][1]);
  for(i=2;i<=ox-x1;i++)
    omega1+=fabs(phi[i-1][1]-phi[i+1][1])*ncos(the[i][1]);
  for(j=2;j<oy+y1;j++)
    omega1+=fabs(phi[1][j-1]-phi[1][j+1])*ncos(the[1][j]);
  omega2=fabs(phi[nx-1][1]-phi[nx][2])*ncos(the[nx][1]);
  for(i=ox-x1+1;i<nx;i++)
    omega2+=fabs(phi[i-1][1]-phi[i+1][1])*ncos(the[i][1]);
  for(j=2;j<=oy-y2;j++)
    omega2+=fabs(phi[nx][j-1]-phi[nx][j+1])*ncos(the[nx][j]);
  omega3=fabs(phi[nx][ny-1]-phi[nx-1][ny])*ncos(the[nx][ny]);
  for(i=ox+x2;i<nx;i++)
    omega3+=fabs(phi[i-1][ny]-phi[i+1][ny])*ncos(the[i][ny]);
  for(j=oy-y2+1;j<ny;j++)
    omega3+=fabs(phi[nx][j-1]-phi[nx][j+1])*ncos(the[nx][j]);
  omega4=fabs(phi[1][ny-1]-phi[2][ny])*ncos(the[1][ny]);
  for(i=2;i<ox+x2;i++)
    omega4+=fabs(phi[i-1][ny]-phi[i+1][ny])*ncos(the[i][ny]);
  for(j=oy+y1;j<ny;j++)
    omega4+=fabs(phi[1][j-1]-phi[1][j+1])*ncos(the[1][j]);
  omega1=.5*pi-.5*omega1;
  omega2=.5*pi-.5*omega2;
  omega3=.5*pi-.5*omega3;
  omega4=.5*pi-.5*omega4;

  for(j=2;j<=ny;j++) {
    if(phi[nx][j]<phi[nx][j-1]) ns=j;
  }
  for(j=ns;j<=ny;j++) {
    ctemp=cos(the[nx][j]);
    if(ctemp<ctmin) ctmin=ctemp;
    fprintf(fp3,"%f\t%f\n",phi[nx][j],ctemp);
  }
  for(i=nx;i>=1;i--) {
    ctemp=cos(the[i][ny]);
    if(ctemp<ctmin) ctmin=ctemp;
    fprintf(fp3,"%f\t%f\n",phi[i][ny],ctemp);
  }
  for(j=ny;j>=1;j--) {
    ctemp=cos(the[1][j]);
    if(ctemp<ctmin) ctmin=ctemp;
    fprintf(fp3,"%f\t%f\n",phi[1][j],ctemp);
  }
  for(i=1;i<=nx;i++) {
    ctemp=cos(the[i][1]);
    if(ctemp<ctmin) ctmin=ctemp;
    fprintf(fp3,"%f\t%f\n",phi[i][1],ctemp);
  }
  for(j=1;j<ns;j++) {
    ctemp=cos(the[nx][j]);
    if(ctemp<ctmin) ctmin=ctemp;
    fprintf(fp3,"%f\t%f\n",phi[nx][j],ctemp);
  }

  omega=omega1+omega2+omega3+omega4;
  printf("omega : %f\n",omega);
  fprintf(fp2,"%f\t%f\t%f\t%f\n",omega1,omega2,omega3,omega4);
  fprintf(fp2,"%f\n",ctmin);
  printf("maximum zenith angle, ctmin-->deg: %f --> %d\n",ctmin,
	 (int)(acos(ctmin)*180./pi));

  for(i=1;i<=nx;i++) {
    for(j=1;j<=ny;j++) {
      if((flag[i][j]==1)&&(cos(the[i][j])>=ctmin)) {
	fprintf(fp2,"%e\t%e\t%e\n",xv[i],yv[j],zv[i][j]);
	count++;
      if(zv[i][j]<0.) printf("%d\t%d\n",i,j);
      }
    }
  }

  printf("number of surviving grid points: %d\n",count);
  printf("overburden at the origin in cm: %f\n",zv[ox][oy]);

  free_dvector(xv,1,nx);
  free_dvector(yv,1,ny);
  free_dmatrix(zv,1,nx,1,ny);
  free_dmatrix(the,1,nx,1,ny);
  free_dmatrix(phi,1,nx,1,ny);
  free_imatrix(flag,1,nx,1,ny);
  fclose(fp1);
  fclose(fp2);
  fclose(fp3);
  return 0;
}

void ra(double x, double y, double z, double *th, double *ph) {
  double cx,cy,cz,r;
  r=sqrt(x*x+y*y+z*z);
  cx=x/r;
  cy=y/r;
  cz=z/r;
  *th=acos(cz);
  if(cx!=0.) {
    *ph=atan(cy/cx);
    if(cx<0.) *ph+=pi;
  }
  if(cx==0.) {
    *ph=pi/2.;
    if(cy<0.) *ph=pi*3./2.;
  }
  if(*ph>pi*2.) *ph-=pi*2;
  if(*ph<0.) *ph+=pi*2.;
}

double costh(double *x, double *y, double **z, int i, int j, int nx, int ny) {
  double x0,y0,z0,r0;
  double x1,y1,z1,x2,y2,z2,x3,y3,z3,x4,y4,z4;
  double xt,yt,zt,rt;

  x0=x[i];
  y0=y[j];
  z0=z[i][j];

  if(i>1) {
    x1=x[i-1]-x0;
    z1=z[i-1][j]-z0;
  }
  if(i==1) x1=z1=0.;
  if(i<nx) {
    x3=x[i+1]-x0;
    z3=z[i+1][j]-z0;
  }
  if(i==nx) x3=z3=0.;
  x2=x4=0.;
  if(j>1) {
    y4=y[j-1]-y0;
    z4=z[i][j-1]-z0;
  }
  if(j==1) y4=z4=0.;
  if(j<ny) {
    y2=y[j+1]-y0;
    z2=z[i][j+1]-z0;
  }
  if(j==ny) y2=z2=0.;
  y1=y3=0.;
  xt=(z1*y2-y1*z2)+(z4*y1-y4*z1)+(z3*y4-y3*z4)+(z2*y3-y2*z3);
  yt=(x1*z2-z1*x2)+(x4*z1-z4*x1)+(x3*z4-z3*x4)+(x2*z3-z2*x3);
  zt=(y1*x2-x1*y2)+(y4*x1-x4*y1)+(y3*x4-x3*y4)+(y2*x3-x2*y3);

  r0=sqrt(x0*x0+y0*y0+z0*z0);
  x0/=r0;
  y0/=r0;
  z0/=r0;

  rt=sqrt(xt*xt+yt*yt+zt*zt);
  xt/=rt;
  yt/=rt;
  zt/=rt;

  return x0*xt+y0*yt+z0*zt;
}

double ncos(double the) {
  double ct;
  ct=cos(the);
  if(ct>0.) return ct;
  else return 0.;
}

#undef NRANSI
