int main (int argc, char **argv)
  
{
	int nt;                 /* number of time samples */
	int nz;                 /* number of migrated depth samples */
	int nx,nxshot;      /* number of midpoints,shotgathers, the folds in a shot
				gather */

	int flag=1;		/*flag to use ft or meter as the unit*/
	int dip=65;		/*maximum dip angle to migrate*/
	int iz,iw,ix,it,oldsx;     /* loop counters*/
	int ntfft;        /* fft size*/
	int nw;              /* number of wave numbers */
	int mytid,tids[NNTASKS],msgtype,rc,i;/*variable for PVM function*/
	int nw1,task; 	
	int lpad=9999,rpad=9999;	/*zero-traces padded on left and right sides*/
	float f1,f2,f3,f4;	/*frequencies to build the Hamming window*/
	int nf1,nf2,nf3,nf4;	/*the index for above frequencies*/
	int NTASKS=0;		/*number of slave tasks to start*/
	char cpu_name[NNTASKS][80];	/*strings to store the computers' name*/
	int flag_cpu=0;			/*flag to control if using NTASKS variable*/

	float sx,gxmin,gxmax;	/*location of  geophone and receivers*/
	int isx,nxo,ifx=0;	/*index for geophone and receivers*/
	int ix1,ix2,ix3,il,ir;	/*dummy index*/

	float *wl,*wtmp;	/*pointers for the souce function*/
	float Fmax=25;		/*peak frequency to make the Ricker wavelet*/
	int ntw,truenw;		/*number of frequencies to be migrated*/


	float dt=0.004,dz;   	/*time, depth sampling interval*/
	float ft;            	/*first time sample*/
	float dw;         	/*frequency sampling interval*/
	float fw;         	/*first frequency*/
	float dx;            	/*spatial sampling interval*/
	float **p,**cresult,**result_tmp;    /* input, output data*/
	float **v;		/*double pointer direct to velocity structure*/ 
	complex *wlsp,**cp,**cq,**cq1; /*pointers for internal usage*/

	char *vfile="";         /* name of file containing velocities */
	char *cpufile="";	/* name of file containing CPU name */

	FILE *vfp,*cpu_fp;

                        
	/* hook up getpar to handle the parameters */
	initargs(argc,argv);
	requestdoc(1);

	/* get optional parameters */
	if (!getparfloat("ft",&ft)) ft = 0.0;
	if (!getparint("nz",&nz)) err("nz must be specified");
	if (!getparfloat("dz",&dz)) err("dz must be specified");
	if (!getparstring("vfile", &vfile)) err("vfile must be specified");
	if (!getparint("nxo",&nxo)) err("nxo must be specified");
	if (!getparint("nxshot",&nxshot)) err("nshot must be specified");
	if (!getparfloat("Fmax",&Fmax)) err("Fmax must be specified");
	if (!getparfloat("f1",&f1)) f1 = 10.0;
	if (!getparfloat("f2",&f2)) f2 = 20.0;
	if (!getparfloat("f3",&f3)) f3 = 40.0;
	if (!getparfloat("f4",&f4)) f4 = 50.0;
	if (!getparint("lpad",&lpad)) lpad=9999;
	if (!getparint("rpad",&rpad)) rpad=9999;
	if (!getparint("flag",&flag)) flag=1;
	if (!getparint("dip",&dip)) dip=65;

	if (getparstring("cpufile", &cpufile)){
	cpu_fp=fopen(cpufile,"r");
	NTASKS=0;
	while(!feof(cpu_fp)){
	fscanf(cpu_fp,"%s",cpu_name[NTASKS]);
	NTASKS++;
	}
	NTASKS-=1;
	flag_cpu=1;
	}
	else /*if cpufile not specified, the use NTASKS*/
	if (!getparint("NTASKS",&NTASKS)) err("No CPUfile specified, NTASKS must be specified");

	/*allocate space for the velocity profile*/
	tshot=nxshot;
	v=alloc2float(nxo,nz);
        
	/*load velicoty file*/
	vfp=efopen(vfile,"r");
	efread(v[0],FSIZE,nz*nxo,vfp);
	efclose(vfp);

	/*PVM communication starts here*/
	mytid=pvm_mytid();	/*get my pid*/
	task=NTASKS;
	warn("\n %d",task);
	rc=0;
	/*spawn slave processes here*/
	if(!flag_cpu){
	rc=pvm_spawn(child,NULL,PvmTaskDefault,"",task,tids);
	}
	else{
	for(i=0;i<NTASKS;i++){
	rc+=pvm_spawn(child,NULL,PvmTaskHost,cpu_name[i],1,&tids[i]);
	}
	}
        
	/*show the pid of slaves if*/
	for(i=0;i<NTASKS;i++){
	if(tids[i]<0)warn("\n %d",tids[i]);
	else warn("\nt%x\t",tids[i]);
        }

	/*if not all the slaves start, then quit*/
	if(rc<NTASKS){ warn("error");pvm_exit();exit(1);}
        
	/*broadcast the global parameters nxo,nz,dip to all slaves*/
	pvm_initsend(PvmDataDefault);
	rc=pvm_pkint(&nxo,1,1);
	rc=pvm_pkint(&nz,1,1);
	rc=pvm_pkint(&dip,1,1);
	msgtype=PARA_MSGTYPE;
	task=NTASKS;
	rc=pvm_mcast(tids,task,msgtype);

	/*broadcast the velocity profile to all slaves*/
        pvm_initsend(PvmDataDefault);
        rc=pvm_pkfloat(v[0],nxo*nz,1);
        msgtype=VEL_MSGTYPE; 
        rc=pvm_mcast(tids,task,msgtype);
	
	/*free the space for velocity profile*/
	free2float(v);


/*loop over shot gathers begin here*/
loop:

        /* get info from first trace */
        if (!gettr(&tr))  err("can't get first trace");
        nt = tr.ns;


        /* let user give dt and/or dx from command line */
        if (!getparfloat("dt", &dt)) {
                if (tr.dt) { /* is dt field set? */
                        dt = ((double) tr.dt)/1000000.0;
                } else { /* dt not set, assume 4 ms */   
                        dt = 0.004;
                        warn("tr.dt not set, assuming dt=0.004");
                }
        }
        if (!getparfloat("dx",&dx)) {
                if (tr.d2) { /* is d2 field set? */
                        dx = tr.d2;
                } else {
                        dx = 1.0;
                        warn("tr.d2 not set, assuming d2=1.0");
                }
        }


	sx=tr.sx;
	isx=sx/dx;
	gxmin=gxmax=tr.gx;
	oldsx=sx;

        /* determine frequency sampling interval*/
        ntfft = npfar(nt);
        nw = ntfft/2+1;
        dw = 2.0*PI/(ntfft*dt);

	/*compute the index of the frequency to be migrated*/
	fw=2.0*PI*f1;
	nf1=fw/dw+0.5;

	fw=2.0*PI*f2;
	nf2=fw/dw+0.5;
 
	fw=2.0*PI*f3;
	nf3=fw/dw+0.5;

	fw=2.0*PI*f4;
	nf4=fw/dw+0.5;

	/*the number of frequency to migrated*/
	truenw=nf4-nf1+1;
	fw=0.0+nf1*dw;
	warn("nf1=%d nf2=%d nf3=%d nf4=%d nw=%d",nf1,nf2,nf3,nf4,truenw);
	fw=0.0;

        /* allocate space */
        wl=alloc1float(ntfft);
        wlsp=alloc1complex(nw);

	/*generate the Ricker wavelet*/
        wtmp=ricker(Fmax,dt,&ntw);

        for(it=0;it<ntfft;it++)
        wl[it]=0.0;

        for(it=0;it<ntw-12;it++)
        wl[it]=wtmp[it+12];
	free1float( wtmp);

	/*Fourier transform the Ricker wavelet to frequency domain*/
        pfarc(-1,ntfft,wl,wlsp);
        
	/* allocate space */
        p = alloc2float(ntfft,nxo);
        cp = alloc2complex(nw,nxo);

        for (ix=0; ix<nxo; ix++)
                for (it=0; it<ntfft; it++)
                        p[ix][it] = 0.0;
       
	
	/*read in a single shot gather*/
	ix=tr.gx/dx;
	memcpy( (void *) p[ix], (const void *) tr.data,nt*FSIZE);

        nx = 0;

	while(gettr(&tr)){
			int igx;

			if(tr.sx!=oldsx){ fseek(stdin,(long)(-240-nt*4),SEEK_CUR); break;}
			igx=tr.gx/dx;
			memcpy( (void *) p[igx], (const void *) tr.data,nt*FSIZE);  
                
			if(gxmin>tr.gx)gxmin=tr.gx;
			if(gxmax<tr.gx)gxmax=tr.gx;
			nx++;
			oldsx=tr.sx;
			}

	warn("\nnx= %d",nx);
	warn("sx %f , gxmin %f  gxmax %f",sx,gxmin,gxmax);

	/*transform the shot gather from time to frequency domain*/
        pfa2rc(1,1,ntfft,nxo,p[0],cp[0]);

	/*compute the most left and right index for the migrated section*/ 
	ix1=sx/dx;
	ix2=gxmin/dx;
	ix3=gxmax/dx;
        
	if(ix1>=ix3)ix3=ix1;
	if(ix1<=ix2)ix2=ix1;

	il=ix2;
	ir=ix3;
	ix2-=lpad;
	ix3+=rpad;
	if(ix2<0)ix2=0;
	if(ix3>nxo-1)ix3=nxo-1;

	/*the total traces to be migrated*/
	nx=ix3-ix2+1;

	/*allocate space*/
        cq = alloc2complex(nx,nw);
	cq1 = alloc2complex(nx,nw);


	/*transpose the frequency domain data from data[ix][iw] to data[iw][ix] and
	apply a Hamming at the same time*/

	for (ix=0; ix<nx; ix++)
	for (iw=0; iw<nw; iw++){	

	float tmpp=0.0,tmppp=0.0;
	
	if(iw<nf1||iw>nf4)
	cq[iw][ix]=cmplx(0.0,0.0);
	else{
		if(iw>=nf1&&iw<=nf2){tmpp=PI/(nf2-nf1);tmppp=tmpp*(iw-nf1)-PI;tmpp=0.54+0.46*cos(tmppp);
		cq[iw][ix]=crmul(cp[ix+ix2][iw],tmpp);}
		else{
			if(iw>=nf3&&iw<=nf4){tmpp=PI/(nf4-nf3);tmppp=tmpp*(iw-nf3);tmpp=0.54+0.46*cos(tmppp);
			cq[iw][ix]=crmul(cp[ix+ix2][iw],tmpp);}
			else
			{cq[iw][ix]=cp[ix+ix2][iw];}
		}
	}
	cq[iw][ix]=cp[ix+ix2][iw];
	cq1[iw][ix]=cmplx(0.0,0.0);
	}


	ix=sx/dx-ifx;
	warn("ix %d",ix);

	for(iw=0;iw<nw;iw++){
	cq1[iw][ix-ix2]=wlsp[iw];
	}


	free2float(p);
	free2complex(cp);
	free1float(wl);
	free1complex(wlsp);

	/*if the horizontal spacing interval is in feet, convert it to meter*/ 
	if(!flag)
	dx*=0.3048;

	/*start of the timing function*/
	time(&t1);

	/* send local parameters to all slaves*/
	pvm_initsend(PvmDataDefault);

	ix=15;
	rc=pvm_pkint(&ix,1,1);

	rc=pvm_pkint(&ntfft,1,1);
        rc=pvm_pkint(&ix2,1,1);
        rc=pvm_pkint(&ix3,1,1);
	rc=pvm_pkint(&isx,1,1);
	rc=pvm_pkint(&il,1,1);
	rc=pvm_pkint(&ir,1,1);
        rc=pvm_pkfloat(&dx,1,1);
        rc=pvm_pkfloat(&dz,1,1);
        rc=pvm_pkfloat(&dw,1,1);
	rc=pvm_pkfloat(&dt,1,1);
	msgtype=PARA_MSGTYPE;

	task=NTASKS;
	rc=pvm_mcast(tids,task,msgtype);

	
	/* send all the frequency to slaves*/
	count=NTASKS*5; /*count is the number of frequency components in a shot
			gather*/ 
        
	nw=truenw;        
	nw1=nw/(count);
	if(nw1==0)nw1=1;
	total=count=ceil(nw*1.0/nw1);

	/* if it is the first shot gather, send equal data to all the slaves, then for
	the following shot gathers, only send data when slave requests*/

	if(nxshot==tshot){

	for(i=0;i<NTASKS;i++){ 
	float *tmpp;
	float fw1;
	int nww,byte,nwww;
			
        pvm_initsend(PvmDataDefault);
	nww=nf1+i*nw1;fw1=fw+nww*dw;
	nwww=nw1;
        byte=UnDone;

        rc=pvm_pkint(&byte,1,1);
        rc=pvm_pkfloat(&fw1,1,1);
        rc=pvm_pkint(&nwww,1,1);   
	rc=pvm_pkfloat((float *)cq[nww],nx*nwww*2,1);
        rc=pvm_pkfloat((float *)cq1[nww],nx*nwww*2,1);
	msgtype=DATA_MSGTYPE;
	pvm_send(tids[i],msgtype);
	}

	count-=NTASKS;

	}


	while(count){

	int tid0,bufid;
	float *tmpp;
	float fw1;
	int nww,byte,nwww;  
	int i;  
	i=total-count;

        
	msgtype=COM_MSGTYPE;
	bufid=pvm_recv(-1,msgtype);
	rc=pvm_upkint(&tid0,1,1);
	pvm_freebuf(bufid);
        
        pvm_initsend(PvmDataDefault);
        nww=nf1+i*nw1;fw1=fw+nww*dw;
        if(i==total-1)nwww=nw-nw1*i;
        else nwww=nw1;

	byte=UnDone;
        rc=pvm_pkint(&byte,1,1);
        rc=pvm_pkfloat(&fw1,1,1);
        rc=pvm_pkint(&nwww,1,1);
        rc=pvm_pkfloat((float *)cq[nww],nx*nwww*2,1);
        rc=pvm_pkfloat((float *)cq1[nww],nx*nwww*2,1);
        msgtype=DATA_MSGTYPE;
        pvm_send(tid0,msgtype);

        count--;
	}

	ix=Done;
        
        pvm_initsend(PvmDataDefault);
        rc=pvm_pkint(&ix,1,1);

        msgtype=DATA_MSGTYPE;
        pvm_mcast(tids,task,msgtype);


	free2complex(cq);
	free2complex(cq1);

	time(&t2);

	warn("\n %d shot been finished in %f seconds, Ntask=%d",nxshot,difftime(t2,t1),NTASKS);

	nxshot--;                       

	if(nxshot)goto loop;
	

	/*when all the shot gathers done, send signal to all slaves to request the
								partial imaging*/
	ix=FinalDone;
        pvm_initsend(PvmDataDefault);
        rc=pvm_pkint(&ix,1,1);
        msgtype=PARA_MSGTYPE;
        pvm_mcast(tids,task,msgtype);
        
	/*allocate space for the final image*/
        cresult = alloc2float(nz,nxo);
	for(ix=0;ix<nxo;ix++)
        for(iz=0;iz<nz;iz++)
        { cresult[ix][iz]=0.0;
	}

	result_tmp= alloc2float(nz,nxo);
	
	/*receive partial image from all the slaves*/
	msgtype=RESULT_MSGTYPE;
	i=0;

	while(i<NTASKS){
	int bufid;
	bufid=pvm_recv(-1,msgtype);
	rc=pvm_upkfloat(result_tmp[0],nxo*nz,1);
	pvm_freebuf(bufid);
	for(ix=0;ix<nxo;ix++)
	for(iz=0;iz<nz;iz++)
	{
	cresult[ix][iz]+=result_tmp[ix][iz];	
	}
	i=i+1;
	warn("\n i=%d been received",i);
	}

	/*send signal to all slaves to kill themselves*/
	pvm_initsend(PvmDataDefault);
	pvm_mcast(tids,task,COM_MSGTYPE);

	/*output the final image*/
        for(ix=0; ix<nxo; ix++){
                tr.ns = nz ;
                tr.dt = dz*1000000.0 ;
		tr.d2 = dx;
		tr.offset = 0;
		tr.cdp = tr.tracl = ix;
                memcpy( (void *) tr.data, (const void *) cresult[ix],nz*FSIZE);
                puttr(&tr);
        }



        pvm_exit();            
        return EXIT_SUCCESS;
                                
}                               
int
main (int argc, char **argv)
{
	int nt;			/* number of time samples		*/
	int nz;			/* number of migrated depth samples	*/
	int nx;			/* number of horizontal samples		*/
	int nxshot;		/* number of shots to be migrated	*/
	/*int nxshot_orig;*/	/* first value of nxshot		*/ 
	int iz,iw,ix,it;	/* loop counters 			*/
	int igx;		/* integerized gx value			*/
	int ntfft;		/* fft size				*/
	int nw,truenw;		/* number of wave numbers		*/	
	int dip=79;		/* dip angle				*/
	
	float sx,gx;		/* x source and geophone location	*/
	float gxmin=0.0,gxmax=0.0; /* x source and geophone location	*/
	float min_sx_gx;	/* min(sx,gx)				*/
	float oldgx;		/* old gx position			*/
/*	float oldgxmin;	*/	/* old gx position			*/
/*	float oldgxmax;	*/	/* old gx position			*/
	float oldsx=0.0;	/* old sx position			*/
	int isx=0,nxo;		/* index for source and geophone	*/	
	int oldisx=0;		/* old value of source index		*/	
	int oldigx=0;		/* old value of integerized gx value	*/
	int ix1,ix2,ix3,ixshot; /* dummy index				*/
	int lpad,rpad; /* padding on both sides of the migrated section */

	float *wl=NULL,*wtmp=NULL;
	float fmax;
	float f1,f2,f3,f4;
	int nf1,nf2,nf3,nf4;
	int ntw;

	float dt=0.004,dz;	/* time and depth sampling interval 	*/
	float dw;		/* frequency  sampling interval		*/
	float fw;		/* first frequency 			*/
	float w;		/* frequency				*/
	float dx;		/* spatial sampling interval		*/
	float **p=NULL;		/* input data				*/
	float **cresult=NULL;	/* output result			*/
	float v1;		/* average velocity			*/
	double kz2;	
	float **v=NULL,**vp=NULL;/* pointers for the velocity profile	*/
	complex cshift2;
	complex *wlsp=NULL;	/* complex input,output			*/
	complex **cp=NULL;	/* ...					*/	
	complex **cp1=NULL;	/* ...					*/	
	complex **cq=NULL;	/* ...					*/	
	char *vfile="";		/* name of file containing velocities	*/
	FILE *vfp=NULL;

	int verbose;		/* verbose flag				*/

	/* hook up getpar to handle the parameters */
	initargs(argc,argv);
	requestdoc(1);

	/* get required parameters */
	MUSTGETPARINT("nz",&nz);
	MUSTGETPARINT("nxo",&nxo);
	MUSTGETPARFLOAT("dz",&dz);
	MUSTGETPARSTRING("vfile",&vfile);
	MUSTGETPARINT("nxshot",&nxshot);

	/* get optional parameters */
	if (!getparfloat("fmax",&fmax)) fmax = 25.0;  
	if (!getparfloat("f1",&f1)) f1 = 10.0;
	if (!getparfloat("f2",&f2)) f2 = 20.0;
	if (!getparfloat("f3",&f3)) f3 = 40.0;
	if (!getparfloat("f4",&f4)) f4 = 50.0;

	if (!getparint("lpad",&lpad)) lpad=9999;
	if (!getparint("rpad",&rpad)) rpad=9999;
	if (!getparint("dip",&dip)) dip=79;

	if (!getparint("verbose",&verbose)) 	verbose = 0;

	/* allocating space */
	cresult = alloc2float(nz,nxo);
	vp = alloc2float(nxo,nz);

	/* load velicoty file */
	vfp=efopen(vfile,"r");
	efread(vp[0],FSIZE,nz*nxo,vfp);
	efclose(vfp);

	/* zero out cresult array */
	memset((void *) cresult[0], 0, nxo*nz*FSIZE);

	/* save value of nxshot */
/* nxshot_orig=nxshot; */

	/* get info from first trace */
	if (!gettr(&tr))  err("can't get first trace");
	nt = tr.ns;
	get_sx_gx(&sx,&gx);
	min_sx_gx = MIN(sx,gx);
	sx = sx - min_sx_gx;
	gx = gx - min_sx_gx;

	/* let user give dt and/or dx from command line */
	if (!getparfloat("dt", &dt)) {
		if (tr.dt) { /* is dt field set? */
			dt = ((double) tr.dt)/1000000.0;
		} else { /* dt not set, assume 4 ms */
			dt = 0.004;
			if(verbose) warn("tr.dt not set, assuming dt=0.004");
		}
	}
	if (!getparfloat("dx",&dx)) {
		if (tr.d2) { /* is d2 field set? */
			dx = tr.d2;
		} else {
			dx = 1.0;
			if(verbose) warn("tr.d2 not set, assuming d2=1.0");
		}
	}

        checkpars();

	oldisx=0;

	do { 	/* begin loop over shots */


		/* determine frequency sampling interval*/
		ntfft = npfar(nt);
		nw = ntfft/2+1;
		dw = 2.0*PI/(ntfft*dt);

		/* compute the index of the frequency to be migrated*/
		fw=2.0*PI*f1;
		nf1=fw/dw+0.5;
		 
		fw=2.0*PI*f2;
		nf2=fw/dw+0.5;

		fw=2.0*PI*f3;
		nf3=fw/dw+0.5;

		fw=2.0*PI*f4;
		nf4=fw/dw+0.5;  

		/* the number of frequencies to migrated*/
		truenw=nf4-nf1+1;
		fw=0.0+nf1*dw;
		if(verbose)
			warn("nf1=%d nf2=%d nf3=%d nf4=%d nw=%d",nf1,nf2,nf3,nf4,truenw);

		/* allocate space */
		wl=alloc1float(ntfft);
		wlsp=alloc1complex(nw);
	
		/* generate the Ricker wavelet */
		wtmp=ricker(fmax,dt,&ntw);


		/* zero out wl[] array */
		memset((void *) wl, 0, ntfft*FSIZE);
	
		/* CHANGE BY CHRIS STOLK, Dec. 11, 2005 */
		/* The next two lines are the old code, */ 
		/* it is erroneous because the peak of	*/
		/* the wavelet occurs at positive time 	*/
		/* instead of time zero. */
		/*
		for(it=0;it<ntw;it++)
	  		wl[it]=wtmp[it];
		*/
		/* New code: we put in the wavelet in a centered fashion */ 

		for(it=0;it<ntw;it++) 
	  		wl[(it-ntw/2+ntfft) % ntfft]=wtmp[it];

		/* End of new code */
		free1float(wtmp);

		/* fourier transform wl array */
		pfarc(-1,ntfft,wl,wlsp);

		/* allocate space */
		p = alloc2float(ntfft,nxo);
		cq = alloc2complex(nw,nxo);

		/* zero out p[][] array */
		memset((void *) p[0], 0, ntfft*nxo*FSIZE);

		/* initialize a number of items before looping over traces */
		nx = 0;
		igx=0;
		oldigx=0;
		oldsx=sx;
		oldgx=gx;
		/* oldgxmax=gxmax; */
	/*	oldgxmin=gxmin; */
		do { /* begin looping over traces within a shot gather */

			memcpy( (void *) p[igx], (const void *) tr.data,nt*FSIZE);
			/* get sx and gx */
			get_sx_gx(&sx,&gx);
			sx = (sx - min_sx_gx);
			gx = (gx - min_sx_gx);

			igx = NINT(gx/dx);
			if (igx==oldigx) 
			   warn("repeated igx!!! check dx or scalco value!!!");
			oldigx = igx;


			if(gxmin>gx)gxmin=gx;
			if(gxmax<gx)gxmax=gx;

			if(verbose)
				warn(" inside loop:  min_sx_gx %f isx %d igx %d gx %f sx %f",min_sx_gx,isx,igx,gx,sx);

			/* sx, gx must increase monotonically */
			if (!(oldsx <= sx) ) 
			 err("sx field must be monotonically increasing!");
			if (!(oldgx <= gx) )
			 err("gx field must be monotonically increasing!");

			++nx;
		} while(gettr(&tr) && sx==oldsx);


		isx=NINT(oldsx/dx);
		ixshot=isx;
		if (isx==oldisx) 
			warn("repeated isx!!! check dx or scalco value!!!");
		oldisx=isx;
		if(verbose) {
			warn("sx %f, gx %f , gxmin %f  gxmax %f nx %d",sx,gx,gxmin,gxmax, nx);
			warn("isx %d igx %d ixshot %d" ,isx,igx,ixshot);
		}


		/* transform the shot gather from time to frequency domain */
		pfa2rc(1,1,ntfft,nxo,p[0],cq[0]);


		/* compute the most left and right index for the migrated */
		/* section */
		ix1=NINT(oldsx/dx);
		ix2=NINT(gxmin/dx);
		ix3=NINT(gxmax/dx);

		if(ix1>=ix3)ix3=ix1;
		if(ix1<=ix2)ix2=ix1;

		ix2-=lpad;
		ix3+=rpad;
		if(ix2<0)ix2=0;
		if(ix3>nxo-1)ix3=nxo-1;

		/* the total traces to be migrated */
		nx=ix3-ix2+1;
		nw=truenw;

		/* allocate space for velocity profile within the aperature */
		v=alloc2float(nx,nz);	
		for(iz=0;iz<nz;iz++)
			for(ix=0;ix<nx;ix++)
				v[iz][ix]=vp[iz][ix+ix2];


		/* allocate space */
		cp = alloc2complex(nx,nw);
		cp1 = alloc2complex(nx,nw);

		/* transpose the frequency domain data from	*/
		/* data[ix][iw] to data[iw][ix] and apply a 	*/
		/* Hamming at the same time			*/
		for (ix=0; ix<nx; ++ix) {
			for (iw=0; iw<nw; iw++){
				float tmpp=0.0,tmppp=0.0;

				if(iw>=(nf1-nf1)&&iw<=(nf2-nf1)){
					tmpp=PI/(nf2-nf1);
					tmppp=tmpp*(iw-nf1)-PI;
					tmpp=0.54+0.46*cos(tmppp);
					cp[iw][ix]=crmul(cq[ix+ix2][iw+nf1],tmpp);
				} else {
					if(iw>=(nf3-nf1)&&iw<=(nf4-nf1)) {
						tmpp=PI/(nf4-nf3);
						tmppp=tmpp*(iw-nf3);
						tmpp=0.54+0.46*cos(tmppp);
						cp[iw][ix]=crmul(cq[ix+ix2][iw+nf1],tmpp);
					} else {
						cp[iw][ix]=cq[ix+ix2][iw+nf1];
					}
				}
				cp1[iw][ix]=cmplx(0.0,0.0);
			}

		}

		for(iw=0;iw<nw;iw++){
			cp1[iw][ixshot-ix2]=wlsp[iw+nf1];
		}

		if(verbose) {
			warn("ixshot %d ix %d ix1 %d ix2 %d ix3 %d",ixshot,ix,ix1,ix2,ix3);
			warn("oldsx %f ",oldsx);
		}
			
		free2float(p);
		free2complex(cq);
		free1float(wl);
		free1complex(wlsp);


		/* loops over depth */
		for(iz=0; iz<nz; ++iz) {

			/* the imaging condition */
			for(ix=0; ix<nx; ++ix){
				for(iw=0,w=fw;iw<nw;w+=dw,iw++){	
					complex tmp;
					float ratio=10.0;
		
					if(fabs(ix+ix2-ixshot)*dx<ratio*iz*dz)
						tmp=cmul(cp[iw][ix],cp1[iw][ix]);
					else
						tmp=cmplx(0.0,0.0);  

					cresult[ix+ix2][iz]+=tmp.r/ntfft;
				}
			}

			/* get the average velocity */ 
			v1=0.0;
			for(ix=0;ix<nx;++ix) 
				v1+=v[iz][ix]/nx;

			/* compute time-invariant wavefield */
			for(ix=0;ix<nx;++ix) {
				for(iw=0,w=fw;iw<nw;w+=dw,++iw) {
					kz2=-(1.0/v1)*w*dz;
					cshift2=cmplx(cos(kz2),sin(kz2));
					cp[iw][ix]=cmul(cp[iw][ix],cshift2);
					cp1[iw][ix]=cmul(cp1[iw][ix],cshift2);
				}
			}

			/* wave-propagation using finite-difference method */
			fdmig(cp, nx, nw,v[iz],fw,dw,dz,dx,dt,dip);
			fdmig(cp1,nx, nw,v[iz],fw,dw,dz,dx,dt,dip);

			/* apply thin lens term here */
			for(ix=0;ix<nx;++ix) {
				for(iw=0,w=fw;iw<nw;w+=dw,++iw){
					kz2=-(1.0/v[iz][ix]-1.0/v1)*w*dz;
					cshift2=cmplx(cos(kz2),sin(kz2));
					cp[iw][ix]=cmul(cp[iw][ix],cshift2);
					cp1[iw][ix]=cmul(cp1[iw][ix],cshift2);
				}
			}
	
		}

		free2complex(cp);
		free2complex(cp1);
		free2float(v);
	
		--nxshot;

 	} while(nxshot);


	/* restore header fields and write output */
	for(ix=0; ix<nxo; ix++){
		tr.ns = nz;
		tr.d1 = dz;
		tr.d2 = dx;
		tr.offset = 0; 
		tr.cdp = tr.tracl = ix;
		memcpy( (void *) tr.data, (const void *) cresult[ix],nz*FSIZE);
		puttr(&tr);
	}
	

	return(CWP_Exit());	

}
Exemple #3
0
int
main (int argc, char **argv)
{
	int nt;			/* number of time samples		*/
	int nz;			/* number of migrated depth samples	*/
	int nx;			/* number of horizontal samples       	*/
	int nxshot;		/* number of shots to be migrated	*/
	int iz,iw,ix,it,ik;	/* loop counters			*/
        int igx;                /* integerized gx value			*/
	int ntfft,nxfft;	/* fft size				*/
	int nw,truenw,nk;	/* number of wave numbers		*/
	int dip=65;		/* dip angle				*/
	int oldigx=0;		/* old value of integerized gx value	*/
	int oldisx=0;		/* old value of integerized sx value	*/

        float sx,gx;            /* x source and geophone location       */
        float gxmin=0.0,gxmax=0.0; /* x source and geophone location    */
        float min_sx_gx;        /* min(sx,gx)                           */
        float oldgx;            /* old gx position                      */
        float oldgxmin;         /* old gx position                      */
        float oldgxmax;         /* old gx position                      */
        float oldsx=0.0;        /* old sx position                      */

        int isx=0,nxo;          /* index for source and geophone        */
	int ix1,ix2,ix3,ixshot,il=0,ir=0; /* dummy index		*/
	int lpad,rpad; /* padding on both sides of the migrated section */

	float *wl=NULL,*wtmp=NULL;
	float fmax;
	float f1,f2,f3,f4;
	int nf1,nf2,nf3,nf4;
	int ntw;

	float dt=0.004,dz;	/* time and depth sampling interval 	*/
	float dw,dk;		/* wavenumber and frequency sampling interval */
	float fw,fk;		/* first wavenumber and frequency	*/
	float w,k;		/* wavenumber and frequency		*/
	float dx;		/* spatial sampling interval		*/
	float **p=NULL;
	float **cresult=NULL;	/* input, output data			*/
	float v1,vmin;

	double kz1,kz2;
	double phase1;
	float **v=NULL;
	float **vp=NULL;
	complex cshift1,cshift2;
	complex *wlsp=NULL;
	complex **cp=NULL;
	complex **cp1=NULL;
	complex **cq=NULL;
	complex **cq1=NULL;	/*complex input,output*/
	char *vfile="";		/* name of file containing velocities */
	FILE *vfp=NULL;

        int verbose;            /* verbose flag                         */
	

	/* hook up getpar to handle the parameters */
	initargs(argc,argv);
	requestdoc(1);

	/* get optional parameters */
	MUSTGETPARINT("nz",&nz);
	MUSTGETPARFLOAT("dz",&dz);
	MUSTGETPARSTRING("vfile", &vfile);
	MUSTGETPARINT("nxo",&nxo);
	MUSTGETPARINT("nxshot",&nxshot);

	if (!getparfloat("fmax",&fmax)) fmax = 25. ;  
	if (!getparfloat("f1",&f1)) f1 = 10.0;
	if (!getparfloat("f2",&f2)) f2 = 20.0;
	if (!getparfloat("f3",&f3)) f3 = 40.0;
	if (!getparfloat("f4",&f4)) f4 = 50.0;
	if (!getparint("lpad",&lpad)) lpad=9999;
	if (!getparint("rpad",&rpad)) rpad=9999;
	if (!getparint("dip",&dip)) dip=65;

        if (!getparint("verbose",&verbose))     verbose = 0;	

	/* allocate space */
	cresult = alloc2float(nz,nxo);
	vp=alloc2float(nxo,nz);

	/* load velocity file */
	vfp=efopen(vfile,"r");
	efread(vp[0],FSIZE,nz*nxo,vfp);
	efclose(vfp);

        /* zero out cresult array */
        memset((void *) cresult[0], 0, nxo*nz*FSIZE);

	if (!gettr(&tr))  err("can't get first trace");
	nt = tr.ns;
        get_sx_gx(&sx,&gx);
        min_sx_gx = MIN(sx,gx);
        gxmin=gxmax=gx;
        erewind(stdin);
/*
        sx = sx - min_sx_gx;
        gx = gx - min_sx_gx;
*/

	/* let user give dt and/or dx from command line */
	if (!getparfloat("dt", &dt)) {
		if (tr.dt) { /* is dt field set? */
			dt = ((double) tr.dt)/1000000.0;
		} else { /* dt not set, assume 4 ms */
			dt = 0.004;
			warn("tr.dt not set, assuming dt=0.004");
		}
	}
	if (!getparfloat("dx",&dx)) {
		if (tr.d2) { /* is d2 field set? */
			dx = tr.d2;
		} else {
			dx = 1.0;
			warn("tr.d2 not set, assuming d2=1.0");
		}
	}

        do {    /* begin loop over shots */

		/* determine frequency sampling interval*/
		ntfft = npfar(nt);
		nw = ntfft/2+1;
		dw = 2.0*PI/(ntfft*dt);

		/* compute the index of the frequency to be migrated */
		fw=2.0*PI*f1;
		nf1=fw/dw+0.5;
		 
		fw=2.0*PI*f2;
		nf2=fw/dw+0.5;

		fw=2.0*PI*f3;
		nf3=fw/dw+0.5;

		fw=2.0*PI*f4;
		nf4=fw/dw+0.5;  

		/* the number of frequencies to migrated */
		truenw=nf4-nf1+1;
		fw=0.0+nf1*dw;

		if (verbose)
		warn("nf1=%d nf2=%d nf3=%d nf4=%d nw=%d",nf1,nf2,nf3,nf4,truenw);

		/* allocate space */
		wl=alloc1float(ntfft);
		wlsp=alloc1complex(nw);

		/* generate the Ricker wavelet */
		wtmp=ricker(fmax,dt,&ntw);

                /* zero out wl[] array */
                memset((void *) wl, 0, ntfft*FSIZE);

	
		/* CHANGE BY CHRIS STOLK, Dec. 11, 2005 */
		/* The next two lines are the old code, */
		/* it is erroneous because the peak of  */
		/* the wavelet occurs at positive time 	*/
		/* instead of time zero.		*/
		for(it=0;it<ntw;it++)
	  			wl[it]=wtmp[it];
		/* New code: we put in the wavelet in a centered fashion */ 
		/*
		for(it=0;it<ntw;it++) {
	  		wl[(it-ntw/2+ntfft) % ntfft]=wtmp[it];
		}
		*/
	  	/*  warn("%12i    %12f    \n",(it-ntw/2+ntfft) % ntfft,wtmp[it]); */
		/* End of new code */
		free1float(wtmp);

                /* fourier transform wl array */
		pfarc(-1,ntfft,wl,wlsp);

		/* CS TEST: this was used to output the array wlsp
			   (the wavelet in the frequency domain) to the file CSinfo,
			   no longer needed and commented out */
			/*
			FILE *CSinfo;
			CSinfo=fopen("CSinfo","w");
			fprintf(CSinfo,"ntfft=%10i\n",ntfft);
			fprintf(CSinfo,"ntw=%10i\n",ntw);
			for(iw=0;iw<ntfft/2+1;iw++)
			  fprintf(CSinfo,"%12f   %12f   \n",wlsp[iw].r,wlsp[iw].i);
			fclose(CSinfo);
					*/
			/* conclusion from the analysis of this info:
			   the wavelet (whose fourier transform is in wlsp)
			   is not zero phase!!! 
			   so there is a timeshift error!!!
			   Conclusion obtained dec 11 2005 */
			/* CS */

		/* allocate space */
		p = alloc2float(ntfft,nxo);
		cq = alloc2complex(nw,nxo);
	
                /* zero out p[][] array */
                memset((void *) p[0], 0, ntfft*nxo*FSIZE);
		
                /* initialize a number of items before looping over traces */
                nx = 0;
                if (gx < 0 ) {
                    igx=gx/dx + nxo;
                } else {
                    igx=gx/dx ;
                }
                oldigx=igx;
                oldsx=sx;
                oldgx=gx;
                oldgxmax=gxmax;
                oldgxmin=gxmin;
                while(gettr(&tr)) { /* begin looping over traces within a shot gather */

                        /* get sx and gx */
                        get_sx_gx(&sx,&gx);
/*
warn("%d nx=%d", igx, nx);
                        sx = (sx - min_sx_gx);
                        gx = (gx - min_sx_gx);
*/
                        if (gx < 0 ) {
                            igx=gx/dx + nxo;
                        } else {
                            igx=gx/dx ;
                        }
			if (igx==oldigx) 
			   warn("repeated igx!!! check dx or scalco value!!!");
			oldigx = igx;
                        if(tr.sx!=oldsx){ efseeko(stdin,(off_t)(-240-nt*4),SEEK_CUR); break;}

                        if(gxmin>gx)gxmin=gx;
                        if(gxmax<gx)gxmax=gx;

                        if(verbose)
                                warn(" inside loop:  min_sx_gx %f isx %d igx %d gx %f sx %f",min_sx_gx,isx,igx,gx,sx);
                        /* sx, gx must increase monotonically */
                        if (!(oldsx <= sx) )
                         err("sx field must be monotonically increasing!");
                        if (!(oldgx <= gx) )
                         err("gx field must be monotonically increasing!");

			memcpy( (void *) p[igx], (const void *) tr.data,nt*FSIZE);

                        ++nx;
                } 

                isx=oldsx/dx;
		if (isx==oldisx) 
			warn("repeated isx!!! check dx or scalco value!!!");
		oldisx=isx;
                ixshot=isx;
                if(verbose) {
                        warn("sx %f, gx %f , gxmin %f  gxmax %f nx %d",sx,gx,gxmin,gxmax, nx);
                        warn("isx %d igx %d ixshot %d" ,isx,igx,ixshot);
                }

		/* transform the shot gather from time to frequency domain */
		pfa2rc(1,1,ntfft,nxo,p[0],cq[0]);

                /* compute the most left and right index for the migrated */
                /* section */
                ix1=oldsx/dx;
                ix2=gxmin/dx;
                ix3=gxmax/dx;

                if(ix1>=ix3)ix3=ix1;
                if(ix1<=ix2)ix2=ix1;
                il=ix2;
                ir=ix3;

                ix2-=lpad;
                ix3+=rpad;
                if(ix2<0)ix2=0;
                if(ix3>nxo-1)ix3=nxo-1;

                /* the total traces to be migrated */
                nx=ix3-ix2+1;
                nw=truenw;

		/* determine wavenumber sampling (for complex to complex FFT) */
		nxfft = npfa(nx);
		nk = nxfft;
		dk = 2.0*PI/(nxfft*dx);
		fk = -PI/dx;

		/* allocate space for velocity profile within the aperature */
		v=alloc2float(nx,nz);   
		for(iz=0;iz<nz;iz++)
			for(ix=0;ix<nx;ix++)
				v[iz][ix]=vp[iz][ix+ix2];

		/* allocate space */
		cp = alloc2complex(nx,nw);
		cp1 = alloc2complex(nx,nw);

                /* transpose the frequency domain data from     */
                /* data[ix][iw] to data[iw][ix] and apply a     */
                /* Hamming at the same time                     */
		for (ix=0; ix<nx; ix++) {
			for (iw=0; iw<nw; iw++){
				float tmpp=0.0,tmppp=0.0;

				if(iw>=(nf1-nf1)&&iw<=(nf2-nf1)){
					tmpp=PI/(nf2-nf1);
					tmppp=tmpp*(iw-nf1)-PI;
					tmpp=0.54+0.46*cos(tmppp);
					cp[iw][ix]=crmul(cq[ix+ix2][iw+nf1],tmpp);
				} else {
					if(iw>=(nf3-nf1)&&iw<=(nf4-nf1)){
						tmpp=PI/(nf4-nf3);
						tmppp=tmpp*(iw-nf3);
						tmpp=0.54+0.46*cos(tmppp);
						cp[iw][ix]=crmul(cq[ix+ix2][iw+nf1],tmpp);
					} else {
						cp[iw][ix]=cq[ix+ix2][iw+nf1];}
				}
				cp1[iw][ix]=cmplx(0.0,0.0);
			}
		}

		for(iw=0;iw<nw;iw++){
			cp1[iw][ixshot-ix2]=wlsp[iw+nf1];
		}

                if(verbose) {
                        warn("ixshot %d ix %d ix1 %d ix2 %d ix3 %d",ixshot,ix,ix1,ix2,ix3);
                        warn("oldsx %f ",oldsx);
                }
			
		free2float(p);
		free2complex(cq);
		free1float(wl);
		free1complex(wlsp);

		/* allocating space */
		cq=alloc2complex(nxfft,nw);
		cq1=alloc2complex(nxfft,nw);


		/* loops over depth */
		for(iz=0;iz<nz;++iz){

			/* the imaging condition */
			for(ix=0;ix<nx;ix++){
				for(iw=0,w=fw;iw<nw;w+=dw,iw++){   
					complex tmp;
					float ratio=10.0;
		
					if(fabs(ix+ix2-ixshot)*dx<ratio*iz*dz)
						tmp=cmul(cp[iw][ix],cp1[iw][ix]);
					else 
						tmp=cmplx(0.0,0.0);  

					cresult[ix+ix2][iz]+=tmp.r/ntfft;
				}
			}

			/* get the minimum velocity */
			vmin=0;
			for(ix=il-ix2;ix<=ir-ix2;ix++){
				vmin+=1.0/v[iz][ix]/(ir-il+1);
			}
			vmin=1.0/vmin;
		
			/* compute the shifted wavefield */
			for (ik=0;ik<nx;++ik) {
				for (iw=0; iw<nw; ++iw) {
					cq[iw][ik] = ik%2 ? cneg(cp[iw][ik]) : cp[iw][ik];
					cq1[iw][ik] = ik%2 ? cneg(cp1[iw][ik]) : cp1[iw][ik];
				}
			}
		 
			/* zero out cq[][] cq1[][] */
			for (ik=nx; ik<nk; ++ik) {
				for (iw=0; iw<nw; ++iw) {
					cq[iw][ik] = cmplx(0.0,0.0);
					cq1[iw][ik] = cmplx(0.0,0.0);
				}
			}

			/* FFT to W-K domain */
			pfa2cc(-1,1,nk,nw,cq[0]);
			pfa2cc(-1,1,nk,nw,cq1[0]);
	
			v1=vmin;
			for(ik=0,k=fk;ik<nk;++ik,k+=dk) {
				for(iw=0,w=fw;iw<nw;++iw,w+=dw){
					if(w==0.0)w=1.0e-10/dt; 
					kz1=1.0-pow(v1*k/w,2.0);
					if(kz1>0.15){
						phase1 = -w*sqrt(kz1)*dz/v1;
						cshift1 = cmplx(cos(phase1), sin(phase1));
						cq[iw][ik] = cmul(cq[iw][ik],cshift1);
						cq1[iw][ik] = cmul(cq1[iw][ik],cshift1);
					} else {
						cq[iw][ik] = cq1[iw][ik] = cmplx(0.0,0.0);
					}
				}
			}
	
			pfa2cc(1,1,nk,nw,cq[0]);
			pfa2cc(1,1,nk,nw,cq1[0]);

			for(ix=0;ix<nx;++ix) {
				for(iw=0,w=fw;iw<nw;w+=dw,++iw){
					float a=0.015,g=1.0;
					int I=10;
				
					if(ix<=I)g=exp(-a*(I-ix)*(I-ix));
					if(ix>=nx-I)g=exp(-a*(-nx+I+ix)*(-nx+I+ix));
				 
				
					cq[iw][ix] = crmul( cq[iw][ix],1.0/nxfft);
					cq[iw][ix] =ix%2 ? cneg(cq[iw][ix]) : cq[iw][ix];
					kz2=(1.0/v1-1.0/v[iz][ix])*w*dz;
					cshift2=cmplx(cos(kz2),sin(kz2));
					cp[iw][ix]=cmul(cq[iw][ix],cshift2);
		
					cq1[iw][ix] = crmul( cq1[iw][ix],1.0/nxfft);
					cq1[iw][ix] =ix%2 ? cneg(cq1[iw][ix]) : cq1[iw][ix];
					cp1[iw][ix]=cmul(cq1[iw][ix],cshift2);
		 
				}
			}
		}
		
		free2complex(cp);
		free2complex(cp1);
		free2complex(cq);
		free2complex(cq1);
		free2float(v);

		--nxshot;

	} while(nxshot);

        /* restore header fields and write output */
        for(ix=0; ix<nxo; ix++){
                tr.ns = nz;
                tr.d1 = dz;
                tr.d2 = dx;
                tr.offset = 0;
                tr.cdp = tr.tracl = ix;
                memcpy( (void *) tr.data, (const void *) cresult[ix],nz*FSIZE);
                puttr(&tr);
        }


	return(CWP_Exit());	

}