Xmipp  v3.23.11-Nereus
mpi_angular_projection_matching.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Authors: J.M. de la Rosa Trevin (jmdelarosa@cnb.csic.es)
3  *
4  *
5  * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20  * 02111-1307 USA
21  *
22  * All comments concerning this program package may be sent to the
23  * e-mail address 'xmipp@cnb.csic.es'
24  ***************************************************************************/
25 
28 
29 /*Some constast to message passing tags */
30 constexpr int TAG_JOB_REQUEST = 1;
31 constexpr int TAG_JOB_REPLY = 2;
32 
33 /*Constructor */
35 {
36  imagesBuffer = nullptr;
37  last_chunk = nullptr;
38 }
39 /* Destructor */
41 {
42  if (node->isMaster())
43  {
44  delete[] imagesBuffer;
45  delete[] last_chunk;
46  }
47  delete node; //this calls MPI_Finalize
48 }
49 
51 {
52  node = new MpiNode(argc, argv);
53  // Master should read first
54  if (node->isMaster())
55  ProgAngularProjectionMatching::read(argc, (const char **)argv);
56  node->barrierWait();
57  if (!node->isMaster())
58  {
59 
60  verbose = 0;//disable verbose for slaves
61  ProgAngularProjectionMatching::read(argc, (const char **)argv);
62  }
63 }
64 
65 /* Define accepted params ------------------------------------------------------------------- */
67 {
70  " [--mpi_job_size <size=10>] : Number of images sent to a cpu in a single job ");
71  addParamsLine(" : 10 may be a good value");
73  " : if -1 the computer will fill the value for you");
75  " [--chunk_angular_distance <dist=-1>] : sample the projection sphere with this ");
77  " :using the voronoi regions");
79  " [--sym <cn=\"c1\">] : One of the 17 possible symmetries in");
81  " :single particle electronmicroscopy");
83  " :i.e. ci, cs, cn, cnv, cnh, sn, dn, dnv,");
85  " :dnh, t, td, th, o, oh, i1 (default MDB), i2, i3, i4, ih");
87  " :i1h (default MDB), i2h, i3h, i4h");
89  " : where n may change from 1 to 99");
90 }
91 
92 /* Read parameters --------------------------------------------------------- */
94 {
96  mpi_job_size = getIntParam("--mpi_job_size");
97  imagesBuffer = new size_t[mpi_job_size + 1];
98  chunk_angular_distance = getDoubleParam("--chunk_angular_distance");
99  fn_sym = getParam("--sym");
100 }
101 
103 {
104  if (node->isMaster()) //master distribute jobs
105  {
106 
107  size_t finishingWorkers = 0;
108  size_t processedImages = 0, finishedImages = 0, totalImages = DFexp.size();
109  MPI_Status status;
110 
111  if (verbose)
112  {
113  progress_bar_step = XMIPP_MAX(1, totalImages / 80);
114  init_progress_bar(totalImages);
115  }
116 
117  while (finishingWorkers < node->size - 1)
118  {
119  //Receive a request of job from a worker
120  //the number of images processed should be sent in imagesBuffer[0]
121  MPI_Recv(&processedImages, 1, XMIPP_MPI_SIZE_T, MPI_ANY_SOURCE,
122  TAG_JOB_REQUEST, MPI_COMM_WORLD, &status);
123  finishedImages += processedImages;
124 
125  if (!distributeJobs(imagesBuffer, status.MPI_SOURCE))
126  {
127  ++finishingWorkers;
128  }
129  MPI_Send(imagesBuffer, imagesBuffer[0] + 1, XMIPP_MPI_SIZE_T,
130  status.MPI_SOURCE, TAG_JOB_REPLY, MPI_COMM_WORLD);
131 
132  if (verbose && processedImages > 0)
133  progress_bar(finishedImages);
134  }
135 
136  } else //slaves really work
137  {
138  std::vector<size_t> imagesToProcess;
139  while (requestJobs (imagesToProcess))
140  {
141  processSomeImages(imagesToProcess);
142  }
143  }
144 
145  // Synchronize all nodes.
146  //node->barrierWait();
147 }
148 
150  int node)
151 {
152  int node_index = last_chunk[node];
153  static bool reached_last_chunk = false;
154 
155  if (node_index == -1
156  || chunk_mysampling.my_exp_img_per_sampling_point[node_index].empty())
157  {
158 
159  if (!reached_last_chunk)
160  {
161  node_index = chunk_index;
162  chunk_index = (chunk_index + 1) % chunk_number;
163  reached_last_chunk = (chunk_index == 0);
164  }
165  else
166  {
167  int i = 0;
168  for (;
169  i < chunk_number
170  && chunk_mysampling.my_exp_img_per_sampling_point[chunk_index].empty();
171  ++i, chunk_index = (chunk_index + 1) % chunk_number)
172  ;
173 
174  // std::cerr << formatString("DEBUG: master: assigned %d chuck to node %d, i = %d", chunk_index, node, i);
175  if (i == chunk_number)
176  {
177  imagesToSent[0] = 0;
178  return false;
179  }
180  last_chunk[node] = node_index = chunk_index;
181  chunk_index = (chunk_index + 1) % chunk_number;
182  }
183  }
184 
185  size_t assigned_images = std::min((size_t)mpi_job_size, chunk_mysampling.my_exp_img_per_sampling_point[node_index].size());
186  imagesToSent[0] = assigned_images;
187 
188  //std::cerr << formatString("DEBUG: master: assigned %lu images to node %d\n", assigned_images, node);
189 
190  for (size_t i = 1; i <= assigned_images; ++i)
191  {
192  imagesToSent[i] =
193  chunk_mysampling.my_exp_img_per_sampling_point[node_index].back() + FIRST_IMAGE;
194  // std::cerr << " " << imagesToSent[i];
195  chunk_mysampling.my_exp_img_per_sampling_point[node_index].pop_back();
196  }
197 
198  // std::cerr << std::endl;
199 
200  return true;
201 }
202 
204  std::vector<size_t> &imagesToProcess)
205 {
206  static size_t numberOfImages = 0;
207  MPI_Status status;
208 
209  //Sent last receveiced numberOfImages, which should be processed by this worker
210  MPI_Send(&numberOfImages, 1, XMIPP_MPI_SIZE_T, 0, TAG_JOB_REQUEST,
211  MPI_COMM_WORLD);
212  //Get new job to do
213  MPI_Recv(imagesBuffer, mpi_job_size + 1, XMIPP_MPI_SIZE_T, 0,
214  TAG_JOB_REPLY, MPI_COMM_WORLD, &status);
215  numberOfImages = imagesBuffer[0];
216 
217  if (numberOfImages == 0)
218  return false;
219 
220  imagesToProcess.clear();
221  for (size_t i = 1; i <= numberOfImages; ++i)
222  imagesToProcess.push_back(imagesBuffer[i]);
223  return true;
224 }
225 
227 {
228  node->gatherMetadatas(DFo, fn_out);
229  if (node->isMaster())
230  {
231  MetaDataDb mdAux;
232  mdAux.sort(DFo,MDL_IMAGE);
233  mdAux.write(fn_out, do_overwrite);
234  }
235 }
236 
238 {
240 
241  if (node->isMaster())
242  computeChunks();
243  node->barrierWait();
244 }
245 
247 {
248  size_t max_number_of_images_in_around_a_sampling_point = 0;
249  //process the symmetry file
250  if (!chunk_mysampling.SL.isSymmetryGroup(fn_sym, symmetry, sym_order))
252  (String)"mpi_angular_proj_match::prerun Invalid symmetry: " + fn_sym);
253  chunk_mysampling.SL.readSymmetryFile(fn_sym);
254  // find a value for chunk_angular_distance if != -1
255  if (chunk_angular_distance == -1)
256  computeChunkAngularDistance(symmetry, sym_order);
257  //store symmetry matrices, this is faster than computing them
258  //each time we need them
259  chunk_mysampling.fillLRRepository();
260  int remaining_points = 0;
261 
262  while (remaining_points == 0)
263  {
264  //first set sampling rate
265  chunk_mysampling.setSampling(chunk_angular_distance);
266  //create sampling points in the whole sphere
267  //chunk_mysampling.computeSamplingPoints(false, 0, 180);
268  chunk_mysampling.computeSamplingPoints(false, 180, 0);
269  //precompute product between symmetry matrices
270  //and experimental data
271  chunk_mysampling.fillExpDataProjectionDirectionByLR(fn_exp);
272  //remove redundant sampling points: symmetry
273  chunk_mysampling.removeRedundantPoints(symmetry, sym_order);
274  remaining_points =
275  chunk_mysampling.no_redundant_sampling_points_angles.size();
276  if (chunk_angular_distance > 2)
277  chunk_angular_distance -= 1;
278  else
279  chunk_angular_distance /= 2;
280  //if(remaining_points ==0)
281  if (verbose)
282  std::cout << "New chunk_angular_distance " << chunk_angular_distance
283  << std::endl;
284  if (chunk_angular_distance < 0)
286  "Can't compute chunk_angular_distance");
287  }
288  //remove sampling points too far away from experimental data
289  chunk_mysampling.removePointsFarAwayFromExperimentalData();
290  //for each sampling point find the experimental images
291  //closer to that point than to any other
292  chunk_mysampling.findClosestExperimentalPoint();
293  //print number of points per node
294  chunk_number = chunk_mysampling.my_exp_img_per_sampling_point.size();
295  for (int j = 0; j < chunk_number; j++)
296  {
297  if (max_number_of_images_in_around_a_sampling_point
298  < chunk_mysampling.my_exp_img_per_sampling_point[j].size())
299  max_number_of_images_in_around_a_sampling_point =
300  chunk_mysampling.my_exp_img_per_sampling_point[j].size();
301  }
302  if (verbose)
303  {
304  std::cout << "number of subsets: " << chunk_number << std::endl
305  << "biggest subset (EXPERIMENTAL images per chunk): "
306  << max_number_of_images_in_around_a_sampling_point << std::endl
307  << "maximun number of references in memory: "
308  << max_nr_refs_in_memory << std::endl;
309  }
310  //alloc memory for buffer
311  if (mpi_job_size == -1)
312  mpi_job_size = (int)ceil((double)DFexp.size()/(node->size - 1));
313 
314  //Distribution related variables
315  chunk_index = 0;
316  last_chunk = new int[node->size];
317  for (size_t i = 1; i < node->size; ++i)
318  last_chunk[i] = -1;//by default no chunk assigned yet
319 }
320 
322  int sym_order)
323 {
324  double non_reduntant_area_of_sphere =
325  chunk_mysampling.SL.nonRedundantProjectionSphere(symmetry,
326  sym_order);
327  double number_cpus = (double) node->size - 1;
328  //NEXT ONE IS SAMPLING NOT ANOTHERSAMPLING
329  double neighborhood_radius = fabs(acos(mysampling.cos_neighborhood_radius));
330  //NEXT ONE IS SAMPLING NOT ANOTHERSAMPLING
331  if (mysampling.cos_neighborhood_radius < -1.001)
332  neighborhood_radius = 0;
333  int counter = 0;
334  while (1)
335  {
336  if (counter++ > 1000)
337  {
338  chunk_angular_distance = 0.001;
339  std::cerr << "****************************************************"
340  << std::endl;
341  std::cerr << "* WARNING: The neighbourhood does not fit in memory "
342  << std::endl;
343  std::cerr << "****************************************************"
344  << std::endl;
345  break;
346  }
347  double area_chunk = non_reduntant_area_of_sphere / number_cpus;
348  //area chunk is area of spheric casket=2 PI h
349  chunk_angular_distance = acos(1 - area_chunk / (2 * PI));
350  double area_chunck_neigh = 2 * PI
351  * (1 - cos(chunk_angular_distance + neighborhood_radius));
352  //double area_chunck= 2 * PI *( 1 - cos(chunk_angular_distance));
353  //let us see how many references from the reference library fit
354  //in area_chunk, that is divide area_chunk between the voronoi
355  //region of the sampling points of the reference library
356  double areaVoronoiRegionReferenceLibrary = 2 *( 3 *( acos(
357  //NEXT ONE IS SAMPLING NOT ANOTHERSAMPLING
359  auto number_of_images_that_fit_in_a_chunck_neigh =(int)
360  ceil(area_chunck_neigh / areaVoronoiRegionReferenceLibrary);
361  //#define DEBUG
362 #ifdef DEBUG
363 
364  std::cerr << "\n\ncounter " << counter << std::endl;
365  std::cerr << "area_chunk " << area_chunk << std::endl;
366  std::cerr << "2*chunk_angular_distance " << 2*chunk_angular_distance << std::endl;
367  //NEXT ONE IS SAMPLING NOT ANOTHERSAMPLING
368  std::cerr << "sampling_rate_rad " << mysampling.sampling_rate_rad
369  << " " << mysampling.sampling_rate_rad*180/PI
370  << std::endl;
371  std::cerr << "neighborhood_radius " << neighborhood_radius
372  << std::endl;
373  std::cerr << "areaVoronoiRegionReferenceLibrary " << areaVoronoiRegionReferenceLibrary << std::endl;
374  std::cerr << "number_of_images_that_fit_in_a_chunck_neigh " << number_of_images_that_fit_in_a_chunck_neigh << std::endl;
375  std::cerr << "number_cpus " << number_cpus << std::endl;
376  std::cerr << "max_nr_imgs_in_memory " << max_nr_imgs_in_memory << std::endl;
377 #endif
378 #undef DEBUG
379 
380  if (number_of_images_that_fit_in_a_chunck_neigh > max_nr_imgs_in_memory)
381  number_cpus = 1.2 * number_cpus;
382  else
383  break;
384  }
385  //chunk_angular_distance -= neighborhood_radius;
386  chunk_angular_distance *= 2.0;
387 
388  //#define DEBUG
389 #ifdef DEBUG
390 
391  std::cerr << "chunk_angular_distance " << chunk_angular_distance
392  << std::endl
393  << "neighborhood_radius " << neighborhood_radius
394  << std::endl;
395 #endif
396 #undef DEBUG
397  //chuck should not be bigger than a triangle in the icosahedra
398  if (chunk_angular_distance >= 0.5 * cte_w)
399  chunk_angular_distance = 0.5 * cte_w;
400  chunk_angular_distance *= (180. / PI);
401  //#define DEBUG
402 #ifdef DEBUG
403 
404  std::cerr << "chunk_angular_distance_degrees " << chunk_angular_distance
405  << std::endl;
406 #endif
407 #undef DEBUG
408 
409 }
double nonRedundantProjectionSphere(int pgGroup, int pgOrder)
size_t size
Definition: xmipp_mpi.h:52
void computeChunkAngularDistance(int symmetry, int sym_order)
void init_progress_bar(long total)
std::vector< std::vector< size_t > > my_exp_img_per_sampling_point
Definition: sampling.h:90
void setSampling(double sampling)
Definition: sampling.cpp:121
void min(Image< double > &op1, const Image< double > &op2)
void removeRedundantPoints(const int symmetry, int sym_order)
Definition: sampling.cpp:691
#define XMIPP_MAX(x, y)
Definition: xmipp_macros.h:193
double getDoubleParam(const char *param, int arg=0)
virtual void read(int argc, const char **argv, bool reportErrors=true)
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
int readSymmetryFile(FileName fn_sym, double accuracy=SYM_ACCURACY)
Definition: symmetries.cpp:33
virtual void readParams()
Read arguments from command line.
void processSomeImages(const std::vector< size_t > &imagesToProcess)
bool isSymmetryGroup(FileName fn_sym, int &pgGroup, int &pgOrder)
Definition: symmetries.cpp:601
void findClosestExperimentalPoint()
Definition: sampling.cpp:2100
virtual void defineParams()
Define arguments accepted.
bool requestJobs(std::vector< size_t > &imagesToProcess)
void barrierWait()
Definition: xmipp_mpi.cpp:171
#define i
#define XMIPP_MPI_SIZE_T
Definition: xmipp_mpi.h:37
void readParams()
Read arguments from command line.
double sampling_rate_rad
Definition: sampling.h:69
void defineParams()
Define arguments accepted.
int argc
Original command line arguments.
Definition: xmipp_program.h:86
void computeSamplingPoints(bool only_half_sphere=true, double max_tilt=180, double min_tilt=0)
Definition: sampling.cpp:155
const char * getParam(const char *param, int arg=0)
void progress_bar(long rlen)
Error related to numerical calculation.
Definition: xmipp_error.h:179
const char ** argv
Definition: xmipp_program.h:87
double cos_neighborhood_radius
Definition: sampling.h:84
int verbose
Verbosity level.
void write(const FileName &outFile, WriteModeMetaData mode=MD_OVERWRITE) const override
size_t size() const override
void fillLRRepository(void)
Definition: sampling.cpp:2216
bool distributeJobs(size_t *imagesToSent, int node)
#define j
void sort(MetaDataDb &MDin, const MDLabel sortLabel, bool asc=true, int limit=-1, int offset=0)
std::vector< Matrix1D< double > > no_redundant_sampling_points_angles
Definition: sampling.h:121
std::string String
Definition: xmipp_strings.h:34
constexpr int TAG_JOB_REQUEST
#define cte_w
Definition: sampling.h:35
constexpr int TAG_JOB_REPLY
bool isMaster() const
Definition: xmipp_mpi.cpp:166
#define FIRST_IMAGE
void fillExpDataProjectionDirectionByLR(const MetaData &DFi)
Definition: sampling.cpp:2256
void removePointsFarAwayFromExperimentalData()
Definition: sampling.cpp:1928
#define PI
Definition: tools.h:43
int getIntParam(const char *param, int arg=0)
void gatherMetadatas(T &MD, const FileName &rootName)
Definition: xmipp_mpi.cpp:200
Incorrect value received.
Definition: xmipp_error.h:195
Name of an image (std::string)
SymList SL
Definition: sampling.h:138
void addParamsLine(const String &line)