/** * \file FFTFitting.cpp * \brief FFT based fitting * * Copyright 2007-2013 IMP Inventors. All rights reserved. * */ #include #include #include #include #include #include #include #include #include #include #include IMPMULTIFIT_BEGIN_NAMESPACE namespace { internal::EulerAnglesList parse_angles_file(const std::string &filename) { internal::EulerAnglesList output; typedef boost::split_iterator string_split_iterator; std::ifstream afile (filename.c_str()); if (!afile.is_open()) { IMP_THROW("problem opening angles file"< 0) { std::vector ls; boost::split(ls, line, boost::is_any_of("|")); if (ls.size() != 3) { IMP_THROW("Format error, the line should read psi|theta|phi", ValueException); } else { internal::EulerAngles rec( boost::lexical_cast(ls[0])*PI/180., boost::lexical_cast(ls[1])*PI/180., boost::lexical_cast(ls[2])*PI/180.); output.push_back(rec); } }} return output; } // clang doesn't see that these functions are used IMP_CLANG_PRAGMA(diagnostic push) IMP_CLANG_PRAGMA(diagnostic ignored "-Wunused-function") bool cmp_fit_scores_max(FittingSolutionRecord a, FittingSolutionRecord b) { return a.get_fitting_score() < b.get_fitting_score(); } bool cmp_fit_scores_min(FittingSolutionRecord a, FittingSolutionRecord b) { return a.get_fitting_score() > b.get_fitting_score(); } bool cmp_rot_scores_min(internal::RotScore a, internal::RotScore b) { return a.score_ > b.score_; } IMP_CLANG_PRAGMA(diagnostic pop) } // anonymous namespace void FFTFitting::copy_density_data(em::DensityMap *dmap,double *data_array) { for(long i=0;iget_number_of_voxels();i++) { data_array[i]=dmap->get_value(i); } } void FFTFitting::pad_resolution_map() { // add padding for FFT fftw_zero_padding_extent_[0] = ceil(nx_*fftw_pad_factor_); fftw_zero_padding_extent_[1] = ceil(ny_*fftw_pad_factor_); fftw_zero_padding_extent_[2] = ceil(nz_*fftw_pad_factor_); //copy margin for fast convolution //add half of the convolution kernel size to the padding for (int i=0;i<3;i++) { margin_ignored_in_conv_[i] = fftw_zero_padding_extent_[i]; fftw_zero_padding_extent_[i] += (filtered_kernel_ext_-1)/2; } //pad the map accordingly Pointer padded_low_res=low_map_->pad_margin( fftw_zero_padding_extent_[0], fftw_zero_padding_extent_[1], fftw_zero_padding_extent_[2]); padded_low_res->set_was_used(true); nx_=padded_low_res->get_header()->get_nx(); ny_=padded_low_res->get_header()->get_ny(); nz_=padded_low_res->get_header()->get_nz(); origx_=padded_low_res->get_origin()[0]; origy_=padded_low_res->get_origin()[1]; origz_=padded_low_res->get_origin()[2]; nvox_=nx_*ny_*nz_; // set FFTW grid sizes fftw_nvox_r2c_ = nz_*ny_*(2*(nx_/2+1)); fftw_nvox_c2r_ = nz_*ny_*(nx_/2+1); low_map_data_.resize(nvox_); copy_density_data(padded_low_res,low_map_data_); low_map_=padded_low_res; } void FFTFitting::prepare_kernels() { double sigma1d = resolution_ / (2.0*spacing_*sqrt(3.0)); unsigned ext_ga_save; boost::scoped_array phi_ga_save, phi_fx_save; double sigma_factor=0; //create Gaussian kernels, modify sigma factor arguments as necessary em::Kernel3D g1 = em::create_3d_gaussian(sigma1d,3.0); em::Kernel3D g2 = em::create_3d_gaussian(sigma1d,5.0); gauss_kernel_.reset(new double[g1.get_size()]); for(int i=0;iget_header()->get_nx(); int in_ny=in_map->get_header()->get_ny(); int in_nz=in_map->get_header()->get_nz(); em::emreal *in_data=in_map->get_data(); int minx,miny,minz,maxx,maxy,maxz; minx=in_nx-1;miny=in_ny-1;minz=in_nz-1; maxx=0;maxy=0;maxz=0; long ret_ind,in_ind; for (int iz=0;iz0) { if (ix<=minx) minx=ix; if (ix>=maxx) maxx=ix; if (iy<=miny) miny=iy; if (iy>=maxy) maxy=iy; if (iz<=minz) minz=iz; if (iz>=maxz) maxz=iz; } } int margin[6]; margin[0]=minx; margin[1]=in_nx-maxx-1; margin[2]=miny; margin[3]=in_ny-maxy-1; margin[4]=minz; margin[5]=in_nz-maxz-1; // compute new grid size int ret_nx=in_nx-(margin[0]+margin[1]); int ret_ny=in_ny-(margin[2]+margin[3]); int ret_nz=in_nz-(margin[4]+margin[5]); // make extent odd if (2*(ret_nx/2)==ret_nx) { ret_nx++; if (margin[0]>0)margin[0]--;} if (2*(ret_ny/2)==ret_ny) { ret_ny++; if (margin[2]>0)margin[2]--;} if (2*(ret_nz/2)==ret_nz) { ret_nz++; if (margin[4]>0)margin[4]--;} em::DensityMap *ret= em::create_density_map( ret_nx,ret_ny,ret_nz,in_map->get_header()->get_spacing()); ret->set_was_used(true); ret->set_origin(in_map->get_origin()+ in_map->get_spacing()* algebra::Vector3D(margin[0],margin[2],margin[4])); //copy data em::emreal *ret_data=ret->get_data(); for (int iz=margin[4];iz=(2*PI-max_angle_sampling_rad)))&& ((rots_all[i].theta<=max_angle_sampling_rad)|| (rots_all[i].theta>=(PI-max_angle_sampling_rad)))&& ((rots_all[i].phi<=max_angle_sampling_rad)|| (rots_all[i].phi>=(2*PI-max_angle_sampling_rad)))){ // std::cout<<"ACCEPTED"<get_header()->get_resolution(); rots_=rots; num_fits_reported_=num_fits_to_report; //----------- TODO FIX THAT, should be in the parameters low_cutoff_=density_threshold; if (resolution_ >= 10) corr_mode_=1;//1-laplacian else corr_mode_=0; //TODO - do not use lap // corr_mode_=0; if (corr_mode_==0) fftw_pad_factor_=0.1; else fftw_pad_factor_=0.2; //---------------------------- orig_cen_=core::get_centroid(core::XYZs(core::get_leaves(mol2fit))); std::cout<<"orig_cen_:"<get_header())); sampled_map_->set_was_used(true); ParticlesTemp mol_ps=core::get_leaves(orig_mol_); IMP_LOG_TERSE("Projecting probe structure to lattice \n"); sampled_map_->reset_data(); sampled_map_->project(core::get_leaves(orig_mol_), margin_ignored_in_conv_[0], margin_ignored_in_conv_[1], margin_ignored_in_conv_[2], map_cen_-core::get_centroid(core::XYZs(mol_ps))); IMP_LOG_TERSE("Applying filters to target and probe maps\n"); switch (corr_mode_) { case 0: low_map_->convolute_kernel(kernel_filter_.get(), kernel_filter_ext_); break; case 1: internal::relax_laplacian(low_map_,fftw_zero_padding_extent_,5.); internal::convolve_kernel_inside_erode(low_map_, kernel_filter_.get(), kernel_filter_ext_); break; } sampled_map_->convolute_kernel(filtered_kernel_.get(), filtered_kernel_ext_); sampled_norm_ = sampled_map_->calcRMS(); asmb_norm_ = low_map_->calcRMS(); sampled_map_->multiply(1./sampled_norm_); low_map_->multiply(1./asmb_norm_); //create plan for low res map fftw_plan_forward_lo_ = fftw_plan_dft_r2c_3d( nz_, ny_, nx_, low_map_data_, fftw_grid_lo_,FFTW_MEASURE); copy_density_data(low_map_,low_map_data_); //do the actual fitting //init results hash fits_hash_.insert(fits_hash_.end(),nvox_, internal::RotScores()); for (unsigned int m=0;mbest_fits_=final_fits_pruned; ret->best_trans_per_rot_=best_trans_per_rot_log_; return ret.release(); } void FFTFitting::fftw_translational_search( const multifit::internal::EulerAngles &rot, int rot_ind) { //save original coordinates of the copy mol ParticlesTemp temp_ps=core::get_leaves(copy_mol_); algebra::Vector3Ds origs(temp_ps.size()); for(unsigned int i=0;ireset_data(0.); sampled_map_->project( temp_ps, margin_ignored_in_conv_[0], margin_ignored_in_conv_[1], margin_ignored_in_conv_[2], map_cen_-core::get_centroid(core::XYZs(mol_ps))); sampled_map_->convolute_kernel(filtered_kernel_.get(), filtered_kernel_ext_); sampled_map_->multiply(1./(sampled_norm_*nvox_)); // FFT the molecule copy_density_data(sampled_map_,fftw_r_grid_mol_); fftw_execute(fftw_plan_forward_hi_.get()); // IFFT(molxEM*) double save_b_re; for (unsigned int i=0;istatic_cast < unsigned int>(num_angle_per_voxel_)) { std::pop_heap(fits_hash_[pos_ind].begin(), fits_hash_[pos_ind].end(),cmp_rot_scores_min); fits_hash_[pos_ind].pop_back(); } if (curr_score>max_score) { grid_ind[0]=fft_scores_flipped_[i].ix; grid_ind[1]=fft_scores_flipped_[i].iy; grid_ind[2]=fft_scores_flipped_[i].iz; max_score=curr_score; /* std::cout<<"curr max "<< rot.psi*180/PI<< " "<set_was_used(true); //adjust spacing double cut_width; double new_width; spacing_ = dmap->get_spacing(); /* if spacing is too wide adjust resolution */ if (spacing_ > resolution_ * 0.7) { resolution_ = 2.0 * spacing_; IMP_LOG_TERSE( "Target resolution adjusted to 2x voxel spacing "<set_was_used(true); spacing_ = new_width; } low_map_=em::get_threshold_map(low_map_,low_cutoff_); low_map_->set_was_used(true); // crop non-zero density low_map_ = crop_margin(low_map_); low_map_->set_was_used(true); spacing_=low_map_->get_spacing(); origz_=low_map_->get_origin()[2]; origy_=low_map_->get_origin()[1]; origx_=low_map_->get_origin()[0]; nz_=low_map_->get_header()->get_nz(); ny_=low_map_->get_header()->get_ny(); nx_=low_map_->get_header()->get_nx(); nvox_ = nx_*ny_*nz_; low_map_->get_header_writable()->set_resolution(resolution_); low_map_data_.resize(nvox_); copy_density_data(low_map_,low_map_data_); } void FFTFitting::prepare_probe (atom::Hierarchy mol2fit) { algebra::Vector3D cen; IMP_LOG_TERSE("read protein\n"); // read molecule to fit IMP_INTERNAL_CHECK(atom::get_leaves(mol2fit).size()>0, "No atoms to fit \n"); orig_mol_=mol2fit; orig_mol_copy_=atom::create_clone(mol2fit);//for final solutions orig_rb_=core::RigidMember(atom::get_leaves(mol2fit)[0]).get_rigid_body(); cen=core::get_centroid(core::XYZs(core::get_leaves(orig_mol_))); // center protein cen_trans_=algebra::Transformation3D( algebra::get_identity_rotation_3d(),-cen); core::transform(orig_rb_,cen_trans_); copy_mol_=atom::create_clone(mol2fit); } multifit::FittingSolutionRecords FFTFitting::detect_top_fits( const internal::RotScoresVec &ccr, bool cluster_fits, double max_translation, double max_clustering_trans, double max_clustering_rotation) { max_clustering_rotation = max_clustering_rotation*PI/180.; std::cout<<"max translation: "<< max_translation<max_translation) continue; new_rec.set_fit_transformation( algebra::Transformation3D( algebra::get_identity_rotation_3d(),vec)); new_rec.set_dock_transformation( algebra::Transformation3D( algebra::get_identity_rotation_3d(), algebra::Vector3D( rots_[euler_index].psi, rots_[euler_index].theta, rots_[euler_index].phi))); /*std::cout<<"adding peak: "; new_rec.show(); std::cout<static_cast(num_fits_reported_)) { while (max_peaks.size()>static_cast(num_fits_reported_)) { IMP_INTERNAL_CHECK(max_peaks[0].get_fitting_score() <= max_peaks[1].get_fitting_score(), "PROBLEM IN MAX_PEAKS"); std::pop_heap(max_peaks.begin(),max_peaks.end(),cmp_fit_scores_min); max_peaks.pop_back(); } } }} std::sort_heap(max_peaks.begin(),max_peaks.end(),cmp_fit_scores_min); //std::cout<<"==============2===top first score:"<< //max_peaks[0].get_fitting_score(); //std::cout<<" "< gpeak = em::create_density_map(nx_+2, ny_+2, nz_+2,spacing_); gpeak->set_was_used(true); gpeak->reset_data(0.); em::emreal *gpeak_data = gpeak->get_data(); long box_ind; for (unsigned long i=0;icurr_cc) { curr_cc=ccr[wind][jj].score_; } } if (curr_cc>-9999.) for (int zz=-1;zz<2;zz++) for (int yy=-1;yy<2;yy++) for (int xx=-1;xx<2;xx++) { box_ind=(wx+xx+1)+(nx_+2)*((wy+yy+1)+(ny_+2)*(wz+zz+1)); gpeak_data[box_ind]+=smooth_filter[xx+1][yy+1][zz+1]*curr_cc; }} Pointer lpeak = em::create_density_map(nx_+2, ny_+2, nz_+2,spacing_); lpeak->set_was_used(true); lpeak->reset_data(0.); em::emreal *lpeak_data = lpeak->get_data(); //laplacian gpeak // std::cout<<"==============3===top"< filter_max) filter_max = curr_max; curr_msd+=curr_max*curr_max; } // std::cout<<"==============4===top"<filter_max*0.25f) search_cut = filter_max*0.25f; for (unsigned long i=0;i search_cut) peak_count++; } // std::cout<<"Contrast threshold: "< search_cut) { wind=(wx)+(nx_)*((wy)+(ny_)*(wz)); for(unsigned jj=0;jj-999.) { int euler_index=ccr[wind][jj].rot_ind_; algebra::Vector3D peak_vec= algebra::Vector3D( spacing_*nx_half_-spacing_*wx, spacing_*ny_half_-spacing_*wy, spacing_*nz_half_-spacing_*wz); if (algebra::get_distance(peak_vec+map_cen_,orig_cen_)> max_translation) continue; found_peak.push_back(FittingSolutionRecord()); found_peak[peak_count].set_fitting_score(ccr[wind][jj].score_); found_peak[peak_count].set_fit_transformation( algebra::Transformation3D( algebra::get_identity_rotation_3d(),peak_vec)); found_peak[peak_count].set_dock_transformation( algebra::Transformation3D( algebra::get_identity_rotation_3d(), algebra::Vector3D( rots_[euler_index].psi, rots_[euler_index].theta, rots_[euler_index].phi))); peak_count++; }} float scale=30.; // std::cout<<"==============5===top"<scale*num_fits_reported_){//todo - make a parameter std::sort(found_peak.begin(),found_peak.end(),cmp_fit_scores_min); found_peak.erase(found_peak.begin()+num_fits_reported_*scale*0.9, found_peak.end()); peak_count = found_peak.size(); } // std::cout<<"==============6===top"<(nullptr); gpeak=static_cast(nullptr); }//end cluster //add the num_fits_reported_ saved maximum scoring peaks std::cout<<"number of max peaks:"<(max_peaks.size())); ++i) { found_peak.push_back(max_peaks[i]); } peak_count=found_peak.size(); // Sort the extracted peaks as a function of CC std::sort(found_peak.begin(),found_peak.end(),cmp_fit_scores_min); /* for (int i=0;ifound_peak[i].get_fitting_score()){ multifit::FittingSolutionRecord temp = found_peak[i]; found_peak[i]=found_peak[j]; found_peak[j]=temp; } */ int peak_count_all=peak_count; // Eliminate redundant peaks that have both similar //position and orientation double pos_diff; for (int i=0;i-99.0) { found_peak[peak_count]=found_peak[i]; peak_count++; } } IMP_LOG_TERSE("Found "< mask_inside2 = em::get_binarized_interior(dmap); em::emreal* mdata2 = mask_inside2->get_data(); inside_num_flipped_=0; for(long i=0;iget_number_of_voxels();i++) { if (mdata2[i]>0.9) { inside_num_flipped_+=1; } } //flip mask Pointer mask_inside3 = em::create_density_map(mask_inside2); mask_inside3->set_was_used(true); em::emreal *mdata3 = mask_inside3->get_data(); mask_inside3->reset_data(0.); for (unsigned int iz=0;iz(nullptr); fft_scores_flipped_.clear(); fft_scores_flipped_.insert(fft_scores_.end(),inside_num_flipped_, internal::FFTScore()); //set position list int curr=0; unsigned long wind,ind; int ix,iy,iz; for (unsigned int wz=0;wz(nullptr); } //! get the unwrapped index /** The convolution result is in a wrapped around order, which indicates the translation to apply Wrapped around: (0,1,2,.,N,-N,..-2, -1) The function returns the index of the centroid after applying the displacement indicated by the convolution */ //Given indexes in wrapped order (result of FFTW), return //the unwrapped indexes /* \param[in] wx wrapped index in X dimension \param[in] wy wrapped index in Y dimension \param[in] wz wrapped index in Z dimension \param[out] x unwrapped index in X dimension \param[out] y unwrapped index in Y dimension \param[out] z unwrapped index in Z dimension **/ void FFTFitting::get_unwrapped_index ( int wx, int wy, int wz, int &x, int &y, int &z) { int x_shift = nx_half_+1; int y_shift = ny_half_+1; int z_shift = nz_half_+1; if (wx mask_inside2 = em::get_binarized_interior(dmap); em::emreal* mdata2 = mask_inside2->get_data(); inside_num_=0; for(long i=0;iget_number_of_voxels();i++) { if (mdata2[i]>0.9) { inside_num_+=1; } } fft_scores_.clear(); fft_scores_.insert(fft_scores_.end(),inside_num_, internal::FFTScore()); //set position list unsigned int curr=0; unsigned long wind,ind; int ix,iy,iz; for (unsigned int wz=0;wz fits = ff->do_global_fitting(dmap,density_threshold,mol2fit, angle_sampling_interval, number_of_fits_to_report, max_clustering_translation,max_clustering_angle); return fits->best_fits_; } IMPMULTIFIT_END_NAMESPACE