#include<stdio.h>
#include<omp.h>
#include<string.h>
#include<stdlib.h>


#include<sys/types.h>
#include<sys/stat.h>
#include <fcntl.h>

#include <unistd.h>




#define min(a,b) (((a)<(b)) ? (a):(b))
#define max(a,b) (((a)>(b)) ? (a):(b))

#define BLOCKSIZE 128

void  segment( char *pagbone_outputfile,
	       float threshold,
	       int medianR,
	       char *maskbone_outputfile,
	       int myrank,
	       int nprocs,
	       int ncpus,
	       long int MemPerProc, int SIZEZ, int SIZEY, int SIZEX, int dilatation ) {

  printf(" in c++ %d %d %d ncpus %d \n", SIZEZ,  SIZEY, SIZEX, ncpus);

  int margin = dilatation + medianR ;


  int zPstep =  ((SIZEZ+nprocs-1)/nprocs);
  int Pstart =   zPstep*myrank   ;
  int Pend   =   min( Pstart + zPstep, SIZEZ   )        ;
  int zTstep =  (((Pend-Pstart)+ncpus-1)/ncpus);

  omp_set_num_threads(ncpus);
#pragma omp  parallel
  {
    int ID = omp_get_thread_num();
    //printf(" ID %d \n", ID);
    int Tstart =   Pstart + zTstep*ID   ;
    int Tend   =   min( Tstart + zTstep , Pend   )        ;

    int istart, iend;

 #define NZs 20

    int *   Rblock = (int*) malloc(  (NZs+2*margin)*BLOCKSIZE*BLOCKSIZE *sizeof(int));
    int *   Mblock = (int*) malloc(  (NZs+2*margin)*BLOCKSIZE*BLOCKSIZE *sizeof(int));
 
    float *input_data  = (float *) malloc(sizeof(float)*(NZs+2*margin)*SIZEY*SIZEX   );
    float *output_data = (float *) malloc(sizeof(float)* NZs *SIZEY*SIZEX   );

    for(istart = Tstart; istart<Tend; istart+=NZs) {
      printf(" ID %d istart %d \n", ID, istart);
      iend = min(istart +NZs, Tend);
      int Rstart = max(istart-margin,0);
      int Rend   = min(iend  +margin,SIZEZ);
      
      int fd;
      long int l_start  =  ((long int)(Rstart ))*sizeof(float)*SIZEY*SIZEX ; 
      fd = open(pagbone_outputfile, O_RDONLY );
      if(fd==-1) {	
	fprintf(stderr, " ERROR : could not open : %s  \n", pagbone_outputfile );
	exit(1);
      }
      lseek( fd  ,l_start , SEEK_SET);
      read( fd, input_data  ,   sizeof(float)* (Rend-Rstart)*SIZEY*SIZEX  );
      close(fd);

      int  falso = 0 ;

      int DY = BLOCKSIZE-2*margin;
      int DX = BLOCKSIZE-2*margin;

      for(int iY = 0 ; iY < SIZEY; iY+=DY) {
	int eY = min(iY+DY, SIZEY);
	for(int iX = 0 ; iX < SIZEX; iX+=DX) {
	  int eX = min(iX+DX, SIZEX);

	  // printf(" ID %d costruisce blocco iY iX %d %d \n", ID, iY, iX);

	  for(int rz=0; rz<NZs+2*margin; rz++) {
	    int Z = rz + istart -margin;
	    if( Z >= Rstart &&    Z<Rend) {
	      Z = Z - Rstart ; 
	      for(int ry=0; ry<BLOCKSIZE; ry++) {
		int Y = ry + iY -margin ; 
		if( Y>=0 && Y < SIZEY) {
		  for(int rx=0; rx<BLOCKSIZE; rx++) {
		    int X = rx + iX -margin ; 
		    int  rdata ; 
		    if( X>=0 && X < SIZEX) {
		      rdata  = ( input_data[( Z* SIZEY  + Y ) *SIZEX  + X ] > threshold );
		    } else {
		      rdata = falso ;
		    }
		    Rblock[( rz* BLOCKSIZE + ry ) *  BLOCKSIZE+ rx  ]  = rdata;
		  }
		} else {
		  for(int rx=0; rx<BLOCKSIZE; rx++)  Rblock[( rz*BLOCKSIZE   + ry ) * BLOCKSIZE + rx  ]  = falso ;
		}
	      }
	    } else {
	      for(int ry=0; ry<BLOCKSIZE; ry++) for(int rx=0; rx<BLOCKSIZE; rx++)  Rblock[( rz*BLOCKSIZE   + ry ) * BLOCKSIZE + rx  ]  = falso   ;
	    }
	  }
	  
	  int *A=NULL, *B=NULL;
	  if( medianR) {
	    int mediano = ( (2*medianR+1)*  (2*medianR+1)*  (2*medianR+1)      )/2;
	    A = Rblock;
	    B = Mblock ; 
	    for(int z = medianR; z< NZs+2*margin-medianR; z++) {
	      for(int y=0; y< BLOCKSIZE; y++) {
		for(int x=0; x< BLOCKSIZE; x++) {
		  int sum=0;
		  for(int s = -medianR; s<=medianR; s++) {
		    sum +=  A[ ( (z+s)*BLOCKSIZE + (y+0))*BLOCKSIZE + (x+0) ]  ; 
		  }
		  B[ ( z*BLOCKSIZE + y)*BLOCKSIZE + x ] = sum;
		}
	      }
	    }
	    B = Rblock;
	    A = Mblock ; 
	    for(int z = medianR; z< NZs+2*margin-medianR; z++) {
	      for(int y=medianR; y< BLOCKSIZE-medianR; y++) {
		for(int x=0; x< BLOCKSIZE; x++) {
		  int sum=0;
		  for(int s = -medianR; s<=medianR; s++) {
		    sum +=  A[ ( (z+0)*BLOCKSIZE + (y+s))*BLOCKSIZE + (x+0) ]  ; 
		  }
		  B[ ( z*BLOCKSIZE + y)*BLOCKSIZE + x ] = sum;
		}
	      }
	    }
	    A = Rblock;
	    B = Mblock ; 
	    for(int z = medianR; z< NZs+2*margin-medianR; z++) {
	      for(int y=medianR; y< BLOCKSIZE-medianR; y++) {
		for(int x=medianR; x< BLOCKSIZE-medianR; x++) {
		  int sum=0;
		  for(int s = -medianR; s<=medianR; s++) {
		    sum +=  A[ ( (z+0)*BLOCKSIZE + (y+0))*BLOCKSIZE + (x+s) ]  ; 
		  }
		  B[ ( z*BLOCKSIZE + y)*BLOCKSIZE + x ] = (sum >= mediano);
		}
	      }
	    }
	  } else {
	    B = Rblock;
	    A = Mblock;
	  }

	  for(int z = istart-dilatation ; z<istart+NZs+dilatation; z++) {
	    for(int y=iY-dilatation; y<eY+dilatation; y++) {
	      for(int x=iX-dilatation; x<eX+dilatation; x++) {
		int posinblock =   (((z-istart)+margin)*BLOCKSIZE + ((y-iY) +margin  ))*BLOCKSIZE + ((x-iX) +margin  ) ; 
		if(B[posinblock])  B[posinblock]=0 ;
		else               B[posinblock]=-1 ;
	      }
	    }
	  }
	  
#define NOMASK 100000


	  for(int z = istart; z<istart+NZs; z++) {
	    for(int y=iY-dilatation; y<eY+dilatation; y++) {
	      for(int x=iX-dilatation; x<eX+dilatation; x++) {
		float mask= NOMASK;
		int sx=0, sy=0;
		for(int sz = -dilatation ; sz<dilatation+1; sz++) {
		  int posinblock =   (((z-istart)+margin+sz)*BLOCKSIZE + ((y-iY) +margin +sy ))*BLOCKSIZE + ((x-iX) +margin +sx ) ; 
		  if(B[posinblock]>=0) mask = min(mask, sz*sz ) ;
		}

		if(mask==NOMASK) mask = -1 ; 
		
		A[(((z-istart)+margin)*BLOCKSIZE + ((y-iY) +margin))*BLOCKSIZE + ((x-iX) +margin)] = mask ; 


	      }
	    }
	  }
	  for(int z = istart; z<istart+NZs; z++) {
	    for(int y=iY; y<eY; y++) {
	      for(int x=iX-dilatation; x<eX+dilatation; x++) {
		float mask=NOMASK;
		int sx=0, sz=0;
		for(int sy = -dilatation ; sy<dilatation+1; sy++) {
		  int posinblock =   (((z-istart)+margin+sz)*BLOCKSIZE + ((y-iY) +margin +sy ))*BLOCKSIZE + ((x-iX) +margin +sx ) ; 
		  if(A[posinblock]>=0) mask = min(mask,A[posinblock]+sy*sy   )  ;
		}
		if(mask==NOMASK) mask = -1 ; 
		B[(((z-istart)+margin)*BLOCKSIZE + ((y-iY) +margin))*BLOCKSIZE + ((x-iX) +margin)] = mask ; 
	      }
	    }
	  }
	  for(int z = istart; z<istart+NZs; z++) {
	    for(int y=iY; y<eY; y++) {
	      for(int x=iX; x<eX; x++) {
		float mask=NOMASK;
		int sy=0, sz=0;
		for(int sx = -dilatation ; sx<dilatation+1; sx++) {
		  int posinblock =   (((z-istart)+margin+sz)*BLOCKSIZE + ((y-iY) +margin +sy ))*BLOCKSIZE + ((x-iX) +margin +sx ) ; 
		  if(B[posinblock]>=0) mask = min(mask,B[posinblock]+sx*sx)   ;
		}
		if(mask==NOMASK) {
		  mask = 0 ; 
		} else {
		  if(mask>dilatation*dilatation+0.01) {
		    mask=0;
		  } else {
		    mask = 1-mask/dilatation/dilatation/3;
		  }
		  // mask = sqrt(mask);
		  // if(mask>dilatation+0.01) mask=0;
		  // else mask = mask = 1.0 - mask / (dilatation+1);
		}
		output_data[( (z-istart)* SIZEY  + y ) *SIZEX  + x ] = mask ; 
	      }
	    }
	  }
	  // printf(" ID %d costruito blocco iY iX %d %d \n", ID, iY, iX);
	  
	  // for(int z = istart; z<istart+NZs; z++) {
	  //   for(int y=iY; y<eY; y++) {
	  //     for(int x=iX; x<eX; x++) {
	  // 	int mask=0;
	  // 	for(int sz = -dilatation ; sz<dilatation+1; sz++) {
	  // 	  for(int sy = -dilatation ; sy<dilatation+1; sy++) {
	  // 	    for(int sx = -dilatation ; sx<dilatation+1; sx++) {
	  // 	      int posinblock =   (((z-istart)+margin+sz)*BLOCKSIZE + ((y-iY) +margin +sy ))*BLOCKSIZE + ((x-iX) +margin +sx ) ; 
	  // 	      if(B[posinblock]) mask = 1;
	  // 	    }
	  // 	  }
	  // 	}
	  // 	output_data[( (z-istart)* SIZEY  + y ) *SIZEX  + x ] = mask ; 
	  //     }
	  //   }
	  // }
	}
      }
      // printf(" scrivo pezzo su file \n");
      {
	struct flock fl;
	int fd;
	
	fl.l_type   = F_WRLCK;  /* F_RDLCK, F_WRLCK, F_UNLCK    */
	fl.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */

	fl.l_len    = sizeof(float)*(Rend-Rstart)*SIZEY*SIZEX; /* length, 0 = to EOF           */
	fl.l_pid    = getpid(); /* our PID                      */


	fd = open( maskbone_outputfile , O_RDWR | O_CREAT , 640);
	if(fd==-1) {	
	  fprintf(stderr, " ERROR : could not open : %s  \n", maskbone_outputfile );
	  exit(0);
	}

	// printf(" locking slices %d to %d   in file %s \n",istart, iend,  maskbone_outputfile );
	fl.l_start  =  ((long int) istart)*sizeof(float)*SIZEY*SIZEX; 
	fcntl(fd, F_SETLKW, &fl);  /* F_GETLK, F_SETLK, F_SETLKW */
	lseek( fd  ,fl.l_start , SEEK_SET);
	write(fd, output_data  ,   sizeof(float)* (iend-istart)*SIZEY*SIZEX);
	fl.l_type   = F_UNLCK;  /* tell it to unlock the region */
	fcntl(fd, F_SETLK, &fl); /* set the region to unlocked */
	// printf("unlocked \n");
	close(fd);
      }

    }
    free(input_data);
    free(output_data);
    free(Rblock);
    free(Mblock);
  }
}







