示例#1
0
文件: fftw.cpp 项目: shy3u/GeRelion
// Transform ---------------------------------------------------------------
void FourierTransformer::Transform(int sign)
{
	if (sign == FFTW_FORWARD)
	{
		fftw_execute(fPlanForward);

		// Normalisation of the transform
		unsigned long int size = 0;
		if (fReal != NULL)
		{
			size = MULTIDIM_SIZE(*fReal);
		}
		else if (fComplex != NULL)
		{
			size = MULTIDIM_SIZE(*fComplex);
		}
		else
		{
			REPORT_ERROR("No complex nor real data defined");
		}

		FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(fFourier)
		DIRECT_MULTIDIM_ELEM(fFourier, n) /= size;
	}
	else if (sign == FFTW_BACKWARD)
	{
		fftw_execute(fPlanBackward);
	}

}
void ParticleSorterMpi::run()
{

	int total_nr_images = MDin.numberOfObjects();
	features.resize(total_nr_images, NR_FEATURES);

	// Each node does part of the work
	long int my_first_image, my_last_image, my_nr_images;
	divide_equally(total_nr_images, node->size, node->rank, my_first_image, my_last_image);
	my_nr_images = my_last_image - my_first_image + 1;

	int barstep;
	if (verb > 0)
	{
		std::cout << "Calculating sorting features for all input particles..." << std::endl;
		init_progress_bar(my_nr_images);
		barstep = XMIPP_MAX(1, my_nr_images/ 60);
	}

	long int ipart = 0;
	FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDin)
	{

		if (ipart >= my_first_image && ipart <= my_last_image)
		{
			if (verb > 0 && ipart % barstep == 0)
				progress_bar(ipart);

			calculateFeaturesOneParticle(ipart);

		}
		ipart++;
	}

	if (verb > 0)
		progress_bar(my_nr_images);

	// Combine results from all nodes
	MultidimArray<double> allnodes_features;
	allnodes_features.resize(features);
	MPI_Allreduce(MULTIDIM_ARRAY(features), MULTIDIM_ARRAY(allnodes_features), MULTIDIM_SIZE(features), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
	features = allnodes_features;

	// Only the master writes out files
	if (verb > 0)
	{
		normaliseFeatures();

		writeFeatures();
	}

}
示例#3
0
/* MAIN -------------------------------------------------------------------- */
int main(int argc, char **argv) {

  // For parallelization
  int rank, size, num_img_tot;

  int c,nn,imgno,opt_refno,iaux;
  double LL,sumw_allrefs,sumcorr;
  double aux,wsum_sigma_noise2, wsum_sigma_offset;
  std::vector<Matrix3D<double > > wsum_Mref;
  std::vector<Matrix3D<double > > wsum_Mwedge;
  std::vector<double> sumw;
  Matrix3D<double> Maux, Mauxbig;
  FileName fn_img,fn_tmp;
  Matrix1D<double> oneline(0);
  DocFile DFo,DFf;
  SelFile SFo,SFa;
    
  Prog_MLalign3D_prm prm;

  // Init Parallel interface		
  MPI_Init(&argc, &argv);  
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  MPI_Comm_size(MPI_COMM_WORLD, &size);
   
  // Get input parameters
  try {

    // Read command line
    prm.read(argc,argv);

    // Select only relevant part of selfile for this rank
    mpiSelectPart(prm.SF, rank,size,num_img_tot);

    prm.produce_Side_info();

    if (rank==0) prm.show();
    else  prm.verb=0;

  } catch (XmippError XE) {if (rank==0) {std::cout << XE; prm.usage();} MPI_Finalize(); exit(1);} 

    
  try {

    Maux.resize(prm.dim,prm.dim,prm.dim);
    Maux.setXmippOrigin();
    Mauxbig.resize(prm.bigdim,prm.bigdim,prm.bigdim);
    Mauxbig.setXmippOrigin();
    DFo.reserve(2*prm.SF.ImgNo()+1);
    DFf.reserve(2*prm.SFr.ImgNo()+4);
    SFa.reserve(prm.Niter*prm.nr_ref);
    SFa.clear();

    // Loop over all iterations
    for (int iter=prm.istart; iter<=prm.Niter; iter++) {

      if (prm.verb>0) std::cerr << "  multi-reference refinement:  iteration " << iter <<" of "<< prm.Niter<<std::endl;

      DFo.clear();
      if (rank==0) 
	DFo.append_comment("Headerinfo columns: rot (1), tilt (2), psi (3), Xoff (4), Yoff (5), Zoff (6), WedNo (7) Ref (8), Pmax/sumP (9)");

      // Integrate over all images
      prm.ML_sum_over_all_images(prm.SF,prm.Iref,LL,sumcorr,DFo, 
				 wsum_Mref,wsum_Mwedge,
				 wsum_sigma_noise2,wsum_sigma_offset,sumw); 

      // Here MPI_allreduce of all wsums,LL and sumcorr !!!
      MPI_Allreduce(&LL,&aux,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
      LL=aux;
      MPI_Allreduce(&sumcorr,&aux,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
      sumcorr=aux;
      MPI_Allreduce(&wsum_sigma_offset,&aux,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
      wsum_sigma_offset=aux;
      MPI_Allreduce(&wsum_sigma_noise2,&aux,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
      wsum_sigma_noise2=aux;
      for (int refno=0;refno<prm.nr_ref; refno++) { 
	MPI_Allreduce(MULTIDIM_ARRAY(wsum_Mref[refno]),MULTIDIM_ARRAY(Maux),
		      MULTIDIM_SIZE(wsum_Mref[refno]),MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
	wsum_Mref[refno]=Maux;
	MPI_Allreduce(MULTIDIM_ARRAY(wsum_Mwedge[refno]),MULTIDIM_ARRAY(Mauxbig),
		      MULTIDIM_SIZE(wsum_Mwedge[refno]),MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
	wsum_Mwedge[refno]=Mauxbig;
	MPI_Allreduce(&sumw[refno],&aux,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
	sumw[refno]=aux;
      }

      // Update model parameters
      prm.update_parameters(wsum_Mref,wsum_Mwedge,
			    wsum_sigma_noise2,wsum_sigma_offset,
			    sumw,sumcorr,sumw_allrefs,iter);
 
      // All nodes write out temporary DFo 
      fn_img.compose(prm.fn_root,rank,"tmpdoc");
      DFo.write(fn_img);
      MPI_Barrier(MPI_COMM_WORLD);

      if (rank==0) {
	prm.write_output_files(iter,SFa,DFf,sumw_allrefs,sumw,LL,sumcorr);
	
	// Write out docfile with optimal transformation & references
	DFo.clear();
	for (int rank2=0; rank2<size; rank2++) {
	  fn_img.compose(prm.fn_root,rank2,"tmpdoc");
	  int ln=DFo.LineNo();
	  DFo.append(fn_img);
	  DFo.locate(DFo.get_last_key());
	  DFo.next();
	  DFo.remove_current();
	  system(((std::string)"rm -f "+fn_img).c_str());
	}
	
	fn_tmp=prm.fn_root+"_it";
	fn_tmp.compose(fn_tmp,iter,"doc");
	DFo.write(fn_tmp);

      }
      
    } // end loop iterations


  } catch (XmippError XE) {if (rank==0) {std::cout << XE; prm.usage();} MPI_Finalize(); exit(1);}


  MPI_Finalize();	
  return 0;

}
示例#4
0
// Fit the beam-induced translations for all average micrographs
void ParticlePolisherMpi::fitMovementsAllMicrographs()
{

	int total_nr_micrographs = exp_model.average_micrographs.size();

	// Each node does part of the work
	long int my_first_micrograph, my_last_micrograph, my_nr_micrographs;
	divide_equally(total_nr_micrographs, node->size, node->rank, my_first_micrograph, my_last_micrograph);
	my_nr_micrographs = my_last_micrograph - my_first_micrograph + 1;

	// Loop over all average micrographs
	int barstep;
	if (verb > 0)
	{
		std::cout << " + Fitting straight paths for beam-induced movements in all micrographs ... " << std::endl;
		init_progress_bar(my_nr_micrographs);
		barstep = XMIPP_MAX(1, my_nr_micrographs/ 60);
	}

	for (long int i = my_first_micrograph; i <= my_last_micrograph; i++)
	{
    	if (verb > 0 && i % barstep == 0)
			progress_bar(i);

		fitMovementsOneMicrograph(i);
	}

	// Wait until all micrographs have been done
	MPI_Barrier(MPI_COMM_WORLD);

	if (verb > 0)
	{
		progress_bar(my_nr_micrographs);
	}

	// Combine results from all nodes
	MultidimArray<DOUBLE> allnodes_fitted_movements;
	allnodes_fitted_movements.resize(fitted_movements);
	MPI_Allreduce(MULTIDIM_ARRAY(fitted_movements), MULTIDIM_ARRAY(allnodes_fitted_movements), MULTIDIM_SIZE(fitted_movements), MY_MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
	fitted_movements = allnodes_fitted_movements;

    // Set the fitted movements in the xoff and yoff columns of the exp_model.MDimg
    for (long int ipart = 0; ipart < exp_model.numberOfParticles(); ipart++)
	{
		long int part_id = exp_model.particles[ipart].id;
		DOUBLE xoff = DIRECT_A2D_ELEM(fitted_movements, part_id, 0);
		DOUBLE yoff = DIRECT_A2D_ELEM(fitted_movements, part_id, 1);
		exp_model.MDimg.setValue(EMDL_ORIENT_ORIGIN_X, xoff, part_id);
		exp_model.MDimg.setValue(EMDL_ORIENT_ORIGIN_Y, yoff, part_id);
	}

    if (node->isMaster())
    {
		// Write out the STAR file with all the fitted movements
		FileName fn_tmp = fn_in.withoutExtension() + "_" + fn_out + ".star";
		exp_model.MDimg.write(fn_tmp);
		std::cout << " + Written out all fitted movements in STAR file: " << fn_tmp << std::endl;
    }


}
示例#5
0
void ParticlePolisherMpi::optimiseBeamTilt()
{

	// This function assumes the shiny particles are in exp_mdel.MDimg!!

	if (beamtilt_max <= 0. && defocus_shift_max <= 0.)
		return;

	if (minres_beamtilt < maxres_model)
	{
		if (verb > 0)
			std::cout << " Skipping beamtilt correction, as the resolution of the shiny reconstruction  does not go beyond minres_beamtilt of " << minres_beamtilt << " Ang." << std::endl;
		return;
	}

	getBeamTiltGroups();

	initialiseSquaredDifferenceVectors();

	int total_nr_micrographs = exp_model.micrographs.size();

	// Each node does part of the work
	long int my_first_micrograph, my_last_micrograph, my_nr_micrographs;
	divide_equally(total_nr_micrographs, node->size, node->rank, my_first_micrograph, my_last_micrograph);
	my_nr_micrographs = my_last_micrograph - my_first_micrograph + 1;

	// Loop over all average micrographs
	int barstep;
	if (verb > 0)
	{
		std::cout << " + Optimising beamtilts and/or defocus values in all micrographs ... " << std::endl;
		init_progress_bar(my_nr_micrographs);
		barstep = XMIPP_MAX(1, my_nr_micrographs/ 60);
	}

    for (long int i = my_first_micrograph; i <= my_last_micrograph; i++)
	{
    	if (verb > 0 && i % barstep == 0)
			progress_bar(i);

    	optimiseBeamTiltAndDefocusOneMicrograph(i);
	}

   	if (verb > 0)
   		progress_bar(my_nr_micrographs);

	// Combine results from all nodes
	if (beamtilt_max > 0.)
	{
		MultidimArray<DOUBLE> allnodes_diff2_beamtilt;
		allnodes_diff2_beamtilt.initZeros(diff2_beamtilt);
		MPI_Allreduce(MULTIDIM_ARRAY(diff2_beamtilt), MULTIDIM_ARRAY(allnodes_diff2_beamtilt), MULTIDIM_SIZE(diff2_beamtilt), MY_MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
		diff2_beamtilt = allnodes_diff2_beamtilt;
	}

	if (defocus_shift_max > 0.)
	{
		MultidimArray<DOUBLE> allnodes_defocus_shift_allmics;
		allnodes_defocus_shift_allmics.initZeros(defocus_shift_allmics);
		MPI_Allreduce(MULTIDIM_ARRAY(defocus_shift_allmics), MULTIDIM_ARRAY(allnodes_defocus_shift_allmics), MULTIDIM_SIZE(defocus_shift_allmics), MY_MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
		defocus_shift_allmics = allnodes_defocus_shift_allmics;
	}

	// Now get the final optimised beamtilts and defocus shifts, and write results to the MetadataTable
	applyOptimisedBeamTiltsAndDefocus();

	// Write the new MDTable to disc
	if (verb > 0)
		exp_model.MDimg.write(fn_out + ".star");

}
示例#6
0
void ParticlePolisherMpi::calculateAllSingleFrameReconstructionsAndBfactors()
{

	FileName fn_star = fn_in.withoutExtension() + "_" + fn_out + "_bfactors.star";
	if (!do_start_all_over && readStarFileBfactors(fn_star))
	{
		if (verb > 0)
			std::cout << " + " << fn_star << " already exists: skipping calculation average of per-frame B-factors." <<std::endl;
		return;
	}

	DOUBLE bfactor, offset, corr_coeff;

	int total_nr_frames = last_frame - first_frame + 1;
	long int my_first_frame, my_last_frame, my_nr_frames;

	// Loop over all frames (two halves for each frame!) to be included in the reconstruction
	// Each node does part of the work
	divide_equally(2*total_nr_frames, node->size, node->rank, my_first_frame, my_last_frame);
	my_nr_frames = my_last_frame - my_first_frame + 1;

	if (verb > 0)
	{
		std::cout << " + Calculating per-frame reconstructions ... " << std::endl;
		init_progress_bar(my_nr_frames);
	}

	for (long int i = my_first_frame; i <= my_last_frame; i++)
	{

		int iframe = (i >= total_nr_frames) ? i - total_nr_frames : i;
		iframe += first_frame;
		int ihalf = (i >= total_nr_frames) ? 2 : 1;

		calculateSingleFrameReconstruction(iframe, ihalf);

    	if (verb > 0)
    		progress_bar(i - my_first_frame + 1);
	}

	if (verb > 0)
	{
		progress_bar(my_nr_frames);
	}

	MPI_Barrier(MPI_COMM_WORLD);

	// Also calculate the average of all single-frames for both halves
    if (node->rank == 0)
    	calculateAverageAllSingleFrameReconstructions(1);
    else if (node->rank == 1)
    	calculateAverageAllSingleFrameReconstructions(2);

	// Wait until all reconstructions have been done, and calculate the B-factors per-frame
	MPI_Barrier(MPI_COMM_WORLD);

	calculateBfactorSingleFrameReconstruction(-1, bfactor, offset, corr_coeff); // FSC between the two averages, also reads mask

	MPI_Barrier(MPI_COMM_WORLD);

	// Loop over all frames (two halves for each frame!) to be included in the reconstruction
	// Each node does part of the work
	divide_equally(total_nr_frames, node->size, node->rank, my_first_frame, my_last_frame);
	my_nr_frames = my_last_frame - my_first_frame + 1;

	if (verb > 0)
	{
		std::cout << " + Calculating per-frame B-factors ... " << std::endl;
		init_progress_bar(my_nr_frames);
	}

	for (long int i = first_frame+my_first_frame; i <= first_frame+my_last_frame; i++)
	{

		calculateBfactorSingleFrameReconstruction(i, bfactor, offset, corr_coeff);
		int iframe = i - first_frame;
		DIRECT_A1D_ELEM(perframe_bfactors, iframe * 3 + 0) = bfactor;
       	DIRECT_A1D_ELEM(perframe_bfactors, iframe * 3 + 1) = offset;
       	DIRECT_A1D_ELEM(perframe_bfactors, iframe * 3 + 2) = corr_coeff;

    	if (verb > 0)
    		progress_bar(i - first_frame - my_first_frame + 1);
	}

	// Combine results from all nodes
	MultidimArray<DOUBLE> allnodes_perframe_bfactors;
	allnodes_perframe_bfactors.resize(perframe_bfactors);
	MPI_Allreduce(MULTIDIM_ARRAY(perframe_bfactors), MULTIDIM_ARRAY(allnodes_perframe_bfactors), MULTIDIM_SIZE(perframe_bfactors), MY_MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
	perframe_bfactors = allnodes_perframe_bfactors;

	if (verb > 0)
	{
		progress_bar(my_nr_frames);
		writeStarFileBfactors(fn_star);

	    // Also write a STAR file with the relative contributions of each frame to all frequencies
	    fn_star = fn_in.withoutExtension() + "_" + fn_out + "_relweights.star";
	    writeStarFileRelativeWeights(fn_star);
	}


}
示例#7
0
文件: fftw.cpp 项目: shy3u/GeRelion
void FourierTransformer::setFourier(MultidimArray<Complex >& inputFourier)
{
	memcpy(MULTIDIM_ARRAY(fFourier), MULTIDIM_ARRAY(inputFourier),
	       MULTIDIM_SIZE(inputFourier) * 2 * sizeof(double));
}
示例#8
0
文件: fftw.cpp 项目: shy3u/GeRelion
void correctMapForMTF(MultidimArray<Complex >& FT, int ori_size, FileName& fn_mtf)
{

	MetaDataTable MDmtf;

	if (!fn_mtf.isStarFile())
	{
		REPORT_ERROR("correctMapForMTF ERROR: input MTF file is not a STAR file.");
	}

	MDmtf.read(fn_mtf);
	MultidimArray<double> mtf_resol, mtf_value;
	mtf_resol.resize(MDmtf.numberOfObjects());
	mtf_value.resize(mtf_resol);

	int i = 0;
	FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDmtf)
	{
		MDmtf.getValue(EMDL_RESOLUTION_INVPIXEL, DIRECT_A1D_ELEM(mtf_resol, i));  // resolution needs to be given in 1/pix
		MDmtf.getValue(EMDL_POSTPROCESS_MTF_VALUE, DIRECT_A1D_ELEM(mtf_value, i));
		if (DIRECT_A1D_ELEM(mtf_value, i) < 1e-10)
		{
			std::cerr << " i= " << i <<  " mtf_value[i]= " << DIRECT_A1D_ELEM(mtf_value, i) << std::endl;
			REPORT_ERROR("Postprocessing::sharpenMap ERROR: zero or negative values encountered in MTF curve!");
		}
		i++;
	}

	double xsize = (double)ori_size;
	FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(FT)
	{
		int r2 = kp * kp + ip * ip + jp * jp;
		double res = sqrt((double)r2) / xsize; // get resolution in 1/pixel
		if (res < 0.5)
		{

			// Find the suitable MTF value
			int i_0 = 0;
			for (int ii = 0; ii < XSIZE(mtf_resol); ii++)
			{
				if (DIRECT_A1D_ELEM(mtf_resol, ii) > res)
				{
					break;
				}
				i_0 = ii;
			}
			// linear interpolation: y = y_0 + (y_1 - y_0)*(x-x_0)/(x1_x0)
			double mtf;
			double x_0 = DIRECT_A1D_ELEM(mtf_resol, i_0);
			if (i_0 == MULTIDIM_SIZE(mtf_resol) - 1 || i_0 == 0) // check boundaries of the array
			{
				mtf = DIRECT_A1D_ELEM(mtf_value, i_0);
			}
			else
			{
				double x_1 = DIRECT_A1D_ELEM(mtf_resol, i_0 + 1);
				double y_0 = DIRECT_A1D_ELEM(mtf_value, i_0);
				double y_1 = DIRECT_A1D_ELEM(mtf_value, i_0 + 1);
				mtf = y_0 + (y_1 - y_0) * (res - x_0) / (x_1 - x_0);
			}

			// Divide Fourier component by the MTF
			DIRECT_A3D_ELEM(FT, k, i, j) /= mtf;
		}
	}



}
示例#9
0
// Transform ---------------------------------------------------------------
void FourierTransformer::Transform(int sign)
{
    if (sign == FFTW_FORWARD)
    {
        fftw_execute(fPlanForward);

        if (sign == normSign)
        {
            unsigned long int size=0;
            if(fReal!=NULL)
                size = MULTIDIM_SIZE(*fReal);
            else if (fComplex!= NULL)
                size = MULTIDIM_SIZE(*fComplex);
            else
                REPORT_ERROR(ERR_UNCLASSIFIED,"No complex nor real data defined");

            double isize=1.0/size;
            double *ptr=(double*)MULTIDIM_ARRAY(fFourier);
            size_t nmax=(fFourier.nzyxdim/4)*4;
            for (size_t n=0; n<nmax; n+=4)
            {
                *ptr++ *= isize;
                *ptr++ *= isize;
                *ptr++ *= isize;
                *ptr++ *= isize;
                *ptr++ *= isize;
                *ptr++ *= isize;
                *ptr++ *= isize;
                *ptr++ *= isize;
            }
            for (size_t n=nmax; n<fFourier.nzyxdim; ++n)
            {
                *ptr++ *= isize;
                *ptr++ *= isize;
            }
        }
    }
    else if (sign == FFTW_BACKWARD)
    {
        fftw_execute(fPlanBackward);

        if (sign == normSign)
        {
            unsigned long int size=0;
            if(fReal!=NULL)
            {
                size = MULTIDIM_SIZE(*fReal);
                double isize=1.0/size;
                FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(*fReal)
                DIRECT_MULTIDIM_ELEM(*fReal,n) *= isize;
            }
            else if (fComplex!= NULL)
            {
                size = MULTIDIM_SIZE(*fComplex);
                double isize=1.0/size;
                double *ptr=(double*)MULTIDIM_ARRAY(*fComplex);
                FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(*fComplex)
                {
                    *ptr++ *= isize;
                    *ptr++ *= isize;
                }
            }
示例#10
0
void FourierTransformer::setFourier(const MultidimArray<std::complex<double> > &inputFourier)
{
    memcpy(MULTIDIM_ARRAY(fFourier),MULTIDIM_ARRAY(inputFourier),
           MULTIDIM_SIZE(inputFourier)*2*sizeof(double));
}
示例#11
0
void MpiProgReconstructADMM::shareVolume(MultidimArray<double> &V)
{
	MPI_Allreduce(MPI_IN_PLACE, MULTIDIM_ARRAY(V), MULTIDIM_SIZE(V), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
	synchronize();
}
示例#12
0
void Postprocessing::divideByMtf(MultidimArray<Complex > &FT)
{

	if (fn_mtf != "")
	{
		if (verb > 0)
		{
			std::cout << "== Dividing map by the MTF of the detector ..." << std::endl;
			std::cout.width(35); std::cout << std::left <<"  + mtf STAR-file: "; std::cout << fn_mtf << std::endl;
		}

		MetaDataTable MDmtf;

		if (!fn_mtf.isStarFile())
			REPORT_ERROR("Postprocessing::divideByMtf ERROR: input MTF file is not a STAR file.");

		MDmtf.read(fn_mtf);
		MultidimArray<DOUBLE> mtf_resol, mtf_value;
		mtf_resol.resize(MDmtf.numberOfObjects());
		mtf_value.resize(mtf_resol);

		int i =0;
		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDmtf)
		{
			MDmtf.getValue(EMDL_RESOLUTION_INVPIXEL, DIRECT_A1D_ELEM(mtf_resol, i) ); // resolution needs to be given in 1/pix
			MDmtf.getValue(EMDL_POSTPROCESS_MTF_VALUE, DIRECT_A1D_ELEM(mtf_value, i) );
			if (DIRECT_A1D_ELEM(mtf_value, i) < 1e-10)
			{
				std::cerr << " i= " << i <<  " mtf_value[i]= " << DIRECT_A1D_ELEM(mtf_value, i) << std::endl;
				REPORT_ERROR("Postprocessing::sharpenMap ERROR: zero or negative values encountered in MTF curve!");
			}
			i++;
		}

	    DOUBLE xsize = (DOUBLE)XSIZE(I1());
	    FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(FT)
	    {
	    	int r2 = kp * kp + ip * ip + jp * jp;
	    	DOUBLE res = sqrt((DOUBLE)r2)/xsize; // get resolution in 1/pixel
			if (res < 0.5 )
			{

				// Find the suitable MTF value
				int i_0 = 0;
				for (int ii = 0; ii < XSIZE(mtf_resol); ii++)
				{
					if (DIRECT_A1D_ELEM(mtf_resol, ii) > res)
						break;
					i_0 = ii;
				}
				// linear interpolation: y = y_0 + (y_1 - y_0)*(x-x_0)/(x1_x0)
				DOUBLE mtf;
				DOUBLE x_0 = DIRECT_A1D_ELEM(mtf_resol, i_0);
				if (i_0 == MULTIDIM_SIZE(mtf_resol) - 1 || i_0 == 0) // check boundaries of the array
					mtf = DIRECT_A1D_ELEM(mtf_value, i_0);
				else
				{
					DOUBLE x_1 = DIRECT_A1D_ELEM(mtf_resol, i_0 + 1);
					DOUBLE y_0 = DIRECT_A1D_ELEM(mtf_value, i_0);
					DOUBLE y_1 = DIRECT_A1D_ELEM(mtf_value, i_0 + 1);
					mtf = y_0 + (y_1 - y_0)*(res - x_0)/(x_1 - x_0);
				}

				// Divide Fourier component by the MTF
				DIRECT_A3D_ELEM(FT, k, i, j) /= mtf;
			}
	    }

	}


}