Xmipp  v3.23.11-Nereus
blobs.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: Carlos Oscar S. Sorzano (coss@cnb.csic.es)
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 
26 #include <pthread.h>
27 #include "blobs.h"
28 #include "core/numerical_recipes.h"
29 #include "xmipp_image_over.h"
30 
31 pthread_mutex_t blobs_conv_mutex = PTHREAD_MUTEX_INITIALIZER;
32 
35 
36 /* Value of a blob --------------------------------------------------------- */
37 double kaiser_value(double r, double a, double alpha, int m)
38 {
39  double rda;
40  double rdas;
41  double arg;
42  double w;
43 
44  rda = r / a;
45  if (rda <= 1.0)
46  {
47  rdas = rda * rda;
48  arg = alpha * sqrt(1.0 - rdas);
49  if (m == 0)
50  {
51  w = bessi0(arg) / bessi0(alpha);
52  }
53  else if (m == 1)
54  {
55  w = sqrt (1.0 - rdas);
56  if (alpha != 0.0)
57  w *= bessi1(arg) / bessi1(alpha);
58  }
59  else if (m == 2)
60  {
61  w = sqrt (1.0 - rdas);
62  w = w * w;
63  if (alpha != 0.0)
64  w *= bessi2(arg) / bessi2(alpha);
65  }
66  else if (m == 3)
67  {
68  w = sqrt (1.0 - rdas);
69  w = w * w * w;
70  if (alpha != 0.0)
71  w *= bessi3(arg) / bessi3(alpha);
72  }
73  else if (m == 4)
74  {
75  w = sqrt (1.0 - rdas);
76  w = w * w * w *w;
77  if (alpha != 0.0)
78  w *= bessi4(arg) / bessi4(alpha);
79  }
80  else
81  REPORT_ERROR(ERR_VALUE_INCORRECT, "m out of range in kaiser_value()");
82 
83  }
84  else
85  w = 0.0;
86 
87  return w;
88 }
89 
90 /* Line integral through a blob -------------------------------------------- */
91 /* Value of line integral through Kaiser-Bessel radial function
92  (n >=2 dimensions) at distance s from center of function.
93  Parameter m = 0, 1, or 2. */
94 double kaiser_proj(double s, double a, double alpha, int m)
95 {
96  double sda;
97  double sdas;
98  double w;
99  double arg;
100  double p;
101 
102  sda = s / a;
103  sdas = sda * sda;
104  w = 1.0 - sdas;
105  if (w > 1.0e-10)
106  {
107  arg = alpha * sqrt(w);
108  if (m == 0)
109  {
110  if (alpha == 0.0)
111  p = 2.0 * a * sqrt(w);
112  else
113  p = (2.0 * a / alpha) * sinh(arg) / bessi0(alpha);
114 
115  }
116  else if (m == 1)
117  {
118  if (alpha == 0.0)
119  p = 2.0 * a * w * sqrt(w) * (2.0 / 3.0);
120  else
121  p = (2.0 * a / alpha) * sqrt(w) * (cosh(arg) - sinh(arg) / arg)
122  / bessi1(alpha);
123 
124  }
125  else if (m == 2)
126  {
127  if (alpha == 0.0)
128  p = 2.0 * a * w * w * sqrt(w) * (8.0 / 15.0);
129  else
130  p = (2.0 * a / alpha) * w *
131  ((3.0 / (arg * arg) + 1.0) * sinh(arg) - (3.0 / arg) * cosh(arg)) / bessi2(alpha);
132  }
133  else
134  REPORT_ERROR(ERR_VALUE_INCORRECT, "m out of range in kaiser_proj()");
135 
136  }
137  else
138  p = 0.0;
139 
140  return p;
141 }
142 
143 /* Fourier value of a blob ------------------------------------------------- */
144 double kaiser_Fourier_value(double w, double a, double alpha, int m)
145 {
146  if (m != 2 && m !=0)
147  REPORT_ERROR(ERR_VALUE_INCORRECT, "m out of range in kaiser_Fourier_value()");
148  double sigma = sqrt(ABS(alpha * alpha - (2. * PI * a * w) * (2. * PI * a * w)));
149  if (m == 2)
150  {
151  if (2.*PI*a*w > alpha)
152  return pow(2.*PI, 3. / 2.)*pow(a, 3.)*pow(alpha, 2.)*bessj3_5(sigma)
153  / (bessi0(alpha)*pow(sigma, 3.5));
154  else
155  return pow(2.*PI, 3. / 2.)*pow(a, 3.)*pow(alpha, 2.)*bessi3_5(sigma)
156  / (bessi0(alpha)*pow(sigma, 3.5));
157  }
158  else if (m == 0)
159  {
160  if (2*PI*a*w > alpha)
161  return pow(2.*PI, 3. / 2.)*pow(a, 3)*bessj1_5(sigma)
162  / (bessi0(alpha)*pow(sigma, 1.5));
163  else
164  return pow(2.*PI, 3. / 2.)*pow(a, 3)*bessi1_5(sigma)
165  / (bessi0(alpha)*pow(sigma, 1.5));
166  }
167  else
168  REPORT_ERROR(ERR_ARG_INCORRECT,"Invalid blob order");
169 }
170 
171 
172 /* Sum a blob on a simple grid --------------------------------------------- */
173 // Computes sum of the values of a unitary blob on grid points. The blob is
174 // supposed to be at the origin of the absolute coordinate system
175 double sum_blob_SimpleGrid(const struct blobtype &blob, const SimpleGrid &grid,
176  const Matrix2D<double> *D)
177 {
179  Matrix1D<double> gr(3);
180  Matrix1D<double> ur(3);
181  Matrix1D<double> corner1(3);
182  Matrix1D<double> corner2(3);
183  double actual_radius;
184  int i;
185  int j;
186  int k;
187  double sum = 0.0;
188 
189  // Compute the limits of the blob in the grid coordinate system
190  grid.universe2grid(vectorR3(-blob.radius, -blob.radius, -blob.radius), corner1);
191  grid.universe2grid(vectorR3(blob.radius, blob.radius, blob.radius), corner2);
192  if (D != nullptr)
193  box_enclosing(corner1, corner2, *D, corner1, corner2);
194 
195  // Compute the sum in the points inside the grid
196  // The integer part of the vectors is taken for not picking points
197  // just in the border of the blob, which we know they are 0.
198  for (i = (int)XX(corner1); i <= (int)XX(corner2); i++)
199  for (j = (int)YY(corner1); j <= (int)YY(corner2); j++)
200  for (k = (int)ZZ(corner1); k <= (int)ZZ(corner2); k++)
201  {
202  VECTOR_R3(gr, i, j, k);
203  grid.grid2universe(gr, ur);
204  if (D != nullptr)
205  M3x3_BY_V3x1(ur, *D, ur);
206  actual_radius = ur.module();
207  if (actual_radius < blob.radius)
208  sum += kaiser_value(actual_radius,
209  blob.radius, blob.alpha, blob.order);
210  }
211  return sum;
212 }
213 
214 /* Volume integral of a blob ----------------------------------------------- */
215 double basvolume(double a, double alpha, int m, int n)
216 {
217  double hn;
218  double tpi;
219  double v;
220  hn = 0.5 * n;
221  tpi = 2.0 * PI;
222 
223  if (alpha == 0.0)
224  {
225  if ((n / 2)*2 == n) /* n even */
226  v = pow(tpi, hn) * in_zeroarg(n / 2 + m) / in_zeroarg(m);
227  else /* n odd */
228  v = pow(tpi, hn) * inph_zeroarg(n / 2 + m) / in_zeroarg(m);
229 
230  }
231  else
232  { /* alpha > 0.0 */
233  if ((n / 2)*2 == n) /* n even */
234  v = pow(tpi / alpha, hn) * i_n(n / 2 + m, alpha) / i_n(m, alpha);
235  else /* n odd */
236  v = pow(tpi / alpha, hn) * i_nph(n / 2 + m, alpha) / i_n(m, alpha);
237  }
238 
239  return v * pow(a, (double)n);
240 }
241 
242 /* Bessel function I_n (x), n = 0, 1, 2, ...
243  Use ONLY for small values of n */
244 double i_n(int n, double x)
245 {
246  int i;
247  double i_ns1;
248  double i_n;
249  double i_np1;
250 
251  if (n == 0)
252  return bessi0(x);
253  if (n == 1)
254  return bessi1(x);
255  if (x == 0.0)
256  return 0.0;
257  i_ns1 = bessi0(x);
258  i_n = bessi1(x);
259 
260  for (i = 1; i < n; i++)
261  {
262  i_np1 = i_ns1 - (2 * i) / x * i_n;
263  i_ns1 = i_n;
264  i_n = i_np1;
265  }
266  return i_n;
267 }
268 
269 /*.....Bessel function I_(n+1/2) (x), n = 0, 1, 2, ..........................*/
270 double i_nph(int n, double x)
271 {
272  int i;
273  double r2dpix;
274  double i_ns1;
275  double i_n;
276  double i_np1;
277 
278  if (x == 0.0)
279  return 0.0;
280  r2dpix = sqrt(2.0 / (PI * x));
281  i_ns1 = r2dpix * cosh(x);
282  i_n = r2dpix * sinh(x);
283 
284  for (i = 1; i <= n; i++)
285  {
286  i_np1 = i_ns1 - (2 * i - 1) / x * i_n;
287  i_ns1 = i_n;
288  i_n = i_np1;
289  }
290  return i_n;
291 }
292 
293 /*....Limit (z->0) of (1/z)^n I_n(z)..........................................*/
294 double in_zeroarg(int n)
295 {
296  int i;
297  double fact;
298  fact = 1.0;
299  for (i = 1; i <= n; i++)
300  {
301  fact *= 0.5 / i;
302  }
303  return fact;
304 }
305 
306 /*.......Limit (z->0) of (1/z)^(n+1/2) I_(n+1/2) (z)..........................*/
307 double inph_zeroarg(int n)
308 {
309  int i;
310  double fact;
311  fact = 1.0;
312  for (i = 1; i <= n; i++)
313  {
314  fact *= 1.0 / (2 * i + 1.0);
315  }
316  return fact*sqrt(2.0 / PI);
317 }
318 
319 /* Sum a blob on a complex grid -------------------------------------------- */
320 double sum_blob_Grid(const struct blobtype &blob, const Grid &grid,
321  const Matrix2D<double> *D)
322 {
323  double sum = 0;
324  for (size_t i = 0; i < grid.GridsNo(); i++)
325  sum += sum_blob_SimpleGrid(blob, grid(i), D);
326  return sum;
327 }
328 
329 /* Zero freq --------------------------------------------------------------- */
330 double blob_freq_zero(struct blobtype b)
331 {
332  return sqrt(b.alpha*b.alpha + 6.9879*6.9879) / (2*PI*b.radius);
333 }
334 
335 /* Attenuation ------------------------------------------------------------- */
336 double blob_att(double w, struct blobtype b)
337 {
338  return blob_Fourier_val(w, b) / blob_Fourier_val(0, b);
339 }
340 
341 /* Number of operations ---------------------------------------------------- */
342 double blob_ops(double w, struct blobtype b)
343 {
344  return pow(b.alpha*b.alpha + 6.9879*6.9879, 1.5) / b.radius;
345 }
346 
347 /* Optimal grid ------------------------------------------------------------ */
349 {
350  return 1 / blob_freq_zero(b);
351 }
353 {
354  return sqrt(8.0) / (2*blob_freq_zero(b));
355 }
357 {
358  return sqrt(27.0) / (4*blob_freq_zero(b));
359 }
360 
361 /* Best blob in region ----------------------------------------------------- */
362 //#define DEBUG
363 blobtype best_blob(double alpha_0, double alpha_F, double inc_alpha,
364  double a_0, double a_F, double inc_a, double w, double *target_att,
365  int target_length)
366 {
367  blobtype retval;
368  retval.order = 2;
369  int alpha_size = FLOOR((alpha_F - alpha_0) / inc_alpha + 1);
370  int a_size = FLOOR((a_F - a_0) / inc_a + 1);
371  Image<double> att;
372  Image<double> ops;
373  att().resize(alpha_size, a_size);
374  ops().resize(alpha_size, a_size);
375  int i;
376  int j;
377  double a;
378  double alpha;
379  double best_a = -1;
380  double best_alpha = -1;
381  double best_ops = 1e10;
382  double best_att = 0;
383  for (i = 0, alpha = alpha_0; i < alpha_size; alpha += inc_alpha, i++)
384  for (j = 0, a = a_0; j < a_size; a += inc_a, j++)
385  {
386  retval.radius = a;
387  retval.alpha = alpha;
388  A2D_ELEM(att(), i, j) = blob_att(w, retval);
389  A2D_ELEM(ops(), i, j) = blob_ops(w, retval);
390  if (j > 0)
391  for (int n = target_length - 1; n >= 0; n--)
392  if (A2D_ELEM(att(), i, j - 1) > target_att[n] &&
393  A2D_ELEM(att(), i, j) < target_att[n])
394  {
395  A2D_ELEM(att(), i, j) = 0;
396  if (A2D_ELEM(ops(), i, j - 1) < best_ops &&
397  A2D_ELEM(att(), i, j - 1) >= best_att)
398  {
399  best_alpha = alpha;
400  best_a = a - inc_a;
401  best_ops = A2D_ELEM(ops(), i, j - 1);
402  best_att = target_att[n];
403  }
404  }
405  }
406 #ifdef DEBUG
407  att.write((std::string)"att" + floatToString(w) + ".xmp");
408  ops.write((std::string)"ops" + floatToString(w) + ".xmp");
409 #endif
410 
411  retval.radius = best_a;
412  retval.alpha = best_alpha;
413  return retval;
414 }
415 
416 /* Footprint of a blob ----------------------------------------------------- */
418  ImageOver &blobprint, // blob foot_print table
419  const struct blobtype &blob, // blob description
420  int istep, // number of foot-print samples per one sample
421  // on projection plane in u,v directions
422  int normalise) // set to 1 if you want normalise. Usually
423 // you may omit it and no normalisation is performed
424 {
425  // Resize output image and redefine the origin of it
426  int footmax = CEIL(blob.radius);
427  blobprint.init(-footmax, footmax, istep, -footmax, footmax, istep);
428 
429  // Run for Imge class indexes
430  for (int i = STARTINGY(blobprint()); i <= FINISHINGY(blobprint()); i++)
431  for (int j = STARTINGX(blobprint()); j <= FINISHINGX(blobprint()); j++)
432  {
433  // Compute oversampled index and blob value
434  double vi;
435  double ui;
436  IMG2OVER(blobprint, i, j, vi, ui);
437  double r = sqrt(vi * vi + ui * ui);
438  IMGPIXEL(blobprint, i, j) = blob_proj(r, blob);
439  }
440 
441  // Adjust the footprint structure
442  if (normalise)
443  blobprint() /= blobprint().sum();
444 }
445 
446 //#define DEBUG
447 //#define DEBUG_MORE
448 /* Blobs -> Voxels for a SimpleGrid ---------------------------------------- */
449 // This function will construct a table of blob values (something like the
450 // footprint)
451 #define DEFORM_BLOB_WHEN_IN_CRYSTAL
452 void * blobs2voxels_SimpleGrid( void * data )
453 {
454  auto * thread_data = (ThreadBlobsToVoxels *) data;
455 
456  const MultidimArray<double> *vol_blobs = thread_data->vol_blobs;
457  const SimpleGrid *grid = thread_data->grid;
458  const struct blobtype *blob = thread_data->blob;
459  MultidimArray<double> *vol_voxels = thread_data->vol_voxels;
460  const Matrix2D<double> *D = thread_data->D;
461  int istep = thread_data->istep;
462  MultidimArray<double> *vol_corr = thread_data->vol_corr;
463  const MultidimArray<double> *vol_mask = thread_data->vol_mask;
464  ;
465  bool FORW = thread_data->FORW;
466  int eq_mode = thread_data->eq_mode;
467 
468  int min_separation = thread_data->min_separation;
469 
470  auto z_planes = (int)(ZZ(grid->highest) - ZZ(grid->lowest) + 1);
471 
472  Matrix2D<double> Dinv; // Inverse of D
473  Matrix1D<double> act_coord(3); // Coord: Actual position inside
474  // the voxel volume without deforming
475  Matrix1D<double> real_position(3); // Coord: actual position after
476  // applying the V transformation
477  Matrix1D<double> beginZ(3); // Coord: Voxel coordinates of the
478  // blob at the 3D point
479  // (z0,YY(lowest),XX(lowest))
480  Matrix1D<double> beginY(3); // Coord: Voxel coordinates of the
481  // blob at the 3D point
482  // (z0,y0,XX(lowest))
483  Matrix1D<double> corner2(3);
484  Matrix1D<double> corner1(3); // Coord: Corners of the blob in the voxel volume
485  Matrix1D<double> gcurrent(3); // Position in g of current point
486  MultidimArray<double> blob_table; // Something like a blobprint but with the values of the
487  // blob in space
488  double d; // Distance between the center
489  // of the blob and a voxel position
490  int id; // index inside the blob value
491  // table for the blob value at a distance d
492  int i;
493  int j;
494  int k; // Index within the blob volume
495  int process; // True if this blob has to be
496  // processed
497  double vol_correction=0; // Correction to apply to the
498  // volume when "projecting" back
500 
501  // Some aliases
502 #define x0 STARTINGX(*vol_voxels)
503 #define xF FINISHINGX(*vol_voxels)
504 #define y0 STARTINGY(*vol_voxels)
505 #define yF FINISHINGY(*vol_voxels)
506 #define z0 STARTINGZ(*vol_voxels)
507 #define zF FINISHINGZ(*vol_voxels)
508 
509 #ifdef DEBUG
510 
511  bool condition = !FORW;
512  if (condition)
513  {
514  (*vol_voxels)().printShape();
515  std::cout << std::endl;
516  std::cout << "x0= " << x0 << " xF= " << xF << std::endl;
517  std::cout << "y0= " << y0 << " yF= " << yF << std::endl;
518  std::cout << "z0= " << z0 << " zF= " << zF << std::endl;
519  std::cout << grid;
520  }
521 #endif
522 
523  // Invert deformation matrix ............................................
524  if (D != nullptr)
525  Dinv = D->inv();
526 
527  // Compute a blob value table ...........................................
528  blob_table.resize((int)(blob->radius*istep + 1));
529  for (size_t i = 0; i < blob_table.xdim; i++)
530  {
531  A1D_ELEM(blob_table, i) = kaiser_value((double)i/istep, blob->radius, blob->alpha, blob->order);
532 
533 #ifdef DEBUG_MORE
534 
535  if (condition)
536  std::cout << "Blob (" << i << ") r=" << (double)i / istep <<
537  " val= " << A1D_ELEM(blob_table, i) << std::endl;
538 #endif
539 
540  }
541 
542  int assigned_slice;
543 
544  do
545  {
546  assigned_slice = -1;
547  do
548  {
549  pthread_mutex_lock(&blobs_conv_mutex);
550  if( slices_processed == z_planes )
551  {
552  pthread_mutex_unlock(&blobs_conv_mutex);
553  return (void*)nullptr;
554  }
555 
556  for(int w = 0 ; w < z_planes ; w++ )
557  {
558  if( slices_status[w]==0 )
559  {
560  slices_status[w] = -1;
561  assigned_slice = w;
563 
564  for( int in = (w-min_separation+1) ; in <= (w+min_separation-1 ) ; in ++ )
565  {
566  if( in != w )
567  {
568  if( ( in >= 0 ) && ( in < z_planes ))
569  {
570  if( slices_status[in] != -1 )
571  slices_status[in]++;
572  }
573  }
574  }
575  break;
576  }
577  }
578 
579  pthread_mutex_unlock(&blobs_conv_mutex);
580  }
581  while( assigned_slice == -1);
582 
583  // Convert the whole grid ...............................................
584  // Corner of the plane defined by Z. These coordinates are in the
585  // universal coord. system
586  Matrix1D<double> aux( grid->lowest );
587  k = (int)(assigned_slice + ZZ( grid->lowest ));
588  ZZ(aux) = k;
589  grid->grid2universe(aux, beginZ);
590 
591  Matrix1D<double> grid_index(3);
592 
593  // Corner of the row defined by Y
594  beginY = beginZ;
595  for (i = (int) YY(grid->lowest); i <= (int) YY(grid->highest); i++)
596  {
597  // First point in the row
598  act_coord = beginY;
599  for (j = (int) XX(grid->lowest); j <= (int) XX(grid->highest); j++)
600  {
601  VECTOR_R3(grid_index, j, i, k);
602 #ifdef DEBUG
603 
604  if (condition)
605  {
606  printf("Dealing blob at (%d,%d,%d) = %f\n", j, i, k, A3D_ELEM(*vol_blobs, k, i, j));
607  std::cout << "Center of the blob "
608  << act_coord.transpose() << std::endl;
609  }
610 #endif
611 
612  // Place act_coord in its right place
613  if (D != nullptr)
614  {
615  M3x3_BY_V3x1(real_position, *D, act_coord);
616 #ifdef DEBUG
617 
618  if (condition)
619  std::cout << "Center of the blob moved to "
620  //ROB, the "moved" coordinates are in
621  // real_position not in act_coord
622  << act_coord.transpose() << std::endl;
623  << real_position.transpose() << std::endl;
624 #endif
625  // ROB This is OK if blob.radius is in Cartesian space as I
626  // think is the case
627  }
628  else
629  real_position = act_coord;
630 
631  // These two corners are also real valued
632  process = true;
633  //ROB
634  //This is OK if blob.radius is in Cartesian space as I think is the case
635  V3_PLUS_CT(corner1, real_position, -blob->radius);
636  V3_PLUS_CT(corner2, real_position, blob->radius);
637 //#ifdef DEFORM_BLOB_WHEN_IN_CRYSTAL
638  //ROB
639  //we do not need this, it is already in Cartesian space
640  //if (D!=NULL)
641  // box_enclosing(corner1,corner2, *D, corner1, corner2);
642 //#endif
643 
644  if (XX(corner1) >= xF)
645  process = false;
646  if (YY(corner1) >= yF)
647  process = false;
648  if (ZZ(corner1) >= zF)
649  process = false;
650  if (XX(corner2) <= x0)
651  process = false;
652  if (YY(corner2) <= y0)
653  process = false;
654  if (ZZ(corner2) <= z0)
655  process = false;
656 #ifdef DEBUG
657 
658  if (!process && condition)
659  std::cout << " It is outside output volume\n";
660 #endif
661 
662  if (!grid->is_interesting(real_position))
663  {
664 #ifdef DEBUG
665  if (process && condition)
666  std::cout << " It is not interesting\n";
667 #endif
668 
669  process = false;
670  }
671 
672 #ifdef DEBUG
673  if (condition)
674  {
675  std::cout << "Corner 1 for this point " << corner1.transpose() << std::endl;
676  std::cout << "Corner 2 for this point " << corner2.transpose() << std::endl;
677  }
678 #endif
679 
680  if (process)
681  {
682  // Clip the corners to the volume borders
683  XX(corner1) = ROUND(CLIP(XX(corner1), x0, xF));
684  YY(corner1) = ROUND(CLIP(YY(corner1), y0, yF));
685  ZZ(corner1) = ROUND(CLIP(ZZ(corner1), z0, zF));
686  XX(corner2) = ROUND(CLIP(XX(corner2), x0, xF));
687  YY(corner2) = ROUND(CLIP(YY(corner2), y0, yF));
688  ZZ(corner2) = ROUND(CLIP(ZZ(corner2), z0, zF));
689 #ifdef DEBUG
690 
691  if (condition)
692  {
693  std::cout << "Clipped and rounded Corner 1 " << corner1.transpose() << std::endl;
694  std::cout << "Clipped and rounded Corner 2 " << corner2.transpose() << std::endl;
695  }
696 #endif
697 
698  if (!FORW)
699  switch (eq_mode)
700  {
701  case VARTK:
702  vol_correction = 0;
703  break;
704  case VMAXARTK:
705  vol_correction = -1e38;
706  break;
707  }
708 
709  // Effectively convert
710  long N_eq;
711  N_eq = 0;
712  for (auto intz = (int)ZZ(corner1); intz <=(int)ZZ(corner2); intz++)
713  for (auto inty = (int)YY(corner1); inty <= (int)YY(corner2); inty++)
714  for (auto intx = (int)XX(corner1); intx <= (int)XX(corner2); intx++)
715  {
716  if (vol_mask != nullptr && A3D_ELEM(*vol_mask, intz, inty, intx)!=0.0)
717  continue;
718 
719  // Compute distance to the center of the blob
720  VECTOR_R3(gcurrent, (double)intx, (double)inty, (double)intz);
721 //#ifdef DEFORM_BLOB_WHEN_IN_CRYSTAL
722  // ROB
723  //if (D!=NULL)
724  // M3x3_BY_V3x1(gcurrent,Dinv,gcurrent);
725 //#endif
726 
727  V3_MINUS_V3(gcurrent, real_position, gcurrent);
728  d = sqrt(XX(gcurrent) * XX(gcurrent) +
729  YY(gcurrent) * YY(gcurrent) +
730  ZZ(gcurrent) * ZZ(gcurrent));
731  if (d > blob->radius)
732  continue;
733  id = (int)(d * istep);
734 #ifdef DEBUG_MORE
735 
736  if (condition)
737  {
738  std::cout << "At (" << intx << ","
739  << inty << "," << intz << ") distance=" << d;
740  std::cout.flush();
741  }
742 #endif
743 
744  // Add at that position the corresponding blob value
745 
746  if (FORW)
747  {
748  A3D_ELEM(*vol_voxels, intz, inty, intx) +=
749  A3D_ELEM(*vol_blobs, k, i, j) *
750  A1D_ELEM(blob_table, id);
751 #ifdef DEBUG_MORE
752 
753  if (condition)
754  {
755  std::cout << " adding " << A3D_ELEM(*vol_blobs, k, i, j)
756  << " * " << A1D_ELEM(blob_table, id) << " = "
757  << A3D_ELEM(*vol_blobs, k, i, j)*
758  A1D_ELEM(blob_table, id) << std::endl;
759  std::cout.flush();
760  }
761 #endif
762  if (vol_corr != nullptr)
763  A3D_ELEM(*vol_corr, intz, inty, intx) +=
764  A1D_ELEM(blob_table, id) * A1D_ELEM(blob_table, id);
765  }
766  else
767  {
768  double contrib = A3D_ELEM(*vol_corr, intz, inty, intx) *
769  A1D_ELEM(blob_table, id);
770  switch (eq_mode)
771  {
772  case VARTK:
773  vol_correction += contrib;
774  N_eq++;
775  break;
776  case VMAXARTK:
777  if (contrib > vol_correction)
778  vol_correction = contrib;
779  break;
780 
781  }
782 #ifdef DEBUG_MORE
783  if (condition)
784  {
785  std::cout << " adding " << A3D_ELEM(*vol_corr, intz, inty, intx)
786  << " * " << A1D_ELEM(blob_table, id) << " = "
787  << contrib << std::endl;
788  std::cout.flush();
789  }
790 #endif
791 
792  }
793  }
794  if (N_eq == 0)
795  N_eq = 1;
796  if (!FORW)
797  {
798  A3D_ELEM(*vol_blobs, k, i, j) += vol_correction / N_eq;
799 #ifdef DEBUG_MORE
800 
801  std::cout << " correction= " << vol_correction << std::endl
802  << " Number of eqs= " << N_eq << std::endl
803  << " Blob after correction= "
804  << A3D_ELEM(*vol_blobs, k, i, j) << std::endl;
805 #endif
806 
807  }
808  }
809 
810  // Prepare for next iteration
811  XX(act_coord) = XX(act_coord) + grid->relative_size * (grid->basis)( 0, 0);
812  YY(act_coord) = YY(act_coord) + grid->relative_size * (grid->basis)( 1, 0);
813  ZZ(act_coord) = ZZ(act_coord) + grid->relative_size * (grid->basis)( 2, 0);
814  }
815  XX(beginY) = XX(beginY) + grid->relative_size * (grid->basis)( 0, 1);
816  YY(beginY) = YY(beginY) + grid->relative_size * (grid->basis)( 1, 1);
817  ZZ(beginY) = ZZ(beginY) + grid->relative_size * (grid->basis)( 2, 1);
818  }
819 
820  pthread_mutex_lock(&blobs_conv_mutex);
821 
822  for( int in = (assigned_slice-min_separation+1) ; in <= (assigned_slice+min_separation-1); in ++ )
823  {
824  if( in != assigned_slice )
825  {
826  if( ( in >= 0 ) && ( in < z_planes))
827  {
828  if( slices_status[in] != -1 )
829  slices_status[in]--;
830  }
831  }
832  }
833 
834  pthread_mutex_unlock(&blobs_conv_mutex);
835  }
836  while(1);
837 
838  return (void*)nullptr;
839 }
840 #undef x0
841 #undef y0
842 #undef z0
843 #undef xF
844 #undef yF
845 #undef zF
846 #undef DEBUG
847 #undef DEBUG_MORE
848 
849 /* Voxel volume shape ------------------------------------------------------ */
850 //#define DEBUG
851 void voxel_volume_shape(const GridVolume &vol_blobs,
852  const struct blobtype &blob, const Matrix2D<double> *D,
853  Matrix1D<int> &corner1, Matrix1D<int> &size)
854 {
855  Matrix1D<double> Gcorner1(3);
856  Matrix1D<double> Gcorner2(3); // lowest and highest coord.
857 
858  corner1.resize(3);
859  size.resize(3);
860 
861  // Look for the lowest and highest volume coordinate
862  vol_blobs.grid().voxel_corners(Gcorner1, Gcorner2, D);
863 
864  // Add blob radius in each direction, and find the furthest integer
865  // samples => compute size
866  Gcorner1 -= blob.radius;
867  Gcorner1.selfCEIL();
868  Gcorner2 += blob.radius;
869  Gcorner2.selfFLOOR();
870 
871  XX(size) = (int)XX(Gcorner2) - (int)XX(Gcorner1) + 1;
872  YY(size) = (int)YY(Gcorner2) - (int)YY(Gcorner1) + 1;
873  ZZ(size) = (int)ZZ(Gcorner2) - (int)ZZ(Gcorner1) + 1;
874 #ifdef DEBUG
875 
876  std::cout << "Gcorner1 " << Gcorner1.transpose() << std::endl;
877  std::cout << "Gcorner2 " << Gcorner2.transpose() << std::endl;
878  std::cout << "Size of voxel volume " << (int)ZZ(size) << " x "
879  << (int)YY(size) << " x " << (int)XX(size) << std::endl;
880 #endif
881 
882 #ifdef NEVER_DEFINED
883  // In principle this limitation has been substituted by a direct
884  // specification of the output volume size, and should no longer
885  // be valid. However it is a beautiful piece of code to be removed
886  // already
887  if (limit != 0 && XX(size) != limit)
888  {
889  double diff = ((double)XX(size) - (double)limit) / 2;
890  if (diff == (int)diff)
891  {
892  Gcorner1 += diff;
893  Gcorner2 -= diff;
894  }
895  else
896  {
897  Gcorner1 += (diff - 0.5);
898  Gcorner2 -= (diff + 0.5);
899  }
900  XX(size) = (int)XX(Gcorner2) - (int)XX(Gcorner1) + 1;
901  YY(size) = (int)YY(Gcorner2) - (int)YY(Gcorner1) + 1;
902  ZZ(size) = (int)ZZ(Gcorner2) - (int)ZZ(Gcorner1) + 1;
903 #ifdef DEBUG
904 
905  std::cout << "Limiting to " << limit << " diff = " << diff << std::endl;
906  std::cout << "New Gcorner1 " << Gcorner1.transpose() << std::endl;
907  std::cout << "New Gcorner2 " << Gcorner2.transpose() << std::endl;
908 #endif
909 
910  }
911 #endif
912 
913  typeCast(Gcorner1, corner1);
914 
915 #ifdef DEBUG
916 
917  std::cout << "Final size of voxel volume " << (int)ZZ(size) << " x "
918  << (int)YY(size) << " x " << (int)XX(size) << std::endl;
919  std::cout << "Corner1= " << corner1.transpose() << std::endl;
920 #endif
921 }
922 #undef DEBUG
923 
924 /* Blobs -> Voxels for a Grid ---------------------------------------------- */
925 //#define DEBUG
926 void blobs2voxels(const GridVolume &vol_blobs,
927  const struct blobtype &blob, MultidimArray<double> *vol_voxels,
928  const Matrix2D<double> *D, int threads, int Zdim, int Ydim, int Xdim)
929 {
930 
931  // Resize and set starting corner .......................................
932  if (Zdim == 0 || Ydim == 0 || Xdim == 0)
933  {
934  Matrix1D<int> size;
935  Matrix1D<int> corner;
936  voxel_volume_shape(vol_blobs, blob, D, corner, size);
937  (*vol_voxels).initZeros(ZZ(size), YY(size), XX(size));
938  STARTINGX(*vol_voxels) = XX(corner);
939  STARTINGY(*vol_voxels) = YY(corner);
940  STARTINGZ(*vol_voxels) = ZZ(corner);
941  }
942  else
943  {
944  (*vol_voxels).initZeros(Zdim, Ydim, Xdim);
945  (*vol_voxels).setXmippOrigin();
946  }
947 
948  auto * th_ids = new pthread_t [threads];
949  auto * threads_d = new ThreadBlobsToVoxels [threads];
950 
951  // Convert each subvolume ...............................................
952  for (size_t i = 0; i < vol_blobs.VolumesNo(); i++)
953  {
954  int min_distance = (int)ceil((2*(vol_blobs.grid(i)).relative_size ) / blob.radius ) + 1;
955  slices_status = new int[(int)(ZZ(vol_blobs.grid(i).highest)-ZZ(vol_blobs.grid(i).lowest)+1)]();
956  slices_processed = 0;
957 
958  for( int c = 0 ; c < threads ; c++ )
959  {
960  threads_d[c].vol_blobs = &(vol_blobs(i)());
961  threads_d[c].grid = &(vol_blobs.grid(i));
962  threads_d[c].blob = &blob;
963  threads_d[c].vol_voxels = vol_voxels;
964  threads_d[c].D = D;
965  threads_d[c].istep = 50;
966  threads_d[c].vol_corr = nullptr;
967  threads_d[c].vol_mask = nullptr;
968  threads_d[c].FORW = true;
969  threads_d[c].eq_mode = VARTK;
970  threads_d[c].thread_id = c;
971  threads_d[c].threads_num = threads;
972  threads_d[c].min_separation = min_distance;
973 
974  pthread_create( (th_ids+c), nullptr, blobs2voxels_SimpleGrid, (void *)(threads_d+c) );
975  }
976 
977  // Wait for threads to finish
978  for( int c = 0 ; c < threads ; c++ )
979  {
980  pthread_join(*(th_ids+c),nullptr);
981  }
982 
983 #ifdef DEBUG
984  std::cout << "Blob grid no " << i << " stats: ";
985  vol_blobs(i)().printStats();
986  std::cout << std::endl;
987  std::cout << "So far vol stats: ";
988  (*vol_voxels).printStats();
989  std::cout << std::endl;
990  Image<double> save;
991  save() = *vol_voxels;
992  save.write((std::string)"PPPvoxels" + integerToString(i));
993 #endif
994 
995  delete[] slices_status;
996  }
997 
998  // Now normalise the resulting volume ..................................
999  double inorm = 1.0 / sum_blob_Grid(blob, vol_blobs.grid(), D); // Aqui tambien hay que multiplicar ****!!!!
1000  FOR_ALL_ELEMENTS_IN_ARRAY3D(*vol_voxels)
1001  A3D_ELEM(*vol_voxels, k, i, j) *= inorm;
1002 
1003  // Set voxels outside interest region to minimum value .................
1004  double R = vol_blobs.grid(0).get_interest_radius();
1005  if (R != -1)
1006  {
1007  double R2 = (R - 6) * (R - 6);
1008 
1009  // Compute minimum value within sphere
1010  double min_val = A3D_ELEM(*vol_voxels, 0, 0, 0);
1011  FOR_ALL_ELEMENTS_IN_ARRAY3D(*vol_voxels)
1012  if (j*j + i*i + k*k <= R2 - 4)
1013  min_val = XMIPP_MIN(min_val, A3D_ELEM(*vol_voxels, k, i, j));
1014 
1015  // Substitute minimum value
1016  R2 = (R - 2) * (R - 2);
1017  FOR_ALL_ELEMENTS_IN_ARRAY3D(*vol_voxels)
1018  if (j*j + i*i + k*k >= R2)
1019  A3D_ELEM(*vol_voxels, k, i, j) = min_val;
1020  }
1021 
1022  delete[] th_ids;
1023  delete[] threads_d;
1024 }
1025 #undef DEBUG
1026 
1027 /* Blobs -> Coefs ---------------------------------------------------------- */
1028 //#define DEBUG
1029 void blobs2space_coefficients(const GridVolume &vol_blobs,
1030  const struct blobtype &blob, MultidimArray<double> *vol_coefs)
1031 {
1032 
1033  // Compute vol_coefs shape
1034  Matrix1D<int> corner1;
1035  Matrix1D<int> size;
1036  voxel_volume_shape(vol_blobs, blob, nullptr, corner1, size);
1037  double g_2 = vol_blobs.grid(0).relative_size / 2;
1038  XX(corner1) = (int)(FLOOR(XX(corner1)) / g_2);
1039  XX(size) = (int)(CEIL(XX(size)) / g_2);
1040  YY(corner1) = (int)(FLOOR(YY(corner1)) / g_2);
1041  YY(size) = (int)(CEIL(YY(size)) / g_2);
1042  ZZ(corner1) = (int)(FLOOR(ZZ(corner1)) / g_2);
1043  ZZ(size) = (int)(CEIL(ZZ(size)) / g_2);
1044  (*vol_coefs).initZeros(ZZ(size), YY(size), XX(size));
1045  STARTINGX(*vol_coefs) = XX(corner1);
1046  STARTINGY(*vol_coefs) = YY(corner1);
1047  STARTINGZ(*vol_coefs) = ZZ(corner1);
1048 
1049  // Set all blob coefficients at the right position
1050  for (size_t n = 0; n < vol_blobs.VolumesNo(); n++)
1051  {
1052  auto ZZ_lowest = (int)ZZ(vol_blobs.grid(n).lowest);
1053  auto YY_lowest = (int)YY(vol_blobs.grid(n).lowest);
1054  auto XX_lowest = (int)XX(vol_blobs.grid(n).lowest);
1055  auto ZZ_highest = (int)ZZ(vol_blobs.grid(n).highest);
1056  auto YY_highest = (int)YY(vol_blobs.grid(n).highest);
1057  auto XX_highest = (int)XX(vol_blobs.grid(n).highest);
1058  for (int k = ZZ_lowest; k <= ZZ_highest; k++)
1059  for (int i = YY_lowest; i <= YY_highest; i++)
1060  for (int j = XX_lowest; j <= XX_highest; j++)
1061  {
1062  Matrix1D<double> grid_index(3);
1063  Matrix1D<double> univ_position(3),
1064  coef_position(3);
1065  VECTOR_R3(grid_index, j, i, k);
1066  vol_blobs.grid(n).grid2universe(grid_index, univ_position);
1067  V3_BY_CT(coef_position, univ_position, 1.0 / g_2);
1068  A3D_ELEM((*vol_coefs),
1069  (int)ZZ(coef_position),
1070  (int)YY(coef_position),
1071  (int)XX(coef_position) ) = A3D_ELEM(vol_blobs(n)(), k, i, j);
1072 #ifdef DEBUG
1073 
1074  std::cout << "Blob value at (" << j << "," << i << ","
1075  << k << ") (" << XX(univ_position)
1076  << "," << YY(univ_position) << ","
1077  << ZZ(univ_position) << ") ("
1078  << XX(coef_position) << "," << YY(coef_position) << ","
1079  << ZZ(coef_position) << ") --> "
1080  << A3D_ELEM(vol_blobs(n)(), (int)k, (int)i, (int)j) << std::endl;
1081 #endif
1082 
1083  }
1084  }
1085 }
1086 #undef DEBUG
1087 
1088 /* Voxels -> blobs --------------------------------------------------------- */
1089 /* This function is very similar to the ART reconstruction process from
1090  projections, look there for another point of view of the ART process. */
1091 #define FORWARD true
1092 #define BACKWARD false
1093 //#define DEBUG
1095  GridVolume &vol_in, // Input solution
1096  GridVolume *vol_out, // Output solution, might be the same
1097  // as the input one
1098  const struct blobtype &blob, // blob
1099  const Matrix2D<double> *D, // deformation matrix
1100  double lambda, // ART lambda
1101  MultidimArray<double> *theo_vol, // Theoretical volume
1102  const MultidimArray<double> *read_vol, // Volume we want to translate to blobs
1103  MultidimArray<double> *corr_vol, // Normalizing volume
1104  const MultidimArray<double> *mask_vol, // Mask volume, 1 if that voxel must
1105  // be counted as a true equation
1106  double &mean_error, // Output mean error
1107  double &max_error, // Output maximum error in a voxel
1108  int eq_mode, // Equation mode
1109  int threads
1110 )
1111 {
1112 
1113  // Resize output volumes ................................................
1114  if (read_vol != nullptr)
1115  {
1116  (*theo_vol).initZeros(*read_vol);
1117  }
1118  else if (mask_vol != nullptr)
1119  {
1120  (*theo_vol).initZeros(*mask_vol);
1121  }
1122  else
1123  {
1125  "ART_voxels2blobs_single_step: Mask and voxel volumes are empty");
1126  }
1127  (*corr_vol).initZeros(*theo_vol);
1128 
1129  auto * th_ids = (pthread_t *)malloc( threads * sizeof( pthread_t));
1130  auto * threads_d = (ThreadBlobsToVoxels *) malloc ( threads * sizeof( ThreadBlobsToVoxels ) );
1131 
1132  // Translate actual blob volume to voxels ...............................
1133  for (size_t i = 0; i < vol_in.VolumesNo(); i++)
1134  {
1135  int min_distance = (int)ceil((2*(vol_in.grid(i)).relative_size ) / blob.radius ) + 1;
1136 
1137  slices_status = new int[(int)(ZZ(vol_in.grid(i).highest)-ZZ(vol_in.grid(i).lowest)+1)]();
1138  slices_processed = 0;
1139 
1140  for( int c = 0 ; c < threads ; c++ )
1141  {
1142  threads_d[c].vol_blobs = &(vol_in(i)());
1143  threads_d[c].grid = &(vol_in.grid(i));
1144  threads_d[c].blob = &blob;
1145  threads_d[c].vol_voxels = theo_vol;
1146  threads_d[c].D = D;
1147  threads_d[c].istep = 50;
1148  threads_d[c].vol_corr = corr_vol;
1149  threads_d[c].vol_mask = mask_vol;
1150  threads_d[c].FORW = true;
1151  threads_d[c].eq_mode = eq_mode;
1152  threads_d[c].thread_id = c;
1153  threads_d[c].threads_num = threads;
1154  threads_d[c].min_separation = min_distance;
1155 
1156  pthread_create( (th_ids+c), nullptr, blobs2voxels_SimpleGrid, (void *)(threads_d+c) );
1157  }
1158 
1159  // Wait for threads to finish
1160  for( int c = 0 ; c < threads ; c++ )
1161  {
1162  pthread_join(*(th_ids+c),nullptr);
1163  }
1164 
1165  delete[] slices_status;
1166  // blobs2voxels_SimpleGrid(vol_in(i)(), vol_in.grid(i), blob, theo_vol, D,
1167  // 50, corr_vol, mask_vol, FORWARD, eq_mode);
1168 #ifdef DEBUG
1169 
1170  std::cout << "Blob grid no " << i << " stats: ";
1171  vol_in(i)().printStats();
1172  std::cout << std::endl;
1173  std::cout << "So far vol stats: ";
1174  (*theo_vol)().printStats();
1175  std::cout << std::endl;
1176 #endif
1177 
1178  }
1179 
1180  // Now normalise the resulting volume ..................................
1181  double norm = sum_blob_Grid(blob, vol_in.grid(), D); // Aqui tambien hay que multiplicar ****!!!!
1182  FOR_ALL_ELEMENTS_IN_ARRAY3D(*theo_vol)
1183  A3D_ELEM(*theo_vol, k, i, j) /= norm;
1184 
1185 #ifdef DEBUG
1186 
1187  Image<double> save, save2;
1188  save() = *theo_vol;
1189  save.write("PPPtheovol.vol");
1190  std::cout << "Theo stats:";
1191  save().printStats();
1192  std::cout << std::endl;
1193  save() = *corr_vol;
1194  save.write("PPPcorr2vol.vol");
1195  save2().resize(save());
1196 #endif
1197 
1198  // Compute differences ..................................................
1199  mean_error = 0;
1200  double read_val;
1201  if (read_vol != nullptr)
1202  read_val = A3D_ELEM(*read_vol, 0, 0, 0);
1203  else
1204  read_val = 0;
1205  max_error = ABS(read_val - A3D_ELEM(*theo_vol, 0, 0, 0));
1206 
1207  double diff;
1208  int N = 0;
1209  FOR_ALL_ELEMENTS_IN_ARRAY3D(*theo_vol)
1210  {
1211  // Compute difference volume and error
1212  if (read_vol != nullptr)
1213  read_val = A3D_ELEM(*read_vol, k, i, j);
1214  else
1215  read_val = 0;
1216 
1217  if (mask_vol == nullptr)
1218  {
1219  diff = read_val - A3D_ELEM(*theo_vol, k, i, j);
1220  N++;
1221  }
1222  else
1223  if (A3D_ELEM(*mask_vol, k, i, j) == 1)
1224  {
1225  diff = read_val - A3D_ELEM(*theo_vol, k, i, j);
1226  N++;
1227  }
1228  else
1229  diff = 0;
1230 
1231  max_error = XMIPP_MAX(max_error, ABS(diff));
1232  mean_error += diff * diff;
1233 #ifdef DEBUG
1234 
1235  save(k, i, j) = diff;
1236  save2(k, i, j) = read_val;
1237 #endif
1238 
1239 
1240  // Compute the correction volume
1241  if (ABS(A3D_ELEM(*corr_vol, k, i, j)) < 1e-2)
1242  A3D_ELEM(*corr_vol, k, i, j) = SGN(A3D_ELEM(*corr_vol, k, i, j));
1243  A3D_ELEM(*corr_vol, k, i, j) =
1244  lambda * diff / A3D_ELEM(*corr_vol, k, i, j);
1245  }
1246 #ifdef DEBUG
1247  save.write("PPPdiffvol.vol");
1248  std::cout << "Diff stats:";
1249  save().printStats();
1250  std::cout << std::endl;
1251  save2.write("PPPreadvol.vol");
1252  std::cout << "Read stats:";
1253  save2().printStats();
1254  std::cout << std::endl;
1255  save() = *corr_vol;
1256  save.write("PPPcorrvol.vol");
1257  std::cout << "Corr stats:";
1258  save().printStats();
1259  std::cout << std::endl;
1260 #endif
1261 
1262  mean_error /= XMIPP_MAX(N, 1); // At worst, divided by 1
1263 
1264  // Backprojection of correction volume ..................................
1265  for (size_t i = 0; i < vol_in.VolumesNo(); i++)
1266  {
1267  slices_status = new int[(int)(ZZ(vol_out->grid(i).highest)-ZZ(vol_out->grid(i).lowest)+1)]();
1268  slices_processed = 0;
1269 
1270  for( int c = 0 ; c < threads ; c++ )
1271  {
1272  threads_d[c].vol_blobs = &((*vol_out)(i)());
1273  threads_d[c].grid = &(vol_out->grid(i));
1274  threads_d[c].blob = &blob;
1275  threads_d[c].vol_voxels = theo_vol;
1276  threads_d[c].D = D;
1277  threads_d[c].istep = 50;
1278  threads_d[c].vol_corr = corr_vol;
1279  threads_d[c].vol_mask = mask_vol;
1280  threads_d[c].FORW = false;
1281  threads_d[c].eq_mode = eq_mode;
1282  threads_d[c].thread_id = c;
1283  threads_d[c].threads_num = threads;
1284  threads_d[c].min_separation = 1;
1285 
1286  pthread_create( (th_ids+c), nullptr, blobs2voxels_SimpleGrid, (void *)(threads_d+c) );
1287  }
1288 
1289  // Wait for threads to finish
1290  for( int c = 0 ; c < threads ; c++ )
1291  {
1292  pthread_join(*(th_ids+c), nullptr);
1293  }
1294  delete[] slices_status;
1295  // blobs2voxels_SimpleGrid((*vol_out)(i)(), (*vol_out).grid(i), blob,
1296  // theo_vol, D, 50, corr_vol, mask_vol, BACKWARD, eq_mode);
1297 #ifdef DEBUG
1298 
1299  std::cout << "Blob grid no " << i << " stats: ";
1300  vol_in(i)().printStats();
1301  std::cout << std::endl;
1302 #endif
1303 
1304  }
1305  free(threads_d);
1306  free(th_ids);
1307 #ifdef DEBUG
1308  char c;
1309  std::cout << "Press any key to continue\n";
1310  std::cin >> c;
1311 #endif
1312 }
1313 #undef DEBUG
1314 
1315 //#define DEBUG
1316 void voxels2blobs(const MultidimArray<double> *vol_voxels,
1317  const struct blobtype &blob,
1318  GridVolume &vol_blobs, int grid_type, double grid_relative_size,
1319  double lambda, const MultidimArray<double> *vol_mask,
1320  const Matrix2D<double> *D, double final_error_change,
1321  int tell, double R, int threads)
1322 {
1323  Image<double> theo_vol;
1324  Image<double> corr_vol;
1325  double mean_error;
1326  double mean_error_1;
1327  double max_error;
1328  int it = 1;
1329 
1330  tell = SHOW_CONVERSION;
1331 
1332  // Resize output volume .................................................
1333  Grid grid_blobs;
1334  if (R == -1)
1335  {
1336  Matrix1D<double> corner1(3);
1337  Matrix1D<double> corner2(3);
1338  XX(corner1) = STARTINGX(*vol_voxels);
1339  YY(corner1) = STARTINGY(*vol_voxels);
1340  ZZ(corner1) = STARTINGZ(*vol_voxels);
1341  XX(corner2) = FINISHINGX(*vol_voxels);
1342  YY(corner2) = FINISHINGY(*vol_voxels);
1343  ZZ(corner2) = FINISHINGZ(*vol_voxels);
1344 
1345  switch (grid_type)
1346  {
1347  case CC:
1348  grid_blobs = Create_CC_grid(grid_relative_size, corner1, corner2);
1349  break;
1350  case FCC:
1351  grid_blobs = Create_FCC_grid(grid_relative_size, corner1, corner2);
1352  break;
1353  case BCC:
1354  grid_blobs = Create_BCC_grid(grid_relative_size, corner1, corner2);
1355  break;
1356  }
1357  }
1358  else
1359 {
1360  switch (grid_type)
1361  {
1362  case CC:
1363  grid_blobs = Create_CC_grid(grid_relative_size, R);
1364  break;
1365  case FCC:
1366  grid_blobs = Create_FCC_grid(grid_relative_size, R);
1367  break;
1368  case BCC:
1369  grid_blobs = Create_BCC_grid(grid_relative_size, R);
1370  break;
1371  }
1372  }
1373  vol_blobs.adapt_to_grid(grid_blobs);
1374 
1375  // Convert ..............................................................
1376  std::cout << "Converting voxel volume to blobs\n";
1377  ART_voxels2blobs_single_step(vol_blobs, &vol_blobs, blob, D, lambda,
1378  &(theo_vol()), vol_voxels,
1379  &(corr_vol()), vol_mask, mean_error_1, max_error, VARTK, threads);
1380  if (tell && SHOW_CONVERSION)
1381  std::cout << " Finished iteration: " << it++
1382  << " Mean Error= " << mean_error_1
1383  << " Max_Error= " << max_error
1384  << std::endl;
1385  else
1386  std::cout << "0%";
1387  std::cout.flush();
1388 #ifdef DEBUG
1389 
1390  theo_vol.write("PPPtheo.vol");
1391  corr_vol.write("PPPcorr.vol");
1392  std::cout << "Press any key\n";
1393  char c;
1394  std::cin >> c;
1395 #endif
1396 
1397  double change;
1398  bool end_condition;
1399  do
1400 {
1401  ART_voxels2blobs_single_step(vol_blobs, &vol_blobs, blob, D, lambda,
1402  &(theo_vol()), vol_voxels,
1403  &(corr_vol()), vol_mask, mean_error, max_error, VARTK);
1404 #ifdef DEBUG
1405 
1406  theo_vol.write("PPPtheo.vol");
1407  corr_vol.write("PPPcorr.vol");
1408  std::cout << "Press any key\n";
1409  char c;
1410  std::cin >> c;
1411 #endif
1412 
1413  change = ABS(mean_error - mean_error_1) / mean_error_1;
1414  mean_error_1 = mean_error;
1415  if (tell && SHOW_CONVERSION)
1416  std::cout << " Finished iteration: " << it++
1417  << " Mean Error= " << mean_error
1418  << " Max_Error= " << max_error
1419  << std::endl;
1420  else
1421  {
1422  printf("\r");
1423  std::cout << 100 - change << "%";
1424  }
1425  std::cout.flush();
1426  end_condition = change <= final_error_change;
1427  }
1428  while (!end_condition);
1429  std::cout << std::endl;
1430 }
1431 #undef DEBUG
double kaiser_value(double r, double a, double alpha, int m)
Definition: blobs.cpp:37
void voxel_volume_shape(const GridVolume &vol_blobs, const struct blobtype &blob, const Matrix2D< double > *D, Matrix1D< int > &corner1, Matrix1D< int > &size)
Definition: blobs.cpp:851
#define A2D_ELEM(v, i, j)
void universe2grid(const Matrix1D< double > &uv, Matrix1D< double > &gv) const
Definition: grids.h:349
double alpha
Smoothness parameter.
Definition: blobs.h:121
void resize(size_t Ndim, size_t Zdim, size_t Ydim, size_t Xdim, bool copy=true)
#define XMIPP_MAX(x, y)
Definition: xmipp_macros.h:193
Matrix1D< double > highest
Definition: grids.h:161
double module() const
Definition: matrix1d.h:983
__device__ float bessi1(float x)
constexpr int SHOW_CONVERSION
Definition: blobs.h:353
#define FINISHINGX(v)
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
double optimal_FCC_grid_relative_size(struct blobtype b)
Definition: blobs.cpp:356
void blobs2voxels(const GridVolume &vol_blobs, const struct blobtype &blob, MultidimArray< double > *vol_voxels, const Matrix2D< double > *D, int threads, int Zdim, int Ydim, int Xdim)
Definition: blobs.cpp:926
SimpleGrid Create_CC_grid(double relative_size, const Matrix1D< double > &corner1, const Matrix1D< double > &corner2, const Matrix1D< double > &origin)
Definition: grids.cpp:196
doublereal * c
void init(int _umin, int _umax, int _uistep, int _vmin, int _vmax, int _vistep, int _wmin=0, int _wmax=0, int _wistep=1)
#define V3_PLUS_CT(a, b, c)
Definition: matrix1d.h:220
void grid2universe(const Matrix1D< double > &gv, Matrix1D< double > &uv) const
Definition: grids.h:318
void sqrt(Image< double > &op)
size_t GridsNo() const
Definition: grids.h:536
void ART_voxels2blobs_single_step(GridVolume &vol_in, GridVolume *vol_out, const struct blobtype &blob, const Matrix2D< double > *D, double lambda, MultidimArray< double > *theo_vol, const MultidimArray< double > *read_vol, MultidimArray< double > *corr_vol, const MultidimArray< double > *mask_vol, double &mean_error, double &max_error, int eq_mode, int threads)
Definition: blobs.cpp:1094
Matrix1D< double > vectorR3(double x, double y, double z)
Definition: matrix1d.cpp:892
__device__ float bessi4(float x)
constexpr int VARTK
Definition: blobs.h:378
void write(const FileName &name="", size_t select_img=ALL_IMAGES, bool isStack=false, int mode=WRITE_OVERWRITE, CastWriteMode castMode=CW_CAST, int _swapWrite=0)
void blobs2space_coefficients(const GridVolume &vol_blobs, const struct blobtype &blob, MultidimArray< double > *vol_coefs)
Definition: blobs.cpp:1029
The matrix is empty.
Definition: xmipp_error.h:151
#define V3_MINUS_V3(a, b, c)
Definition: matrix1d.h:202
#define A1D_ELEM(v, i)
pthread_mutex_t blobs_conv_mutex
Definition: blobs.cpp:31
void inv(Matrix2D< T > &result) const
Definition: matrix2d.cpp:663
void read_vol(char *vol_file, double *width, double *origx, double *origy, double *origz, unsigned *extx, unsigned *exty, unsigned *extz, double **phi)
Definition: lib_vio.cpp:25
doublereal * w
double blob_freq_zero(struct blobtype b)
Definition: blobs.cpp:330
#define zF
String integerToString(int I, int _width, char fill_with)
#define z0
Definition: grids.h:479
#define FINISHINGZ(v)
T norm(const std::vector< T > &v)
Definition: vector_ops.h:399
#define CC
CC identifier.
Definition: grids.h:585
double i_nph(int n, double x)
Definition: blobs.cpp:270
String floatToString(float F, int _width, int _prec)
bool is_interesting(const Matrix1D< double > &uv) const
Definition: grids.h:361
Matrix1D< double > lowest
Definition: grids.h:158
Matrix2D< double > basis
Definition: grids.h:148
#define STARTINGX(v)
doublereal * x
#define i
ql0001_ & k(htemp+1),(cvec+1),(atemp+1),(bj+1),(bl+1),(bu+1),(x+1),(clamda+1), &iout, infoqp, &zero,(w+1), &lenw,(iw+1), &leniw, &glob_grd.epsmac
doublereal * d
Matrix1D< T > transpose() const
Definition: matrix1d.cpp:644
int * slices_status
Definition: blobs.cpp:33
#define STARTINGY(v)
#define BCC
BCC identifier.
Definition: grids.h:589
#define CLIP(x, x0, xF)
Definition: xmipp_macros.h:260
void adapt_to_grid(const Grid &_grid)
Definition: grids.h:838
#define A3D_ELEM(V, k, i, j)
__device__ float bessi0(float x)
#define FOR_ALL_ELEMENTS_IN_ARRAY3D(V)
__device__ float bessi3(float x)
#define V3_BY_CT(a, b, c)
Definition: matrix1d.h:238
doublereal * b
void box_enclosing(const Matrix1D< double > &v0, const Matrix1D< double > &vF, const Matrix2D< double > &V, Matrix1D< double > &corner1, Matrix1D< double > &corner2)
Definition: geometry.cpp:366
size_t VolumesNo() const
Definition: grids.h:1003
double sum_blob_Grid(const struct blobtype &blob, const Grid &grid, const Matrix2D< double > *D)
Definition: blobs.cpp:320
#define FLOOR(x)
Definition: xmipp_macros.h:240
#define y0
double * lambda
#define x0
#define XX(v)
Definition: matrix1d.h:85
void voxels2blobs(const MultidimArray< double > *vol_voxels, const struct blobtype &blob, GridVolume &vol_blobs, int grid_type, double grid_relative_size, double lambda, const MultidimArray< double > *vol_mask, const Matrix2D< double > *D, double final_error_change, int tell, double R, int threads)
Definition: blobs.cpp:1316
#define CEIL(x)
Definition: xmipp_macros.h:225
double blob_ops(double w, struct blobtype b)
Definition: blobs.cpp:342
#define FCC
FCC identifier.
Definition: grids.h:587
int in
double bessi1_5(double x)
Incorrect argument received.
Definition: xmipp_error.h:113
blobtype best_blob(double alpha_0, double alpha_F, double inc_alpha, double a_0, double a_F, double inc_a, double w, double *target_att, int target_length)
Definition: blobs.cpp:363
double blob_att(double w, struct blobtype b)
Definition: blobs.cpp:336
#define IMG2OVER(IO, iv, iu, v, u)
void resize(size_t Xdim, bool copy=true)
Definition: matrix1d.h:410
#define blob_Fourier_val(w, blob)
Definition: blobs.h:174
__device__ float bessi2(float x)
#define ABS(x)
Definition: xmipp_macros.h:142
free((char *) ob)
#define ROUND(x)
Definition: xmipp_macros.h:210
#define xF
double relative_size
Measuring unit in the grid coordinate system.
Definition: grids.h:163
#define XMIPP_MIN(x, y)
Definition: xmipp_macros.h:181
#define j
#define M3x3_BY_V3x1(a, M, b)
Definition: matrix2d.h:170
void footprint_blob(ImageOver &blobprint, const struct blobtype &blob, int istep, int normalise)
Definition: blobs.cpp:417
double kaiser_Fourier_value(double w, double a, double alpha, int m)
Definition: blobs.cpp:144
double bessj1_5(double x)
#define YY(v)
Definition: matrix1d.h:93
int m
double i_n(int n, double x)
Definition: blobs.cpp:244
Grid Create_FCC_grid(double relative_size, const Matrix1D< double > &corner1, const Matrix1D< double > &corner2)
Definition: grids.cpp:306
void selfFLOOR()
Definition: matrix1d.cpp:499
Grid Create_BCC_grid(double relative_size, const Matrix1D< double > &corner1, const Matrix1D< double > &corner2)
Definition: grids.cpp:251
double bessj3_5(double x)
#define FINISHINGY(v)
#define blob_proj(r, blob)
Definition: blobs.h:161
void typeCast(const Matrix1D< T1 > &v1, Matrix1D< T2 > &v2)
Definition: matrix1d.h:1227
const SimpleGrid & grid(size_t n) const
Definition: grids.h:978
double sum_blob_SimpleGrid(const struct blobtype &blob, const SimpleGrid &grid, const Matrix2D< double > *D)
Definition: blobs.cpp:175
#define VECTOR_R3(v, x, y, z)
Definition: matrix1d.h:124
int order
Derivation order and Bessel function order.
Definition: blobs.h:118
int slices_processed
Definition: blobs.cpp:34
double in_zeroarg(int n)
Definition: blobs.cpp:294
double bessi3_5(double x)
double kaiser_proj(double s, double a, double alpha, int m)
Definition: blobs.cpp:94
double inph_zeroarg(int n)
Definition: blobs.cpp:307
double get_interest_radius() const
Get reconstruction radius.
Definition: grids.h:268
#define PI
Definition: tools.h:43
double optimal_CC_grid_relative_size(struct blobtype b)
Definition: blobs.cpp:348
size_t fact(int num)
Incorrect value received.
Definition: xmipp_error.h:195
double optimal_BCC_grid_relative_size(struct blobtype b)
Definition: blobs.cpp:352
#define SGN(x)
Definition: xmipp_macros.h:155
#define yF
#define STARTINGZ(v)
double radius
Spatial radius in Universal System units.
Definition: blobs.h:115
int * n
#define ZZ(v)
Definition: matrix1d.h:101
doublereal * a
constexpr int VMAXARTK
Definition: blobs.h:379
void selfCEIL()
Definition: matrix1d.cpp:476
double basvolume(double a, double alpha, int m, int n)
Definition: blobs.cpp:215
#define IMGPIXEL(I, i, j)
#define SPEED_UP_temps012
Definition: xmipp_macros.h:403
void * blobs2voxels_SimpleGrid(void *data)
Definition: blobs.cpp:452