void  spilla ( char *pagbone_outputfile,
	       char *absbone_outputfile,
	       char *maskbone_outputfile,
	       float threshold,
	       char *corrbone_outputfile,
	       int myrank,
	       int nprocs,
	       int ncpus,
	       long int MemPerProc, int SIZEZ, int SIZEY, int SIZEX) {

  printf(" in spilla %d %d %d ncpus %d \n", SIZEZ,  SIZEY, SIZEX, ncpus);



  int zPstep =  ((SIZEZ+nprocs-1)/nprocs);
  int Pstart =   zPstep*myrank   ;
  int Pend   =   min( Pstart + zPstep, SIZEZ   )        ;
  int zTstep =  (((Pend-Pstart)+ncpus-1)/ncpus);

  omp_set_num_threads(ncpus);
#pragma omp  parallel
  {
    int ID = omp_get_thread_num();
    int Tstart =   Pstart + zTstep*ID   ;
    int Tend   =   min( Tstart + zTstep , Pend   )        ;

    int istart, iend;

    int margin = 20;

 
    float *pag_data    = (float *) malloc(sizeof(float)*(NZs+2*margin)*SIZEY*SIZEX   );
    float *abs_data    = (float *) malloc(sizeof(float)*(NZs+2*margin)*SIZEY*SIZEX   );
    float *mask_data   = (float *) malloc(sizeof(float)*(NZs+2*margin)*SIZEY*SIZEX   );
    float *output_data = (float *) malloc(sizeof(float)* (NZs+2*margin) *SIZEY*SIZEX   );


    printf(" ID %d va da %d a %d \n", ID, Tstart, Tend);


    for(istart = Tstart; istart<Tend; istart+=NZs) {
      iend = min(istart +NZs, Tend);
      int Rstart = max(istart-margin,0);
      int Rend   = min(iend +margin ,SIZEZ);
      
 
      {
	int fd;
	long int l_start  =  ((long int)(Rstart ))*sizeof(float)*SIZEY*SIZEX ; 
	fd = open(absbone_outputfile, O_RDONLY );
	if(fd==-1) {	
	  fprintf(stderr, " ERROR : a) could not open : %s  \n", absbone_outputfile );
	  exit(1);
	}
	lseek( fd  ,l_start , SEEK_SET);
	read( fd, abs_data  ,   sizeof(float)* (Rend-Rstart)*SIZEY*SIZEX  );
	close(fd);
      }
      {
	int fd;
	long int l_start  =  ((long int)(Rstart ))*sizeof(float)*SIZEY*SIZEX ; 
	fd = open(pagbone_outputfile, O_RDONLY );
	if(fd==-1) {	
	  fprintf(stderr, " ERROR : a) could not open : %s  \n", pagbone_outputfile );
	  exit(1);
	}
	lseek( fd  ,l_start , SEEK_SET);
	read( fd, pag_data  ,   sizeof(float)* (Rend-Rstart)*SIZEY*SIZEX  );
	close(fd);
      }


      {
	int fd;
	long int l_start  =  ((long int)(Rstart ))*sizeof(float)*SIZEY*SIZEX ; 
	fd = open(maskbone_outputfile, O_RDONLY );
	if(fd==-1) {	
	  fprintf(stderr, " ERROR :b) could not open : %s  \n", maskbone_outputfile );
	  exit(1);
	}
	lseek( fd  ,l_start , SEEK_SET);
	read( fd, mask_data  ,   sizeof(float)* (Rend-Rstart)*SIZEY*SIZEX  );
	close(fd);
      }

      int cambi=1;
      int tour=0;
      while(cambi ) {
	
	// printf(" %d %d   cambi %d \n",  Rstart  ,  Rend  ,   cambi );
	
	cambi=0;
	tour++;
	int iz,ix,iy;
	int pos=0;

	int ST_Y = SIZEX;
	int ST_Z = SIZEX*SIZEY;

	for( iz=0; iz<(Rend-Rstart); iz++) {
	  for( iy=0; iy<SIZEY; iy++) {
	    for( ix=0; ix<SIZEX; ix++) {
	      if( mask_data[pos] >0.0f ) {
		
		int count=0;
		int countnear=0;
		float sum=0;
		
		if(threshold==0) {

		  for(int SZ= -(iz>0) ; SZ<=      (iz<(Rend-Rstart)-1) ;SZ++) {
		    for(int SY= -(iy>0) ; SY<= (iy<(SIZEY-1));SY++) {
		      for(int SX= -(ix>0) ; SX<= (ix<(SIZEX-1));SX++) {
			if( mask_data[pos+ST_Z*SZ + ST_Y*SY + SX] == -(tour-1)) {
			  count++;
			  sum+= pag_data[pos+ST_Z*SZ + ST_Y*SY + SX]; 
			  if( abs(SZ)+abs(SY)+abs(SX) ==1) countnear++;
			}
		      }
		    }
		  }
		  
		  if(count && countnear) {
		    output_data[pos] = abs_data[pos];
		    cambi++;
		    pag_data[pos]=sum/count;
		    mask_data[pos] = -tour;
		  }
		} else {
		  output_data[pos] = abs_data[pos];
		  pag_data[pos]=threshold;
		}
	      }
	      pos++;
	    }
	  }
	}
      }

      for(int i=0; i<(Rend-Rstart)*SIZEY*SIZEX;i++) {
	if(mask_data[i] ) {
	  output_data[i] = output_data[i]  -pag_data[i]; 
	  // output_data[i] = pag_data[i]; 
	} else {
	  output_data[i]=0.0f;
	}
      }


      {
	struct flock fl;
	int fd;
	
	fl.l_type   = F_WRLCK;  /* F_RDLCK, F_WRLCK, F_UNLCK    */
	fl.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */

	fl.l_len    = sizeof(float)*(Rend-Rstart)*SIZEY*SIZEX; /* length, 0 = to EOF           */
	fl.l_pid    = getpid(); /* our PID                      */


	fd = open( corrbone_outputfile , O_RDWR | O_CREAT , 640);
	if(fd==-1) {	
	  fprintf(stderr, " ERROR :c) could not open : %s  \n", corrbone_outputfile );
	  exit(0);
	}
	printf(" locking slices %d to %d   in file %s \n",istart, iend,  corrbone_outputfile );
	fl.l_start  =  ((long int) istart)*sizeof(float)*SIZEY*SIZEX; 
	fcntl(fd, F_SETLKW, &fl);  /* F_GETLK, F_SETLK, F_SETLKW */
	lseek( fd  ,fl.l_start , SEEK_SET);
	
	if(0) {
	  double sum=0;
	  int i=0;
	  for(i=0; i<(iend-istart)*SIZEY*SIZEX; i++) {

	    sum+=   output_data [ SIZEY*SIZEX*(istart-Rstart) +i ] ; 
	  }
	  printf(" tot sum %d %d %e \n", iend, istart, sum );
	}
	write(fd, output_data + SIZEY*SIZEX*(istart-Rstart) ,   sizeof(float)* (iend-istart)*SIZEY*SIZEX);
	fl.l_type   = F_UNLCK;  /* tell it to unlock the region */
	fcntl(fd, F_SETLK, &fl); /* set the region to unlocked */
	// printf("unlocked \n");
	close(fd);
      }

    }
    free(pag_data);
    free(abs_data);
    free(mask_data);
    free(output_data);
  }
}



