/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ < BioEM software for Bayesian inference of Electron Microscopy images> Copyright (C) 2014 Pilar Cossio, David Rohr and Gerhard Hummer. Max Planck Institute of Biophysics, Frankfurt, Germany. See license statement for terms of distribution. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #include #define MPI_CHK(expr) \ if (expr != MPI_SUCCESS) \ { \ fprintf(stderr, "Error in MPI function %s: %d\n", __FILE__, __LINE__); \ } #include #include #include #include #include #include #include #include #include #ifdef WITH_OPENMP #include #endif #include #include #include "cmodules/timer.h" #include "param.h" #include "bioem.h" #include "model.h" #include "map.h" #include "MersenneTwister.h" #ifdef BIOEM_USE_NVTX #include "nvToolsExt.h" const uint32_t colors[] = { 0x0000ff00, 0x000000ff, 0x00ffff00, 0x00ff00ff, 0x0000ffff, 0x00ff0000, 0x00ffffff }; const int num_colors = sizeof(colors)/sizeof(colors[0]); #define cuda_custom_timeslot(name,cid) { \ int color_id = cid; \ color_id = color_id%num_colors; \ nvtxEventAttributes_t eventAttrib = {0}; \ eventAttrib.version = NVTX_VERSION; \ eventAttrib.size = NVTX_EVENT_ATTRIB_STRUCT_SIZE; \ eventAttrib.colorType = NVTX_COLOR_ARGB; \ eventAttrib.color = colors[color_id]; \ eventAttrib.messageType = NVTX_MESSAGE_TYPE_ASCII; \ eventAttrib.message.ascii = name; \ nvtxRangePushEx(&eventAttrib); \ } #define cuda_custom_timeslot_end nvtxRangePop(); #else #define cuda_custom_timeslot(name,cid) #define cuda_custom_timeslot_end #endif #include "bioem_algorithm.h" using namespace boost; namespace po = boost::program_options; using namespace std; /* For dvl nodes in hydra with problem in boost namespace std { typedef decltype(nullptr) nullptr_t; }*/ // A helper function of Boost template ostream& operator<<(ostream& os, const vector& v) { copy(v.begin(), v.end(), ostream_iterator(os, " ")); return os; } bioem::bioem() { FFTAlgo = getenv("FFTALGO") == NULL ? 1 : atoi(getenv("FFTALGO")); DebugOutput = getenv("BIOEM_DEBUG_OUTPUT") == NULL ? 2 : atoi(getenv("BIOEM_DEBUG_OUTPUT")); nProjectionsAtOnce = getenv("BIOEM_PROJECTIONS_AT_ONCE") == NULL ? 1 : atoi(getenv("BIOEM_PROJECTIONS_AT_ONCE")); } bioem::~bioem() { } int bioem::configure(int ac, char* av[]) { // ************************************************************************************** // **** Configuration Routine using boost for extracting parameters, models and maps **** // ************************************************************************************** // ****** And Precalculating necessary grids, map crosscorrelations and kernels ******** // ************************************************************************************* HighResTimer timer; if (mpi_rank == 0) { // *** Inizialzing default variables *** std::string infile, modelfile, mapfile,Inputanglefile,Inputbestmap; Model.readPDB = false; param.param_device.writeAngles = false; param.dumpMap = false; param.loadMap = false; RefMap.readMRC = false; RefMap.readMultMRC = false; param.notuniformangles=false; // ************************************************************************************* cout << " ++++++++++++ FROM COMMAND LINE +++++++++++\n\n"; // ************************************************************************************* // ********************* Command line reading input with BOOST ************************ try { po::options_description desc("Command line inputs"); desc.add_options() ("Modelfile", po::value< std::string>() , "(Mandatory) Name of model file") ("Particlesfile", po::value< std::string>(), "if BioEM (Mandatory) Name of paricles file") ("Inputfile", po::value(), "if BioEM (Mandatory) Name of input parameter file") ("PrintBestCalMap", po::value< std::string>(), "(Optional) Only print best calculated map (file nec.). NO BioEM (!)") ("ReadEulerAngles", po::value< std::string>(), "(Optional) Read Euler angle list instead of uniform grid (file nec.)") ("ReadPDB", "(Optional) If reading model file in PDB format") ("ReadMRC", "(Optional) If reading particle file in MRC format") ("ReadMultipleMRC", "(Optional) If reading Multiple MRCs") ("DumpMaps", "(Optional) Dump maps after they were red from maps file") ("LoadMapDump", "(Optional) Read Maps from dump instead of maps file") ("help", "(Optional) Produce help message") ; po::positional_options_description p; p.add("Inputfile", -1); p.add("Modelfile", -1); p.add("Particlesfile", -1); p.add("ReadPDB", -1); p.add("ReadMRC", -1); p.add("ReadMultipleMRC", -1); p.add("ReadEulerAngles",-1); p.add("PrintBestCalMap",-1); p.add("DumpMaps", -1); p.add("LoadMapDump", -1); po::variables_map vm; po::store(po::command_line_parser(ac, av). options(desc).positional(p).run(), vm); po::notify(vm); if((ac < 4)) { std::cout << desc << std::endl; return 1; } if (vm.count("help")) { cout << "Usage: options_description [options]\n"; cout << desc; return 1; } if (vm.count("Inputfile")) { cout << "Input file is: "; cout << vm["Inputfile"].as< std::string >() << "\n"; infile = vm["Inputfile"].as< std::string >(); } if (vm.count("Modelfile")) { cout << "Model file is: " << vm["Modelfile"].as< std::string >() << "\n"; modelfile = vm["Modelfile"].as< std::string >(); } if (vm.count("ReadPDB")) { cout << "Reading model file in PDB format.\n"; Model.readPDB = true; } if (vm.count("ReadEulerAngles")) { cout << "Reading Euler Angles from file: " << vm["ReadEulerAngles"].as< std::string >() << "\n"; cout << "Note: Format should be alpha (12.6f) beta (12.6f) gamma (12.6f)\n"; Inputanglefile = vm["ReadEulerAngles"].as< std::string >(); param.notuniformangles=true; } if (vm.count("PrintBestCalMap")) { cout << "Reading Euler Angles from file: " << vm["PrintBestCalMap"].as< std::string >() << "\n"; Inputbestmap = vm["PrintBestCalMap"].as< std::string >(); param.printModel=true; } if (vm.count("ReadMRC")) { cout << "Reading particle file in MRC format.\n"; RefMap.readMRC=true; } if (vm.count("ReadMultipleMRC")) { cout << "Reading Multiple MRCs.\n"; RefMap.readMultMRC=true; } if (vm.count("DumpMaps")) { cout << "Dumping Maps after reading from file.\n"; param.dumpMap = true; } if (vm.count("LoadMapDump")) { cout << "Loading Map dump.\n"; param.loadMap = true; } if (vm.count("Particlesfile")) { cout << "Paricle file is: " << vm["Particlesfile"].as< std::string >() << "\n"; mapfile = vm["Particlesfile"].as< std::string >(); } } catch(std::exception& e) { cout << e.what() << "\n"; return 1; } //check for consitency in multiple MRCs if(RefMap.readMultMRC && not(RefMap.readMRC)) { cout << "For Multiple MRCs command --ReadMRC is necesary too"; exit(1); } if(!Model.readPDB){ cout << "Note: Reading model in simple text format (not PDB)\n"; cout << "---- x y z radius density ------- \n"; } if (DebugOutput >= 2 && mpi_rank == 0) timer.ResetStart(); // ********************* Reading Parameter Input *************************** if(!param.printModel){ // Standard definition for BioEM param.readParameters(infile.c_str(),Inputanglefile.c_str()); // ********************* Reading Particle Maps Input ********************** RefMap.readRefMaps(param, mapfile.c_str()); } else{ // Reading parameters for only writting down Best projection param.forprintBest(Inputbestmap.c_str()); } // ********************* Reading Model Input ****************************** Model.readModel(modelfile.c_str()); cout << "Remark: look at file COORDREAD to confirm that the Model coordinates are correct\n"; if (DebugOutput >= 2 && mpi_rank == 0) printf("Reading Input Data %f\n", timer.GetCurrentElapsedTime()); if(param.param_device.writeCC && mpi_size>1){ cout << "Exiting::: WRITE CROSS-CORRELATION ONLY VAILD FOR 1 MPI PROCESS\n"; exit(1); } } #ifdef WITH_MPI if (mpi_size > 1) { if (DebugOutput >= 2 && mpi_rank == 0) timer.ResetStart(); MPI_Bcast(¶m, sizeof(param), MPI_BYTE, 0, MPI_COMM_WORLD); //refCtf, CtfParam, angles automatically filled by precalculare function below MPI_Bcast(&Model, sizeof(Model), MPI_BYTE, 0, MPI_COMM_WORLD); if (mpi_rank != 0) Model.points = (bioem_model::bioem_model_point*) mallocchk(sizeof(bioem_model::bioem_model_point) * Model.nPointsModel); MPI_Bcast(Model.points, sizeof(bioem_model::bioem_model_point) * Model.nPointsModel, MPI_BYTE, 0, MPI_COMM_WORLD); MPI_Bcast(&RefMap, sizeof(RefMap), MPI_BYTE, 0, MPI_COMM_WORLD); if (mpi_rank != 0) RefMap.maps = (myfloat_t*) mallocchk(RefMap.refMapSize * sizeof(myfloat_t) * RefMap.ntotRefMap); MPI_Bcast(RefMap.maps, RefMap.refMapSize * sizeof(myfloat_t) * RefMap.ntotRefMap, MPI_BYTE, 0, MPI_COMM_WORLD); if (DebugOutput >= 2 && mpi_rank == 0) printf("MPI Broadcast of Input Data %f\n", timer.GetCurrentElapsedTime()); } #endif // ****************** Precalculating Necessary Stuff ********************* if (DebugOutput >= 2 && mpi_rank == 0) timer.ResetStart(); param.PrepareFFTs(); if (DebugOutput >= 2 && mpi_rank == 0) { printf("Time Prepare FFTs %f\n", timer.GetCurrentElapsedTime()); timer.ResetStart(); } precalculate(); if (getenv("BIOEM_DEBUG_BREAK")) { const int cut = atoi(getenv("BIOEM_DEBUG_BREAK")); if (param.nTotGridAngles > cut) param.nTotGridAngles = cut; if (param.nTotCTFs > cut) param.nTotCTFs = cut; } if (DebugOutput >= 2 && mpi_rank == 0) { printf("Time Precalculate %f\n", timer.GetCurrentElapsedTime()); timer.ResetStart(); } if(!param.printModel)pProb.init(RefMap.ntotRefMap, param.nTotGridAngles, param.nTotCC, *this); if (DebugOutput >= 2 && mpi_rank == 0) { printf("Time Init Probabilities %f\n", timer.GetCurrentElapsedTime()); timer.ResetStart(); } deviceInit(); if (DebugOutput >= 2 && mpi_rank == 0) printf("Time Device Init %f\n", timer.GetCurrentElapsedTime()); return(0); } void bioem::cleanup() { //Deleting allocated pointers free_device_host(pProb.ptr); RefMap.freePointers(); } int bioem::precalculate() { // ************************************************************************************** // **Precalculating Routine of Orientation grids, Map crosscorrelations and CTF Kernels** // ************************************************************************************** HighResTimer timer; // Generating Grids of orientations param.CalculateGridsParam(); if (DebugOutput >= 3) { printf("\tTime Precalculate Grids Param: %f\n", timer.GetCurrentElapsedTime()); timer.ResetStart(); } // Precalculating CTF Kernels stored in class Param param.CalculateRefCTF(); if (DebugOutput >= 3) { printf("\tTime Precalculate CTFs: %f\n", timer.GetCurrentElapsedTime()); timer.ResetStart(); } //Precalculate Maps if(!param.printModel) RefMap.precalculate(param, *this); if (DebugOutput >= 3) printf("\tTime Precalculate Maps: %f\n", timer.GetCurrentElapsedTime()); return(0); } int bioem::run() { // ************************************************************************************** // ********** Secondary routine for printing out the only best projection *************** // ************************************************************************************** if(mpi_rank == 0 && param.printModel){ //Only works for 1 MPI process (not parallelized) cout << "\nAnalysis for printing best projection::: \n \n" ; mycomplex_t* proj_mapsFFT; myfloat_t* conv_map = NULL; mycomplex_t* conv_mapFFT; myfloat_t sumCONV, sumsquareCONV; proj_mapsFFT = (mycomplex_t *) myfftw_malloc(sizeof(mycomplex_t) * param.param_device.NumberPixels * param.param_device.NumberFFTPixels1D); conv_mapFFT = (mycomplex_t *) myfftw_malloc(sizeof(mycomplex_t) * param.param_device.NumberPixels * param.param_device.NumberFFTPixels1D); conv_map = (myfloat_t*) myfftw_malloc(sizeof(myfloat_t) * param.param_device.NumberPixels * param.param_device.NumberPixels); cout << "...... Calculating Projection .......................\n " ; createProjection(0, proj_mapsFFT); cout << "...... Calculating Convolution .......................\n " ; createConvolutedProjectionMap(0, 0, proj_mapsFFT, conv_map, conv_mapFFT, sumCONV, sumsquareCONV); } // ************************************************************************************** // **** Main BioEM routine, projects, convolutes and compares with Map using OpenMP **** // ************************************************************************************** // **** If we want to control the number of threads -> omp_set_num_threads(XX); ****** // ****************** Declarying class of Probability Pointer ************************* if (mpi_rank == 0) printf("\tInitializing Probabilities\n"); // Inizialzing Probabilites to zero and constant to -Infinity for (int iRefMap = 0; iRefMap < RefMap.ntotRefMap; iRefMap ++) { bioem_Probability_map& pProbMap = pProb.getProbMap(iRefMap); pProbMap.Total = 0.0; pProbMap.Constoadd = -FLT_MAX; //Problem if using double presicion if (param.param_device.writeAngles) { for (int iOrient = 0; iOrient < param.nTotGridAngles; iOrient ++) { bioem_Probability_angle& pProbAngle = pProb.getProbAngle(iRefMap, iOrient); pProbAngle.forAngles = 0.0; pProbAngle.ConstAngle = -FLT_MAX; } } if (param.param_device.writeCC) { int cc=0; for (int cent_x = 0; cent_x < param.param_device.NumberPixels; cent_x = cent_x + param.param_device.CCdisplace) { for (int cent_y = 0; cent_y < param.param_device.NumberPixels; cent_y = cent_y + param.param_device.CCdisplace) { bioem_Probability_cc& pProbCC = pProb.getProbCC(iRefMap, cc); //Debuggin:: cout << iRefMap << " " << cc << " " << cent_x << " " << cent_y << "\n"; if(!param.param_device.CCwithBayes) { pProbCC.forCC=-FLT_MAX; }else { pProbCC.forCC = 0.0; pProbCC.ConstCC=-FLT_MAX; } cc++; } } } } // ************************************************************************************** deviceStartRun(); // ******************************** MAIN CYCLE ****************************************** mycomplex_t* proj_mapsFFT; myfloat_t* conv_map = NULL; mycomplex_t* conv_mapFFT; myfloat_t sumCONV, sumsquareCONV; //allocating fftw_complex vector const int ProjMapSize = (param.FFTMapSize + 64) & ~63; //Make sure this is properly aligned for fftw..., Actually this should be ensureb by using FFTMapSize, but it is not due to a bug in CUFFT which cannot handle padding properly proj_mapsFFT = (mycomplex_t *) myfftw_malloc(sizeof(mycomplex_t) * ProjMapSize * nProjectionsAtOnce); conv_mapFFT = (mycomplex_t *) myfftw_malloc(sizeof(mycomplex_t) * param.param_device.NumberPixels * param.param_device.NumberFFTPixels1D); if (!FFTAlgo) conv_map = (myfloat_t*) myfftw_malloc(sizeof(myfloat_t) * param.param_device.NumberPixels * param.param_device.NumberPixels); HighResTimer timer, timer2; if (DebugOutput >= 1 && mpi_rank == 0) printf("\tMain Loop GridAngles %d, CTFs %d, RefMaps %d, Shifts (%d/%d)², Pixels %d², OMP Threads %d, MPI Ranks %d\n", param.nTotGridAngles, param.nTotCTFs, RefMap.ntotRefMap, 2 * param.param_device.maxDisplaceCenter + param.param_device.GridSpaceCenter, param.param_device.GridSpaceCenter, param.param_device.NumberPixels, omp_get_max_threads(), mpi_size); const int iOrientStart = (int) ((long long int) mpi_rank * param.nTotGridAngles / mpi_size); int iOrientEnd = (int) ((long long int) (mpi_rank + 1) * param.nTotGridAngles / mpi_size); if (iOrientEnd > param.nTotGridAngles) iOrientEnd = param.nTotGridAngles; for (int iOrientAtOnce = iOrientStart; iOrientAtOnce < iOrientEnd; iOrientAtOnce += nProjectionsAtOnce) { // *************************************************************************************** // ***** Creating Projection for given orientation and transforming to Fourier space ***** if (DebugOutput >= 1) timer2.ResetStart(); if (DebugOutput >= 2) timer.ResetStart(); int iTmpEnd = std::min(iOrientEnd, iOrientAtOnce + nProjectionsAtOnce); #pragma omp parallel for for (int iOrient = iOrientAtOnce; iOrient < iTmpEnd;iOrient++) { createProjection(iOrient, &proj_mapsFFT[(iOrient - iOrientAtOnce) * ProjMapSize]); } if (DebugOutput >= 2) printf("\tTime Projection %d: %f (rank %d)\n", iOrientAtOnce, timer.GetCurrentElapsedTime(), mpi_rank); for (int iOrient = iOrientAtOnce; iOrient < iTmpEnd;iOrient++) { mycomplex_t* proj_mapFFT = &proj_mapsFFT[(iOrient - iOrientAtOnce) * ProjMapSize]; // *************************************************************************************** // ***** **** Internal Loop over convolutions **** ***** for (int iConv = 0; iConv < param.nTotCTFs; iConv++) { // *** Calculating convolutions of projection map and crosscorrelations *** if (DebugOutput >= 2) timer.ResetStart(); createConvolutedProjectionMap(iOrient, iConv, proj_mapFFT, conv_map, conv_mapFFT, sumCONV, sumsquareCONV); if (DebugOutput >= 2) printf("\t\tTime Convolution %d %d: %f (rank %d)\n", iOrient, iConv, timer.GetCurrentElapsedTime(), mpi_rank); // *************************************************************************************** // *** Comparing each calculated convoluted map with all experimental maps *** if (DebugOutput >= 2) timer.ResetStart(); compareRefMaps(iOrient, iConv, conv_map, conv_mapFFT, sumCONV, sumsquareCONV); if (DebugOutput >= 2) { const double compTime = timer.GetCurrentElapsedTime(); const int nShifts = 2 * param.param_device.maxDisplaceCenter / param.param_device.GridSpaceCenter + 1; const double nFlops = (double) RefMap.ntotRefMap * (double) nShifts * (double) nShifts * (((double) param.param_device.NumberPixels - (double) param.param_device.maxDisplaceCenter / 2.) * ((double) param.param_device.NumberPixels - (double) param.param_device.maxDisplaceCenter / 2.) * 5. + 25.) / compTime; const double nGBs = (double) RefMap.ntotRefMap * (double) nShifts * (double) nShifts * (((double) param.param_device.NumberPixels - (double) param.param_device.maxDisplaceCenter / 2.) * ((double) param.param_device.NumberPixels - (double) param.param_device.maxDisplaceCenter / 2.) * 2. + 8.) * (double) sizeof(myfloat_t) / compTime; const double nGBs2 = (double) RefMap.ntotRefMap * ((double) param.param_device.NumberPixels * (double) param.param_device.NumberPixels + 8.) * (double) sizeof(myfloat_t) / compTime; printf("\t\tTime Comparison %d %d: %f sec (%f GFlops, %f GB/s (cached), %f GB/s) (rank %d)\n", iOrient, iConv, compTime, nFlops / 1000000000., nGBs / 1000000000., nGBs2 / 1000000000., mpi_rank); } } if (DebugOutput >= 1) { printf("\tTotal time for projection %d: %f (rank %d)\n", iOrient, timer2.GetCurrentElapsedTime(), mpi_rank); timer2.ResetStart(); } } } //deallocating fftw_complex vector myfftw_free(proj_mapsFFT); myfftw_free(conv_mapFFT); if (!FFTAlgo) myfftw_free(conv_map); deviceFinishRun(); // ************* Writing Out Probabilities *************** // *** Angular Probability *** #ifdef WITH_MPI if (mpi_size > 1) { if (DebugOutput >= 1 && mpi_rank == 0) timer.ResetStart(); //Reduce Constant and summarize probabilities { myfloat_t* tmp1 = new myfloat_t[RefMap.ntotRefMap]; myfloat_t* tmp2 = new myfloat_t[RefMap.ntotRefMap]; myfloat_t* tmp3 = new myfloat_t[RefMap.ntotRefMap]; for (int i = 0;i < RefMap.ntotRefMap;i++) { tmp1[i] = pProb.getProbMap(i).Constoadd; } MPI_Allreduce(tmp1, tmp2, RefMap.ntotRefMap, MY_MPI_FLOAT, MPI_MAX, MPI_COMM_WORLD); for (int i = 0;i < RefMap.ntotRefMap;i++) { bioem_Probability_map& pProbMap = pProb.getProbMap(i); tmp1[i] = pProbMap.Total * exp(pProbMap.Constoadd - tmp2[i]); } MPI_Reduce(tmp1, tmp3, RefMap.ntotRefMap, MY_MPI_FLOAT, MPI_SUM, 0, MPI_COMM_WORLD); //Find MaxProb MPI_Status mpistatus; { int* tmpi1 = new int[RefMap.ntotRefMap]; int* tmpi2 = new int[RefMap.ntotRefMap]; for (int i = 0;i < RefMap.ntotRefMap;i++) { bioem_Probability_map& pProbMap = pProb.getProbMap(i); tmpi1[i] = tmp2[i] <= pProbMap.Constoadd ? mpi_rank : -1; } MPI_Allreduce(tmpi1, tmpi2, RefMap.ntotRefMap, MPI_INT, MPI_MAX, MPI_COMM_WORLD); for (int i = 0;i < RefMap.ntotRefMap;i++) { if (tmpi2[i] == -1) { if (mpi_rank == 0) printf("Error: Could not find highest probability\n"); } else if (tmpi2[i] != 0) //Skip if rank 0 already has highest probability { if (mpi_rank == 0) { MPI_Recv(&pProb.getProbMap(i).max, sizeof(pProb.getProbMap(i).max), MPI_BYTE, tmpi2[i], i, MPI_COMM_WORLD, &mpistatus); } else if (mpi_rank == tmpi2[i]) { MPI_Send(&pProb.getProbMap(i).max, sizeof(pProb.getProbMap(i).max), MPI_BYTE, 0, i, MPI_COMM_WORLD); } } } delete[] tmpi1; delete[] tmpi2; } if (mpi_rank == 0) { for (int i = 0;i < RefMap.ntotRefMap;i++) { bioem_Probability_map& pProbMap = pProb.getProbMap(i); pProbMap.Total = tmp3[i]; pProbMap.Constoadd = tmp2[i]; } } delete[] tmp1; delete[] tmp2; delete[] tmp3; if (DebugOutput >= 1 && mpi_rank == 0 && mpi_size > 1) printf("Time MPI Reduction: %f\n", timer.GetCurrentElapsedTime()); } //Angle Reduction and Probability summation for individual angles if (param.param_device.writeAngles) { const int count = RefMap.ntotRefMap * param.nTotGridAngles; myfloat_t* tmp1 = new myfloat_t[count]; myfloat_t* tmp2 = new myfloat_t[count]; myfloat_t* tmp3 = new myfloat_t[count]; for (int i = 0;i < RefMap.ntotRefMap;i++) { tmp1[i] = pProb.getProbMap(i).Constoadd; } MPI_Allreduce(tmp1, tmp2, count, MY_MPI_FLOAT, MPI_MAX, MPI_COMM_WORLD); for (int i = 0;i < RefMap.ntotRefMap;i++) { for (int j = 0;j < param.nTotGridAngles;j++) { bioem_Probability_angle& pProbAngle = pProb.getProbAngle(i, j); tmp1[i * param.nTotGridAngles + j] = pProbAngle.forAngles * exp(pProbAngle.ConstAngle - tmp2[i * param.nTotGridAngles + j]); } } MPI_Reduce(tmp1, tmp3, count, MY_MPI_FLOAT, MPI_SUM, 0, MPI_COMM_WORLD); if (mpi_rank == 0) { for (int i = 0;i < RefMap.ntotRefMap;i++) { for (int j = 0;j < param.nTotGridAngles;j++) { bioem_Probability_angle& pProbAngle = pProb.getProbAngle(i, j); pProbAngle.forAngles = tmp3[i * param.nTotGridAngles + j]; pProbAngle.ConstAngle = tmp2[i * param.nTotGridAngles + j]; } } } delete[] tmp1; delete[] tmp2; delete[] tmp3; } } #endif if (mpi_rank == 0) { // Output for Angle Probability File ofstream angProbfile; if(param.param_device.writeAngles) { angProbfile.open ("ANG_PROB"); angProbfile <<"************************* HEADER:: NOTATION *******************************************\n"; angProbfile <<" RefMap: MapNumber ; alpha - beta - gamma - log Probability\n" ; angProbfile <<"************************* HEADER:: NOTATION *******************************************\n"; } // Output for Cross Correlation File ofstream ccProbfile; if(param.param_device.writeCC) { ccProbfile.open ("CROSS_CORRELATION"); ccProbfile <<"************************* HEADER:: NOTATION *******************************************\n"; ccProbfile <<" RefMap: MapNumber ; Pixel x - Pixel y - Cross-Correlation \n"; ccProbfile <<"************************* HEADER:: NOTATION *******************************************\n"; } // Output for Standard Probability ofstream outputProbFile; outputProbFile.open ("Output_Probabilities"); outputProbFile <<"************************* HEADER:: NOTATION *******************************************\n"; outputProbFile << " RefMap: MapNumber ; LogProb: natural logarithm of posterior Probability ; Constant: Numerical Const. for adding Probabilities \n"; outputProbFile << " RefMap: MapNumber ; Maximizing Param: MaxLogProb - alpha - beta - gamma - PSF amp - PSF phase - PSF envelope - center x - center y - normalization - offsett \n"; if(param.writeCTF) outputProbFile << " RefMap: MapNumber ; CTFMaxParm: defocus - b-factor (ref. Penzeck 2010)\n"; outputProbFile <<"************************* HEADER:: NOTATION *******************************************\n\n"; // Loop over reference maps for (int iRefMap = 0; iRefMap < RefMap.ntotRefMap; iRefMap ++) { // **** Total Probability *** bioem_Probability_map& pProbMap = pProb.getProbMap(iRefMap); //Controll for Value of Total Probability // cout << pProbMap.Total << " " << pProbMap.Constoadd << " " << FLT_MAX <<" " << log(FLT_MAX) << "\n"; if(pProbMap.Total>1.e-38){ outputProbFile << "RefMap: " << iRefMap << " LogProb: " << log(pProbMap.Total) + pProbMap.Constoadd + 0.5 * log(M_PI) + (1 - param.param_device.Ntotpi * 0.5)*(log(2 * M_PI) + 1) + log(param.param_device.volu) << " Constant: " << pProbMap.Constoadd << "\n"; outputProbFile << "RefMap: " << iRefMap << " Maximizing Param: "; // *** Param that maximize probability**** outputProbFile << (pProbMap.Constoadd + 0.5 * log(M_PI) + (1 - param.param_device.Ntotpi * 0.5) * (log(2 * M_PI) + 1) + log(param.param_device.volu)) << " "; outputProbFile << param.angles[pProbMap.max.max_prob_orient].pos[0] << " [rad] "; outputProbFile << param.angles[pProbMap.max.max_prob_orient].pos[1] << " [rad] "; outputProbFile << param.angles[pProbMap.max.max_prob_orient].pos[2] << " [rad] "; outputProbFile << param.CtfParam[pProbMap.max.max_prob_conv].pos[0] << " [ ] "; outputProbFile << param.CtfParam[pProbMap.max.max_prob_conv].pos[1] << " [1./A²] "; outputProbFile << param.CtfParam[pProbMap.max.max_prob_conv].pos[2] << " [1./A²] "; outputProbFile << pProbMap.max.max_prob_cent_x << " [pix] "; outputProbFile << pProbMap.max.max_prob_cent_y << " [pix] " ; outputProbFile << pProbMap.max.max_prob_norm << " [ ] " ; outputProbFile << pProbMap.max.max_prob_mu << " [ ] "; outputProbFile << "\n"; }else{ outputProbFile << "PROBLEM!! with Map " << iRefMap << "Numerical Integrated Probability = 0.0; Try re-normalizing experimental map\n"; outputProbFile << "RefMap: " << iRefMap << "Most probabily Numerical Constant Out of Float-point range: " << pProbMap.Constoadd << "\n"; } // Writing out CTF parameters if requiered if(param.writeCTF){ myfloat_t denomi; denomi = param.CtfParam[pProbMap.max.max_prob_conv].pos[1] * param.CtfParam[pProbMap.max.max_prob_conv].pos[1] + param.CtfParam[pProbMap.max.max_prob_conv].pos[2] * param.CtfParam[pProbMap.max.max_prob_conv].pos[2]; outputProbFile << "RefMap: " << iRefMap << " CTFMaxParam: "; outputProbFile << 2*M_PI*param.CtfParam[pProbMap.max.max_prob_conv].pos[1]/denomi/param.elecwavel << " [micro-m]; "; outputProbFile << "2*(" << sqrt(4*M_PI*param.CtfParam[pProbMap.max.max_prob_conv].pos[2]/denomi) << ")² [1./A²] \n"; } // Writing Individual Angle probabilities if(param.param_device.writeAngles) { for (int iOrient = 0; iOrient < param.nTotGridAngles; iOrient++) { bioem_Probability_angle& pProbAngle = pProb.getProbAngle(iRefMap, iOrient); angProbfile << " " << iRefMap << " " << param.angles[iOrient].pos[0] << " " << param.angles[iOrient].pos[1] << " " << param.angles[iOrient].pos[2] << " " << log(pProbAngle.forAngles) + pProbAngle.ConstAngle + 0.5 * log(M_PI) + (1 - param.param_device.Ntotpi * 0.5)*(log(2 * M_PI) + 1) + log(param.param_device.volu) << " " << log(param.param_device.volu) << "\n"; } } // Writing Cross-Correlations if requiered if(param.param_device.writeCC){ int cc=0; int halfPix; int rx=0; int ry=0; myfloat_t localcc[ (param.param_device.NumberPixels+1) * (param.param_device.NumberPixels+1) ]; halfPix = param.param_device.NumberPixels / 2 ; // Ordering the centers of the Cross Correlation for (int rx = 0; rx < param.param_device.NumberPixels ; rx++) { for (int ry = 0; ry < param.param_device.NumberPixels ; ry++) { localcc[ rx * param.param_device.NumberPixels + ry ] = 0.0; } } for (int cent_x = 0; cent_x < param.param_device.NumberPixels ; cent_x = cent_x + param.param_device.CCdisplace) { for (int cent_y = 0; cent_y < param.param_device.NumberPixels ; cent_y = cent_y + param.param_device.CCdisplace) { //localcc[ rx * param.param_device.NumberPixels + ry ] = 0.0; bioem_Probability_cc& pProbCC = pProb.getProbCC(iRefMap, cc); // Applying Periodic boundary conditions to the CC if(cent_x < halfPix && cent_y < halfPix){ // ccProbfile << " " << iRefMap << " " << (myfloat_t) halfPix - cent_x << " " << halfPix - cent_y << " " << pProbCC.forCC <<"\n"; rx = halfPix - cent_x; ry = halfPix - cent_y;} if(cent_x >= halfPix && cent_y < halfPix){ // ccProbfile << " " << iRefMap << " " << (myfloat_t) 3 * halfPix - cent_x << " " << halfPix - cent_y << " " << pProbCC.forCC <<"\n"; rx = 3 * halfPix - cent_x; ry = halfPix - cent_y;} if(cent_x < halfPix && cent_y >= halfPix){ // ccProbfile << " " << iRefMap << " " << (myfloat_t) halfPix - cent_x << " " << 3 * halfPix - cent_y << " " << pProbCC.forCC <<"\n"; rx = halfPix - cent_x; ry = 3 * halfPix - cent_y;} if(cent_x >= halfPix && cent_y >= halfPix){ // ccProbfile << " " << iRefMap << " " << 3* halfPix - cent_x << " " << 3 * halfPix - cent_y << " " << pProbCC.forCC <<"\n"; rx = 3 * halfPix - cent_x; ry = 3 * halfPix - cent_y;} // cout << " TT " << cent_x << " " << rx << " " << cent_y << " " << ry << " " << pProbCC.forCC << "\n"; if(!param.param_device.CCwithBayes){ localcc[ rx * param.param_device.NumberPixels + ry ] = pProbCC.forCC; }else{ localcc[ rx * param.param_device.NumberPixels + ry ] = log(pProbCC.forCC)+pProbCC.ConstCC; } cc++; } // ccProbfile << "\n"; } if(!param.ignoreCCoff){ for (int rx = param.param_device.CCdisplace; rx < param.param_device.NumberPixels ; rx = rx + param.param_device.CCdisplace) { for (int ry = param.param_device.CCdisplace; ry < param.param_device.NumberPixels ; ry = ry + param.param_device.CCdisplace) { ccProbfile << "RefMap: "<< iRefMap << " " << rx << " " << ry << " " << localcc[ rx * param.param_device.NumberPixels + ry ] << "\n" ; // cout << " cc " << rx << " " << ry << " " << localcc[ rx * param.param_device.NumberPixels + ry ] <<"\n" ; } ccProbfile << "\n"; } }else{ for (int rx = param.param_device.CCdisplace; rx < param.param_device.NumberPixels ; rx++) { for (int ry = param.param_device.CCdisplace; ry < param.param_device.NumberPixels ; ry++) { if(localcc[ rx * param.param_device.NumberPixels + ry ]!=0.0) ccProbfile << "RefMap: "<< iRefMap << " " << rx << " " << ry << " " << localcc[ rx * param.param_device.NumberPixels + ry ] << "\n" ; } ccProbfile << "\n"; } } } } if(param.param_device.writeAngles) { angProbfile.close(); } if(param.param_device.writeCC) { ccProbfile.close(); } outputProbFile.close(); } return(0); } int bioem::compareRefMaps(int iOrient, int iConv, const myfloat_t* conv_map, mycomplex_t* localmultFFT, myfloat_t sumC, myfloat_t sumsquareC, const int startMap) { //*************************************************************************************** //***** BioEM routine for comparing reference maps to convoluted maps ***** if (FFTAlgo) { //With FFT Algorithm #pragma omp parallel for schedule(dynamic, 1) for (int iRefMap = startMap; iRefMap < RefMap.ntotRefMap; iRefMap ++) { const int num = omp_get_thread_num(); calculateCCFFT(iRefMap, iOrient, iConv, sumC, sumsquareC, localmultFFT, param.fft_scratch_complex[num], param.fft_scratch_real[num]); } } else { //Without FFT Algorithm #pragma omp parallel for schedule(dynamic, 1) for (int iRefMap = startMap; iRefMap < RefMap.ntotRefMap; iRefMap ++) { compareRefMapShifted < -1 > (iRefMap, iOrient, iConv, conv_map, pProb, param.param_device, RefMap); } } return(0); } inline void bioem::calculateCCFFT(int iRefMap, int iOrient, int iConv, myfloat_t sumC, myfloat_t sumsquareC, mycomplex_t* localConvFFT, mycomplex_t* localCCT, myfloat_t* lCC) { //*************************************************************************************** //***** Calculating cross correlation in FFTALGOrithm ***** const mycomplex_t* RefMapFFT = &RefMap.RefMapsFFT[iRefMap * param.FFTMapSize]; for(int i = 0; i < param.param_device.NumberPixels * param.param_device.NumberFFTPixels1D; i++) { localCCT[i][0] = localConvFFT[i][0] * RefMapFFT[i][0] + localConvFFT[i][1] * RefMapFFT[i][1]; localCCT[i][1] = localConvFFT[i][1] * RefMapFFT[i][0] - localConvFFT[i][0] * RefMapFFT[i][1]; } myfftw_execute_dft_c2r(param.fft_plan_c2r_backward, localCCT, lCC); doRefMapFFT(iRefMap, iOrient, iConv, lCC, sumC, sumsquareC, pProb, param.param_device, RefMap); #ifdef PILAR_DEBUG if (param.param_device.writeCC) { int cc=0; for (int cent_x = 0; cent_x < param.param_device.NumberPixels ; cent_x = cent_x + param.param_device.CCdisplace) { for (int cent_y = 0; cent_y < param.param_device.NumberPixels ; cent_y = cent_y + param.param_device.CCdisplace) { cout << "CHECKCC " << " " << cent_x << " " << cent_y <<" " << lCC[cent_x * param.param_device.NumberPixels + cent_y] / (myfloat_t) (param.param_device.NumberPixels * param.param_device.NumberPixels ) << "\n"; cc++; } } } #endif } int bioem::createProjection(int iMap, mycomplex_t* mapFFT) { // ************************************************************************************** // **** BioEM Create Projection routine in Euler angle predefined grid****************** // ********************* and turns projection into Fourier space ************************ // ************************************************************************************** cuda_custom_timeslot("Projection", 0); myfloat3_t RotatedPointsModel[Model.nPointsModel]; myfloat_t rotmat[3][3]; myfloat_t alpha, gam, beta; myfloat_t* localproj; localproj = param.fft_scratch_real[omp_get_thread_num()]; memset(localproj, 0, param.param_device.NumberPixels * param.param_device.NumberPixels * sizeof(*localproj)); alpha = param.angles[iMap].pos[0]; beta = param.angles[iMap].pos[1]; gam = param.angles[iMap].pos[2]; // **** To see how things are going: cout << "Id " << omp_get_thread_num() << " Angs: " << alpha << " " << beta << " " << gam << "\n"; *** // ********** Creat Rotation with pre-defiend grid of orientations********** rotmat[0][0] = cos(gam) * cos(alpha) - cos(beta) * sin(alpha) * sin(gam); rotmat[0][1] = cos(gam) * sin(alpha) + cos(beta) * cos(alpha) * sin(gam); rotmat[0][2] = sin(gam) * sin(beta); rotmat[1][0] = -sin(gam) * cos(alpha) - cos(beta) * sin(alpha) * cos(gam); rotmat[1][1] = -sin(gam) * sin(alpha) + cos(beta) * cos(alpha) * cos(gam); rotmat[1][2] = cos(gam) * sin(beta); rotmat[2][0] = sin(beta) * sin(alpha); rotmat[2][1] = -sin(beta) * cos(alpha); rotmat[2][2] = cos(beta); for(int n = 0; n < Model.nPointsModel; n++) { RotatedPointsModel[n].pos[0] = 0.0; RotatedPointsModel[n].pos[1] = 0.0; RotatedPointsModel[n].pos[2] = 0.0; } for(int n = 0; n < Model.nPointsModel; n++) { for(int k = 0; k < 3; k++) { for(int j = 0; j < 3; j++) { RotatedPointsModel[n].pos[k] += rotmat[k][j] * Model.points[n].point.pos[j]; } } } int i, j; //********** Projection with radius *************** if(param.doaaradius) { int irad; myfloat_t dist, rad2; for(int n = 0; n < Model.nPointsModel; n++) { //Getting Centers of Sphere i = floor(RotatedPointsModel[n].pos[0] / param.pixelSize + (myfloat_t) param.param_device.NumberPixels / 2.0f + 0.5f); j = floor(RotatedPointsModel[n].pos[1] / param.pixelSize + (myfloat_t) param.param_device.NumberPixels / 2.0f + 0.5f); //Getting the radius irad=int( Model.points[n].radius / param.pixelSize ); rad2= Model.points[n].radius * Model.points[n].radius; //Projecting over the radius for(int ii= i - irad; ii < i + irad; ii++) { for(int jj = j - irad; jj < j + irad; jj++) { dist= ( (myfloat_t) (ii-i)*(ii-i)+(jj-j)*(jj-j) ) * param.pixelSize ; if( dist < rad2 ) { localproj[ii * param.param_device.NumberPixels + jj] += param.pixelSize * 2 * sqrt( rad2 - dist ) * Model.points[n].density // / Model.NormDen * 3 / (4 * M_PI * rad2 * Model.points[n].radius); * 3 / (4 * M_PI * rad2 * Model.points[n].radius); } } } } } else { // ************ Simple Projection over the Z axis******************** for(int n = 0; n < Model.nPointsModel; n++) { //Getting pixel that represents coordinates & shifting the start at to Numpix/2,Numpix/2 ) i = floor(RotatedPointsModel[n].pos[0] / param.pixelSize + (myfloat_t) param.param_device.NumberPixels / 2.0f + 0.5f); j = floor(RotatedPointsModel[n].pos[1] / param.pixelSize + (myfloat_t) param.param_device.NumberPixels / 2.0f + 0.5f); if (i < 0 || j < 0 || i >= param.param_device.NumberPixels || j >= param.param_device.NumberPixels) { if (DebugOutput >= 3) cout << "Model Point out of map: " << i << ", " << j << "\n"; continue; } localproj[i * param.param_device.NumberPixels + j] += Model.points[n].density;//Model.NormDen; } } // **** Output Just to check**** #ifdef PILAR_DEBUG if(iMap == 10) { ofstream myexamplemap; ofstream myexampleRot; myexamplemap.open ("MAP_i10"); myexampleRot.open ("Rot_i10"); myexamplemap << "ANGLES " << alpha << " " << beta << " " << gam << "\n"; for(int k = 0; k < param.param_device.NumberPixels; k++) { for(int j = 0; j < param.param_device.NumberPixels; j++) myexamplemap << "\nMAP " << k << " " << j << " " << localproj[k * param.param_device.NumberPixels + j]; } myexamplemap << " \n"; for(int n = 0; n < Model.nPointsModel; n++)myexampleRot << "\nCOOR " << RotatedPointsModel[n].pos[0] << " " << RotatedPointsModel[n].pos[1] << " " << RotatedPointsModel[n].pos[2]; myexamplemap.close(); myexampleRot.close(); } #endif // ***** Converting projection to Fourier Space for Convolution later with kernel**** // ********** Omp Critical is necessary with FFTW******* myfftw_execute_dft_r2c(param.fft_plan_r2c_forward, localproj, mapFFT); cuda_custom_timeslot_end; return(0); } int bioem::createConvolutedProjectionMap(int iMap, int iConv, mycomplex_t* lproj, myfloat_t* Mapconv, mycomplex_t* localmultFFT, myfloat_t& sumC, myfloat_t& sumsquareC) { // ************************************************************************************** // **** BioEM Create Convoluted Projection Map routine, multiplies in Fourier ********** // **************** calculated Projection with convoluted precalculated Kernel*********** // *************** and Backtransforming it to real Space ******************************** // ************************************************************************************** cuda_custom_timeslot("Convolution", 1); mycomplex_t* tmp = param.fft_scratch_complex[omp_get_thread_num()]; // **** Multiplying FFTmap with corresponding kernel **** const mycomplex_t* refCTF = ¶m.refCTF[iConv * param.FFTMapSize]; for(int i = 0; i < param.param_device.NumberPixels * param.param_device.NumberFFTPixels1D; i++) { localmultFFT[i][0] = ( lproj[i][0] * refCTF[i][0] + lproj[i][1] * refCTF[i][1] ) ; localmultFFT[i][1] = ( lproj[i][1] * refCTF[i][0] - lproj[i][0] * refCTF[i][1] ) ; // cout << "GG " << i << " " << j << " " << refCTF[i][0] << " " << refCTF[i][1] <<" " <