// Inforce Hermitian symmetry --------------------------------------------- void FourierTransformer::enforceHermitianSymmetry() { int ndim = 3; if (ZSIZE(*fReal) == 1) { ndim = 2; if (YSIZE(*fReal) == 1) { ndim = 1; } } long int yHalf = YSIZE(*fReal) / 2; if (YSIZE(*fReal) % 2 == 0) { yHalf--; } long int zHalf = ZSIZE(*fReal) / 2; if (ZSIZE(*fReal) % 2 == 0) { zHalf--; } switch (ndim) { case 2: for (long int i = 1; i <= yHalf; i++) { long int isym = intWRAP(-i, 0, YSIZE(*fReal) - 1); Complex mean = 0.5 * ( DIRECT_A2D_ELEM(fFourier, i, 0) + conj(DIRECT_A2D_ELEM(fFourier, isym, 0))); DIRECT_A2D_ELEM(fFourier, i, 0) = mean; DIRECT_A2D_ELEM(fFourier, isym, 0) = conj(mean); } break; case 3: for (long int k = 0; k < ZSIZE(*fReal); k++) { long int ksym = intWRAP(-k, 0, ZSIZE(*fReal) - 1); for (long int i = 1; i <= yHalf; i++) { long int isym = intWRAP(-i, 0, YSIZE(*fReal) - 1); Complex mean = 0.5 * ( DIRECT_A3D_ELEM(fFourier, k, i, 0) + conj(DIRECT_A3D_ELEM(fFourier, ksym, isym, 0))); DIRECT_A3D_ELEM(fFourier, k, i, 0) = mean; DIRECT_A3D_ELEM(fFourier, ksym, isym, 0) = conj(mean); } } for (long int k = 1; k <= zHalf; k++) { long int ksym = intWRAP(-k, 0, ZSIZE(*fReal) - 1); Complex mean = 0.5 * ( DIRECT_A3D_ELEM(fFourier, k, 0, 0) + conj(DIRECT_A3D_ELEM(fFourier, ksym, 0, 0))); DIRECT_A3D_ELEM(fFourier, k, 0, 0) = mean; DIRECT_A3D_ELEM(fFourier, ksym, 0, 0) = conj(mean); } break; } }
void FourierProjector::produceSideInfo() { // Zero padding MultidimArray<double> Vpadded; int paddedDim=(int)(paddingFactor*volumeSize); // JMRT: TODO: I think it is a very poor design to modify the volume passed // in the construct, it will be padded anyway, so new memory should be allocated volume->window(Vpadded,FIRST_XMIPP_INDEX(paddedDim),FIRST_XMIPP_INDEX(paddedDim),FIRST_XMIPP_INDEX(paddedDim), LAST_XMIPP_INDEX(paddedDim),LAST_XMIPP_INDEX(paddedDim),LAST_XMIPP_INDEX(paddedDim)); volume->clear(); // Make Fourier transform, shift the volume origin to the volume center and center it MultidimArray< std::complex<double> > Vfourier; transformer3D.completeFourierTransform(Vpadded,Vfourier); ShiftFFT(Vfourier, FIRST_XMIPP_INDEX(XSIZE(Vpadded)), FIRST_XMIPP_INDEX(YSIZE(Vpadded)), FIRST_XMIPP_INDEX(ZSIZE(Vpadded))); CenterFFT(Vfourier,true); Vfourier.setXmippOrigin(); // Compensate for the Fourier normalization factor double K=(double)(XSIZE(Vpadded)*XSIZE(Vpadded)*XSIZE(Vpadded))/(double)(volumeSize*volumeSize); FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Vfourier) DIRECT_MULTIDIM_ELEM(Vfourier,n)*=K; Vpadded.clear(); // Compute Bspline coefficients if (BSplineDeg==3) { MultidimArray< double > VfourierRealAux, VfourierImagAux; Complex2RealImag(Vfourier, VfourierRealAux, VfourierImagAux); Vfourier.clear(); produceSplineCoefficients(BSPLINE3,VfourierRealCoefs,VfourierRealAux); produceSplineCoefficients(BSPLINE3,VfourierImagCoefs,VfourierImagAux); //VfourierRealAux.clear(); //VfourierImagAux.clear(); } else Complex2RealImag(Vfourier, VfourierRealCoefs, VfourierImagCoefs); // Allocate memory for the 2D Fourier transform projection().initZeros(volumeSize,volumeSize); projection().setXmippOrigin(); transformer2D.FourierTransform(projection(),projectionFourier,false); // Calculate phase shift terms phaseShiftImgA.initZeros(projectionFourier); phaseShiftImgB.initZeros(projectionFourier); double shift=-FIRST_XMIPP_INDEX(volumeSize); double xxshift = -2 * PI * shift / volumeSize; for (size_t i=0; i<YSIZE(projectionFourier); ++i) { double phasey=(double)(i) * xxshift; for (size_t j=0; j<XSIZE(projectionFourier); ++j) { // Phase shift to move the origin of the image to the corner double dotp = (double)(j) * xxshift + phasey; sincos(dotp,&DIRECT_A2D_ELEM(phaseShiftImgB,i,j),&DIRECT_A2D_ELEM(phaseShiftImgA,i,j)); } } }
TEST_F( FftwTest, directFourierTransformComplex) { MultidimArray< std::complex< double > > FFT1, complxDouble; FourierTransformer transformer1; typeCast(mulDouble, complxDouble); transformer1.FourierTransform(complxDouble, FFT1, false); transformer1.inverseFourierTransform(); transformer1.inverseFourierTransform(); MultidimArray<std::complex<double> > auxFFT; auxFFT.resize(3,3); DIRECT_A2D_ELEM(auxFFT,0,0) = std::complex<double>(2.77778,0); DIRECT_A2D_ELEM(auxFFT,0,1) = std::complex<double>(-0.0555556,0.096225); DIRECT_A2D_ELEM(auxFFT,0,2) = std::complex<double>(-0.0555556,-0.096225); DIRECT_A2D_ELEM(auxFFT,1,0) = std::complex<double>(-0.388889,0.673575) ; DIRECT_A2D_ELEM(auxFFT,1,1) = std::complex<double>(-0.388889,-0.096225); DIRECT_A2D_ELEM(auxFFT,1,2) = std::complex<double>(-0.0555556,-0.288675); DIRECT_A2D_ELEM(auxFFT,2,0) = std::complex<double>(-0.388889,-0.673575) ; DIRECT_A2D_ELEM(auxFFT,2,1) = std::complex<double>(-0.0555556,0.288675) ; DIRECT_A2D_ELEM(auxFFT,2,2) = std::complex<double>(-0.388889,0.096225) ; EXPECT_EQ(FFT1,auxFFT); transformer1.cleanup(); }
void actualPhaseFlip(MultidimArray<double> &I, CTFDescription ctf) { // Perform the Fourier transform FourierTransformer transformer; MultidimArray< std::complex<double> > M_inFourier; transformer.FourierTransform(I,M_inFourier,false); Matrix1D<double> freq(2); // Frequencies for Fourier plane int yDim=YSIZE(I); int xDim=XSIZE(I); double iTm=1.0/ctf.Tm; for (size_t i=0; i<YSIZE(M_inFourier); ++i) { FFT_IDX2DIGFREQ(i, yDim, YY(freq)); YY(freq) *= iTm; for (size_t j=0; j<XSIZE(M_inFourier); ++j) { FFT_IDX2DIGFREQ(j, xDim, XX(freq)); XX(freq) *= iTm; ctf.precomputeValues(XX(freq),YY(freq)); if (ctf.getValuePureWithoutDampingAt()<0) DIRECT_A2D_ELEM(M_inFourier,i,j)*=-1; } } // Perform inverse Fourier transform and finish transformer.inverseFourierTransform(); }
//init metadatas virtual void SetUp() { mulDouble.resize(3,3); DIRECT_A2D_ELEM(mulDouble,0,0) = 1; DIRECT_A2D_ELEM(mulDouble,0,1) = 2; DIRECT_A2D_ELEM(mulDouble,0,2) = 3; DIRECT_A2D_ELEM(mulDouble,1,0) = 3; DIRECT_A2D_ELEM(mulDouble,1,1) = 2; DIRECT_A2D_ELEM(mulDouble,1,2) = 1; DIRECT_A2D_ELEM(mulDouble,2,0) = 4; DIRECT_A2D_ELEM(mulDouble,2,1) = 4; DIRECT_A2D_ELEM(mulDouble,2,2) = 5; }
/* Generate a complete CTF Image ------------------------------------------------------ */ void CTF::getFftwImage(MultidimArray<DOUBLE> &result, int orixdim, int oriydim, DOUBLE angpix, bool do_abs, bool do_only_flip_phases, bool do_intact_until_first_peak, bool do_damping) { DOUBLE xs = (DOUBLE)orixdim * angpix; DOUBLE ys = (DOUBLE)oriydim * angpix; FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM2D(result) { DOUBLE x = (DOUBLE)jp / xs; DOUBLE y = (DOUBLE)ip / ys; DIRECT_A2D_ELEM(result, i, j) = getCTF(x, y, do_abs, do_only_flip_phases, do_intact_until_first_peak, do_damping); } }
EnsembleNaiveBayes::EnsembleNaiveBayes( const std::vector < MultidimArray<double> > &features, const Matrix1D<double> &priorProbs, int discreteLevels, int numberOfClassifiers, double samplingFeatures, double samplingIndividuals, const std::string &newJudgeCombination) { int NFeatures=XSIZE(features[0]); int NsubFeatures=CEIL(NFeatures*samplingFeatures); K=features.size(); judgeCombination=newJudgeCombination; #ifdef WEIGHTED_SAMPLING // Measure the classification power of each variable NaiveBayes *nb_weights=new NaiveBayes(features, priorProbs, discreteLevels); MultidimArray<double> weights=nb_weights->__weights; delete nb_weights; double sumWeights=weights.sum(); #endif for (int n=0; n<numberOfClassifiers; n++) { // Produce the set of features for this subclassifier MultidimArray<int> subFeatures(NsubFeatures); FOR_ALL_ELEMENTS_IN_ARRAY1D(subFeatures) { #ifdef WEIGHTED_SAMPLING double random_sum_weight=rnd_unif(0,sumWeights); int j=0; do { double wj=DIRECT_A1D_ELEM(weights,j); if (wj<random_sum_weight) { random_sum_weight-=wj; j++; if (j==NFeatures) { j=NFeatures-1; break; } } else break; } while (true); DIRECT_A1D_ELEM(subFeatures,i)=j; #else DIRECT_A1D_ELEM(subFeatures,i)=round(rnd_unif(0,NFeatures-1)); #endif } // Container for the new training sample std::vector< MultidimArray<double> > newFeatures; // Produce the data set for each class for (int k=0; k<K; k++) { int NIndividuals=YSIZE(features[k]); int NsubIndividuals=CEIL(NIndividuals*samplingIndividuals); MultidimArray<int> subIndividuals(NsubIndividuals); FOR_ALL_ELEMENTS_IN_ARRAY1D(subIndividuals) subIndividuals(i)=ROUND(rnd_unif(0,NsubIndividuals-1)); MultidimArray<double> newFeaturesK; newFeaturesK.initZeros(NsubIndividuals,NsubFeatures); const MultidimArray<double>& features_k=features[k]; FOR_ALL_ELEMENTS_IN_ARRAY2D(newFeaturesK) DIRECT_A2D_ELEM(newFeaturesK,i,j)=DIRECT_A2D_ELEM(features_k, DIRECT_A1D_ELEM(subIndividuals,i), DIRECT_A1D_ELEM(subFeatures,j)); newFeatures.push_back(newFeaturesK); } // Create a Naive Bayes classifier with this data NaiveBayes *nb=new NaiveBayes(newFeatures, priorProbs, discreteLevels); ensemble.push_back(nb); ensembleFeatures.push_back(subFeatures); } }
// Split several histograms within the indexes l0 and lF so that // the entropy after division is maximized int splitHistogramsUsingEntropy(const std::vector<Histogram1D> &hist, size_t l0, size_t lF) { // Number of classes int K = hist.size(); // Set everything outside l0 and lF to zero, and make it a PDF std::vector<Histogram1D> histNorm; for (int k = 0; k < K; k++) { Histogram1D histaux = hist[k]; for (size_t l = 0; l < XSIZE(histaux); l++) if (l < l0 || l > lF) DIRECT_A1D_ELEM(histaux,l) = 0; histaux *= 1.0/histaux.sum(); histNorm.push_back(histaux); } // Compute for each class the probability of being l<=l0 and l>l0 MultidimArray<double> p(K, 2); for (int k = 0; k < K; k++) { const Histogram1D& histogram=histNorm[k]; DIRECT_A2D_ELEM(p,k, 0) = DIRECT_A1D_ELEM(histogram,l0); DIRECT_A2D_ELEM(p,k, 1) = 0; for (size_t l = l0 + 1; l <= lF; l++) DIRECT_A2D_ELEM(p,k, 1) += DIRECT_A1D_ELEM(histogram,l); } // Compute the splitting l giving maximum entropy double maxEntropy = 0; int lmaxEntropy = -1; size_t l = l0; while (l < lF) { // Compute the entropy of the classes if we split by l double entropy = 0; FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(p) { double aux=DIRECT_MULTIDIM_ELEM(p,n); if (aux != 0) entropy -= aux * log10(aux); } #ifdef DEBUG_SPLITTING_USING_ENTROPY std::cout << "Splitting at " << l << " entropy=" << entropy << std::endl; #endif // Check if this is the maximum if (entropy > maxEntropy) { maxEntropy = entropy; lmaxEntropy = l; } // Move to next split point ++l; // Update probabilities of being l<=l0 and l>l0 for (int k = 0; k < K; k++) { const Histogram1D& histogram=histNorm[k]; double aux=DIRECT_A1D_ELEM(histogram,l); DIRECT_A2D_ELEM(p,k, 0) += aux; DIRECT_A2D_ELEM(p,k, 1) -= aux; } } #ifdef DEBUG_SPLITTING_USING_ENTROPY std::cout << "Finally in l=[" << l0 << "," << lF << " Max Entropy:" << maxEntropy << " lmax=" << lmaxEntropy << std::endl; #endif // If the point giving the maximum entropy is too much on the extreme, // substitute it by the middle point if (lmaxEntropy<=2 || lmaxEntropy>=(int)lF-2) lmaxEntropy = (int)ceil((lF + l0)/2.0); return lmaxEntropy; }
void FourierProjector::project(double rot, double tilt, double psi) { double freqy, freqx; std::complex< double > f; Euler_angles2matrix(rot,tilt,psi,E); projectionFourier.initZeros(); double shift=-FIRST_XMIPP_INDEX(volumeSize); double xxshift = -2 * PI * shift / volumeSize; double maxFreq2=maxFrequency*maxFrequency; double volumePaddedSize=XSIZE(VfourierRealCoefs); for (size_t i=0; i<YSIZE(projectionFourier); ++i) { FFT_IDX2DIGFREQ(i,volumeSize,freqy); double freqy2=freqy*freqy; double phasey=(double)(i) * xxshift; double freqYvol_X=MAT_ELEM(E,1,0)*freqy; double freqYvol_Y=MAT_ELEM(E,1,1)*freqy; double freqYvol_Z=MAT_ELEM(E,1,2)*freqy; for (size_t j=0; j<XSIZE(projectionFourier); ++j) { // The frequency of pairs (i,j) in 2D FFT_IDX2DIGFREQ(j,volumeSize,freqx); // Do not consider pixels with high frequency if ((freqy2+freqx*freqx)>maxFreq2) continue; // Compute corresponding frequency in the volume double freqvol_X=freqYvol_X+MAT_ELEM(E,0,0)*freqx; double freqvol_Y=freqYvol_Y+MAT_ELEM(E,0,1)*freqx; double freqvol_Z=freqYvol_Z+MAT_ELEM(E,0,2)*freqx; double c,d; if (BSplineDeg==0) { // 0 order interpolation // Compute corresponding index in the volume int kVolume=(int)round(freqvol_Z*volumePaddedSize); int iVolume=(int)round(freqvol_Y*volumePaddedSize); int jVolume=(int)round(freqvol_X*volumePaddedSize); c = A3D_ELEM(VfourierRealCoefs,kVolume,iVolume,jVolume); d = A3D_ELEM(VfourierImagCoefs,kVolume,iVolume,jVolume); } else if (BSplineDeg==1) { // B-spline linear interpolation double kVolume=freqvol_Z*volumePaddedSize; double iVolume=freqvol_Y*volumePaddedSize; double jVolume=freqvol_X*volumePaddedSize; c=VfourierRealCoefs.interpolatedElement3D(jVolume,iVolume,kVolume); d=VfourierImagCoefs.interpolatedElement3D(jVolume,iVolume,kVolume); } else { // B-spline cubic interpolation double kVolume=freqvol_Z*volumePaddedSize; double iVolume=freqvol_Y*volumePaddedSize; double jVolume=freqvol_X*volumePaddedSize; c=VfourierRealCoefs.interpolatedElementBSpline3D(jVolume,iVolume,kVolume); d=VfourierImagCoefs.interpolatedElementBSpline3D(jVolume,iVolume,kVolume); } // Phase shift to move the origin of the image to the corner double dotp = (double)(j) * xxshift + phasey; double a,b; sincos(dotp,&b,&a); // Multiply Fourier coefficient in volume times phase shift double ac = a * c; double bd = b * d; double ab_cd = (a + b) * (c + d); // And store the multiplication double *ptrI_ij=(double *)&DIRECT_A2D_ELEM(projectionFourier,i,j); *ptrI_ij = ac - bd; *(ptrI_ij+1) = ab_cd - ac - bd; } } //VfourierRealCoefs.clear(); //VfourierImagCoefs.clear(); transformer2D.inverseFourierTransform(); }
// 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; } }
// Shift an image through phase-shifts in its Fourier Transform (without pretabulated sine and cosine) void shiftImageInFourierTransform(MultidimArray<Complex >& in, MultidimArray<Complex >& out, double oridim, Matrix1D<double> shift) { out.resize(in); shift /= -oridim; double dotp, a, b, c, d, ac, bd, ab_cd, x, y, z, xshift, yshift, zshift; switch (in.getDim()) { case 1: xshift = XX(shift); if (ABS(xshift) < XMIPP_EQUAL_ACCURACY) { out = in; return; } for (long int j = 0; j < XSIZE(in); j++) { x = j; dotp = 2 * PI * (x * xshift); a = cos(dotp); b = sin(dotp); c = DIRECT_A1D_ELEM(in, j).real; d = DIRECT_A1D_ELEM(in, j).imag; ac = a * c; bd = b * d; ab_cd = (a + b) * (c + d); // (ab_cd-ac-bd = ad+bc : but needs 4 multiplications) DIRECT_A1D_ELEM(out, j) = Complex(ac - bd, ab_cd - ac - bd); } break; case 2: xshift = XX(shift); yshift = YY(shift); if (ABS(xshift) < XMIPP_EQUAL_ACCURACY && ABS(yshift) < XMIPP_EQUAL_ACCURACY) { out = in; return; } for (long int i = 0; i < XSIZE(in); i++) for (long int j = 0; j < XSIZE(in); j++) { x = j; y = i; dotp = 2 * PI * (x * xshift + y * yshift); a = cos(dotp); b = sin(dotp); c = DIRECT_A2D_ELEM(in, i, j).real; d = DIRECT_A2D_ELEM(in, i, j).imag; ac = a * c; bd = b * d; ab_cd = (a + b) * (c + d); DIRECT_A2D_ELEM(out, i, j) = Complex(ac - bd, ab_cd - ac - bd); } for (long int i = YSIZE(in) - 1; i >= XSIZE(in); i--) { y = i - YSIZE(in); for (long int j = 0; j < XSIZE(in); j++) { x = j; dotp = 2 * PI * (x * xshift + y * yshift); a = cos(dotp); b = sin(dotp); c = DIRECT_A2D_ELEM(in, i, j).real; d = DIRECT_A2D_ELEM(in, i, j).imag; ac = a * c; bd = b * d; ab_cd = (a + b) * (c + d); DIRECT_A2D_ELEM(out, i, j) = Complex(ac - bd, ab_cd - ac - bd); } } break; case 3: xshift = XX(shift); yshift = YY(shift); zshift = ZZ(shift); if (ABS(xshift) < XMIPP_EQUAL_ACCURACY && ABS(yshift) < XMIPP_EQUAL_ACCURACY && ABS(zshift) < XMIPP_EQUAL_ACCURACY) { out = in; return; } for (long int k = 0; k < ZSIZE(in); k++) { z = (k < XSIZE(in)) ? k : k - ZSIZE(in); for (long int i = 0; i < YSIZE(in); i++) { y = (i < XSIZE(in)) ? i : i - YSIZE(in); for (long int j = 0; j < XSIZE(in); j++) { x = j; dotp = 2 * PI * (x * xshift + y * yshift + z * zshift); a = cos(dotp); b = sin(dotp); c = DIRECT_A3D_ELEM(in, k, i, j).real; d = DIRECT_A3D_ELEM(in, k, i, j).imag; ac = a * c; bd = b * d; ab_cd = (a + b) * (c + d); DIRECT_A3D_ELEM(out, k, i, j) = Complex(ac - bd, ab_cd - ac - bd); } } } break; default: REPORT_ERROR("shiftImageInFourierTransform ERROR: dimension should be 1, 2 or 3!"); } }
void Projector::rotate2D(MultidimArray<Complex > &f2d, Matrix2D<DOUBLE> &A, bool inv) { DOUBLE fx, fy, xp, yp; int x0, x1, y0, y1, y, y2, r2; bool is_neg_x; Complex d00, d01, d10, d11, dx0, dx1; Matrix2D<DOUBLE> Ainv; // f2d should already be in the right size (ori_size,orihalfdim) // AND the points outside max_r should already be zero... // f2d.initZeros(); // Use the inverse matrix if (inv) Ainv = A; else Ainv = A.transpose(); // The f2d image may be smaller than r_max, in that case also make sure not to fill the corners! int my_r_max = XMIPP_MIN(r_max, XSIZE(f2d) - 1); // Go from the 2D slice coordinates to the map coordinates Ainv *= (DOUBLE)padding_factor; // take scaling into account directly int max_r2 = my_r_max * my_r_max; int min_r2_nn = r_min_nn * r_min_nn; #ifdef DEBUG std::cerr << " XSIZE(f2d)= "<< XSIZE(f2d) << std::endl; std::cerr << " YSIZE(f2d)= "<< YSIZE(f2d) << std::endl; std::cerr << " XSIZE(data)= "<< XSIZE(data) << std::endl; std::cerr << " YSIZE(data)= "<< YSIZE(data) << std::endl; std::cerr << " STARTINGX(data)= "<< STARTINGX(data) << std::endl; std::cerr << " STARTINGY(data)= "<< STARTINGY(data) << std::endl; std::cerr << " STARTINGZ(data)= "<< STARTINGZ(data) << std::endl; std::cerr << " max_r= "<< r_max << std::endl; std::cerr << " Ainv= " << Ainv << std::endl; #endif for (int i=0; i < YSIZE(f2d); i++) { // Don't search beyond square with side max_r if (i <= my_r_max) { y = i; } else if (i >= YSIZE(f2d) - my_r_max) { y = i - YSIZE(f2d); } else continue; y2 = y * y; for (int x=0; x <= my_r_max; x++) { // Only include points with radius < max_r (exclude points outside circle in square) r2 = x * x + y2; if (r2 > max_r2) continue; // Get logical coordinates in the 3D map xp = Ainv(0,0) * x + Ainv(0,1) * y; yp = Ainv(1,0) * x + Ainv(1,1) * y; if (interpolator == TRILINEAR || r2 < min_r2_nn) { // Only asymmetric half is stored if (xp < 0) { // Get complex conjugated hermitian symmetry pair xp = -xp; yp = -yp; is_neg_x = true; } else { is_neg_x = false; } // Trilinear interpolation (with physical coords) // Subtract STARTINGY to accelerate access to data (STARTINGX=0) // In that way use DIRECT_A3D_ELEM, rather than A3D_ELEM x0 = FLOOR(xp); fx = xp - x0; x1 = x0 + 1; y0 = FLOOR(yp); fy = yp - y0; y0 -= STARTINGY(data); y1 = y0 + 1; // Matrix access can be accelerated through pre-calculation of z0*xydim etc. d00 = DIRECT_A2D_ELEM(data, y0, x0); d01 = DIRECT_A2D_ELEM(data, y0, x1); d10 = DIRECT_A2D_ELEM(data, y1, x0); d11 = DIRECT_A2D_ELEM(data, y1, x1); // Set the interpolated value in the 2D output array #ifndef FLOAT_PRECISION __m256d __interpx = LIN_INTERP_AVX(_mm256_setr_pd(d00.real, d00.imag, d10.real, d10.imag), _mm256_setr_pd(d01.real, d01.imag, d11.real, d11.imag), _mm256_set1_pd(fx)); #else __m128 __interpx = LIN_INTERP_AVX(_mm_setr_ps(d00.real, d00.imag, d10.real, d10.imag), _mm_setr_ps(d01.real, d01.imag, d11.real, d11.imag), _mm_set1_ps(fx)); #endif Complex* interpx = (Complex*)&__interpx; DIRECT_A2D_ELEM(f2d, i, x) = LIN_INTERP(fy, interpx[0], interpx[1]); // Take complex conjugated for half with negative x if (is_neg_x) DIRECT_A2D_ELEM(f2d, i, x) = conj(DIRECT_A2D_ELEM(f2d, i, x)); } // endif TRILINEAR else if (interpolator == NEAREST_NEIGHBOUR ) { x0 = ROUND(xp); y0 = ROUND(yp); if (x0 < 0) DIRECT_A2D_ELEM(f2d, i, x) = conj(A2D_ELEM(data, -y0, -x0)); else DIRECT_A2D_ELEM(f2d, i, x) = A2D_ELEM(data, y0, x0); } // endif NEAREST_NEIGHBOUR else REPORT_ERROR("Unrecognized interpolator in Projector::project"); } // endif x-loop } // endif y-loop }
void FourierProjector::project(double rot, double tilt, double psi, const MultidimArray<double> *ctf) { double freqy, freqx; std::complex< double > f; Euler_angles2matrix(rot,tilt,psi,E); projectionFourier.initZeros(); double maxFreq2=maxFrequency*maxFrequency; int Xdim=(int)XSIZE(VfourierRealCoefs); int Ydim=(int)YSIZE(VfourierRealCoefs); int Zdim=(int)ZSIZE(VfourierRealCoefs); for (size_t i=0; i<YSIZE(projectionFourier); ++i) { FFT_IDX2DIGFREQ(i,volumeSize,freqy); double freqy2=freqy*freqy; double freqYvol_X=MAT_ELEM(E,1,0)*freqy; double freqYvol_Y=MAT_ELEM(E,1,1)*freqy; double freqYvol_Z=MAT_ELEM(E,1,2)*freqy; for (size_t j=0; j<XSIZE(projectionFourier); ++j) { // The frequency of pairs (i,j) in 2D FFT_IDX2DIGFREQ(j,volumeSize,freqx); // Do not consider pixels with high frequency if ((freqy2+freqx*freqx)>maxFreq2) continue; // Compute corresponding frequency in the volume double freqvol_X=freqYvol_X+MAT_ELEM(E,0,0)*freqx; double freqvol_Y=freqYvol_Y+MAT_ELEM(E,0,1)*freqx; double freqvol_Z=freqYvol_Z+MAT_ELEM(E,0,2)*freqx; double c,d; if (BSplineDeg==0) { // 0 order interpolation // Compute corresponding index in the volume int kVolume=(int)round(freqvol_Z*volumePaddedSize); int iVolume=(int)round(freqvol_Y*volumePaddedSize); int jVolume=(int)round(freqvol_X*volumePaddedSize); c = A3D_ELEM(VfourierRealCoefs,kVolume,iVolume,jVolume); d = A3D_ELEM(VfourierImagCoefs,kVolume,iVolume,jVolume); } else if (BSplineDeg==1) { // B-spline linear interpolation double kVolume=freqvol_Z*volumePaddedSize; double iVolume=freqvol_Y*volumePaddedSize; double jVolume=freqvol_X*volumePaddedSize; c=VfourierRealCoefs.interpolatedElement3D(jVolume,iVolume,kVolume); d=VfourierImagCoefs.interpolatedElement3D(jVolume,iVolume,kVolume); } else { // B-spline cubic interpolation double kVolume=freqvol_Z*volumePaddedSize; double iVolume=freqvol_Y*volumePaddedSize; double jVolume=freqvol_X*volumePaddedSize; // Commented for speed-up, the corresponding code is below // c=VfourierRealCoefs.interpolatedElementBSpline3D(jVolume,iVolume,kVolume); // d=VfourierImagCoefs.interpolatedElementBSpline3D(jVolume,iVolume,kVolume); // The code below is a replicate for speed reasons of interpolatedElementBSpline3D double z=kVolume; double y=iVolume; double x=jVolume; // Logical to physical z -= STARTINGZ(VfourierRealCoefs); y -= STARTINGY(VfourierRealCoefs); x -= STARTINGX(VfourierRealCoefs); int l1 = (int)ceil(x - 2); int l2 = l1 + 3; int m1 = (int)ceil(y - 2); int m2 = m1 + 3; int n1 = (int)ceil(z - 2); int n2 = n1 + 3; c = d = 0.0; double aux; for (int nn = n1; nn <= n2; nn++) { int equivalent_nn=nn; if (nn<0) equivalent_nn=-nn-1; else if (nn>=Zdim) equivalent_nn=2*Zdim-nn-1; double yxsumRe = 0.0, yxsumIm = 0.0; for (int m = m1; m <= m2; m++) { int equivalent_m=m; if (m<0) equivalent_m=-m-1; else if (m>=Ydim) equivalent_m=2*Ydim-m-1; double xsumRe = 0.0, xsumIm = 0.0; for (int l = l1; l <= l2; l++) { double xminusl = x - (double) l; int equivalent_l=l; if (l<0) equivalent_l=-l-1; else if (l>=Xdim) equivalent_l=2*Xdim-l-1; double CoeffRe = (double) DIRECT_A3D_ELEM(VfourierRealCoefs,equivalent_nn,equivalent_m,equivalent_l); double CoeffIm = (double) DIRECT_A3D_ELEM(VfourierImagCoefs,equivalent_nn,equivalent_m,equivalent_l); BSPLINE03(aux,xminusl); xsumRe += CoeffRe * aux; xsumIm += CoeffIm * aux; } double yminusm = y - (double) m; BSPLINE03(aux,yminusm); yxsumRe += xsumRe * aux; yxsumIm += xsumIm * aux; } double zminusn = z - (double) nn; BSPLINE03(aux,zminusn); c += yxsumRe * aux; d += yxsumIm * aux; } } // Phase shift to move the origin of the image to the corner double a=DIRECT_A2D_ELEM(phaseShiftImgA,i,j); double b=DIRECT_A2D_ELEM(phaseShiftImgB,i,j); if (ctf!=NULL) { double ctfij=DIRECT_A2D_ELEM(*ctf,i,j); a*=ctfij; b*=ctfij; } // Multiply Fourier coefficient in volume times phase shift double ac = a * c; double bd = b * d; double ab_cd = (a + b) * (c + d); // And store the multiplication double *ptrI_ij=(double *)&DIRECT_A2D_ELEM(projectionFourier,i,j); *ptrI_ij = ac - bd; *(ptrI_ij+1) = ab_cd - ac - bd; } } transformer2D.inverseFourierTransform(); }