void   incolla( char *pagbone_outputfile,
		char *maskbone_outputfile,
		char *corrected_outputfile,         
		char *outputfile,
		int myrank,
		int nprocs,
		int ncpus,
		long int MemPerProc, int SIZEZ, int SIZEY, int SIZEX) {


  printf(" in c++ %d %d %d ncpus %d \n", SIZEZ,  SIZEY, SIZEX, ncpus);

  int zPstep =  ((SIZEZ+nprocs-1)/nprocs);
  int Pstart =   zPstep*myrank   ;
  int Pend   =   min( Pstart + zPstep, SIZEZ   )        ;
  int zTstep =  (((Pend-Pstart)+ncpus-1)/ncpus);

  omp_set_num_threads(ncpus);
#pragma omp  parallel
  {
    int ID = omp_get_thread_num();
    // printf(" ID %d \n", ID);
    int Tstart =   Pstart + zTstep*ID   ;
    int Tend   =   min( Tstart + zTstep , Pend   )        ;

    int istart, iend;


 
    float *pagbone_data    = (float *) malloc(sizeof(float)*(NZs)*SIZEY*SIZEX   );
    float *mask_data   = (float *) malloc(sizeof(float)*(NZs)*SIZEY*SIZEX   );
    float *corrected_data = (float *) malloc(sizeof(float)* NZs *SIZEY*SIZEX   );
    float *output_data = (float *) malloc(sizeof(float)* NZs *SIZEY*SIZEX   );

    for(istart = Tstart; istart<Tend; istart+=NZs) {
      iend = min(istart +NZs, Tend);
      int Rstart = max(istart,0);
      int Rend   = min(iend  ,SIZEZ);
      
 
      {
	int fd;
	long int l_start  =  ((long int)(Rstart ))*sizeof(float)*SIZEY*SIZEX ; 
	fd = open(pagbone_outputfile, O_RDONLY );
	if(fd==-1) {	
	  fprintf(stderr, " ERROR : could not open : %s  \n", pagbone_outputfile );
	  exit(1);
	}
	lseek( fd  ,l_start , SEEK_SET);
	read( fd, pagbone_data  ,   sizeof(float)* (Rend-Rstart)*SIZEY*SIZEX  );
	close(fd);
      }
      {
	int fd;
	long int l_start  =  ((long int)(Rstart ))*sizeof(float)*SIZEY*SIZEX ; 
	fd = open(maskbone_outputfile, O_RDONLY );
	if(fd==-1) {	
	  fprintf(stderr, " ERROR : could not open : %s  \n", maskbone_outputfile );
	  exit(1);
	}
	lseek( fd  ,l_start , SEEK_SET);
	read( fd, mask_data  ,   sizeof(float)* (Rend-Rstart)*SIZEY*SIZEX  );
	close(fd);
      }

      {
	int fd;
	long int l_start  =  ((long int)(Rstart ))*sizeof(float)*SIZEY*SIZEX ; 
	fd = open(corrected_outputfile, O_RDONLY );
	if(fd==-1) {	
	  fprintf(stderr, " ERROR : could not open : %s  \n", corrected_outputfile );
	  exit(1);
	}
	lseek( fd  ,l_start , SEEK_SET);
	read( fd, corrected_data  ,   sizeof(float)* (Rend-Rstart)*SIZEY*SIZEX  );
	close(fd);
      }


      for(int i=0; i<(Rend-Rstart)*SIZEY*SIZEX;i++) {
	if(mask_data[i]) {
	  output_data[i] = max(  corrected_data[i], pagbone_data[i]*mask_data[i]    );
	} else {
	  output_data[i] =   corrected_data[i];
	}

	// if(mask_data[i]!=0.0f) {
	//   output_data[i] =  pagbone_data[i]; 
	// } else {
	//   output_data[i] =  corrected_data[i];
	// }

	// if(mask_data[i]) {
	//   output_data[i] =  pagbone_data[i]; 
	// } else {
	//   output_data[i] =  corrected_data[i];
	// }
      }
      
      
      {
	struct flock fl;
	int fd;
	
	fl.l_type   = F_WRLCK;  /* F_RDLCK, F_WRLCK, F_UNLCK    */
	fl.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */
	
	fl.l_len    = sizeof(float)*(Rend-Rstart)*SIZEY*SIZEX; /* length, 0 = to EOF           */
	fl.l_pid    = getpid(); /* our PID                      */
	
	
	fd = open( outputfile , O_RDWR | O_CREAT , 640);
	if(fd==-1) {	
	  fprintf(stderr, " ERROR : could not open : %s  \n", outputfile );
	  exit(0);
	}
	// printf(" locking slices %d to %d   in file %s \n",istart, iend,  outputfile );
	fl.l_start  =  ((long int) istart)*sizeof(float)*SIZEY*SIZEX; 
	fcntl(fd, F_SETLKW, &fl);  /* F_GETLK, F_SETLK, F_SETLKW */
	lseek( fd  ,fl.l_start , SEEK_SET);
	write(fd, output_data  ,   sizeof(float)* (iend-istart)*SIZEY*SIZEX);
	fl.l_type   = F_UNLCK;  /* tell it to unlock the region */
	fcntl(fd, F_SETLK, &fl); /* set the region to unlocked */
	// printf("unlocked \n");
	close(fd);
      }
      
    }
    free(pagbone_data);
    free(mask_data);
    free(corrected_data);
    free(output_data);
  }
}
