reco.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <ufo/ufo.h>
  4. #include "reco.h"
  5. #include "io.h"
  6. typedef struct {
  7. UfoPluginManager *pm;
  8. UfoTaskGraph *graph;
  9. UfoTaskNode *pad;
  10. UfoTaskNode *ramp;
  11. UfoTaskNode *fft1;
  12. UfoTaskNode *fft2;
  13. UfoTaskNode *ifft;
  14. UfoTaskNode *conv;
  15. UfoTaskNode *reco;
  16. UfoTaskNode *writer;
  17. /* interactive */
  18. guint current;
  19. UfoTaskNode *output;
  20. UfoTaskNode *input;
  21. Params *params;
  22. } LaminoData;
  23. static void
  24. print_dots (gpointer user)
  25. {
  26. static int n = 0;
  27. if ((n++ % 10) == 0)
  28. g_print (".");
  29. }
  30. static void
  31. check (GError *error)
  32. {
  33. if (error != NULL) {
  34. if (error->message != NULL)
  35. g_printerr ("%s", error->message);
  36. exit (1);
  37. }
  38. }
  39. static UfoTaskNode *
  40. make_task (UfoPluginManager *pm, const gchar *name)
  41. {
  42. GError *error = NULL;
  43. UfoTaskNode *task;
  44. task = ufo_plugin_manager_get_task (pm, name, &error);
  45. check (error);
  46. return task;
  47. }
  48. static guint
  49. next_power_of_two (guint32 x)
  50. {
  51. --x;
  52. x |= x >> 1;
  53. x |= x >> 2;
  54. x |= x >> 4;
  55. x |= x >> 8;
  56. x |= x >> 16;
  57. return x + 1;
  58. }
  59. gboolean
  60. params_okay (Params *params)
  61. {
  62. return params->width != 0 &&
  63. params->height != 0 &&
  64. params->num_radios != 0 &&
  65. params->radios != NULL &&
  66. params->theta < G_MAXDOUBLE &&
  67. params->px < G_MAXDOUBLE &&
  68. params->py < G_MAXDOUBLE;
  69. }
  70. gboolean
  71. with_flat_field_correction (Params *params)
  72. {
  73. return params->darks != NULL && params->flats != NULL;
  74. }
  75. static LaminoData *
  76. reco_graph_new (Params *params)
  77. {
  78. LaminoData *data;
  79. guint xl, xr, yt, yb;
  80. guint padded_width;
  81. guint padded_height;
  82. gdouble theta_rad;
  83. gdouble angle_step;
  84. guint fwidth;
  85. data = g_malloc0 (sizeof (LaminoData));
  86. data->params = params;
  87. data->pm = ufo_plugin_manager_new ();
  88. data->graph = UFO_TASK_GRAPH (ufo_task_graph_new ());
  89. data->pad = make_task (data->pm, "padding-2d");
  90. data->ramp = make_task (data->pm, "lamino-ramp");
  91. data->fft1 = make_task (data->pm, "fft");
  92. data->fft2 = make_task (data->pm, "fft");
  93. data->ifft = make_task (data->pm, "ifft");
  94. data->conv = make_task (data->pm, "lamino-conv");
  95. data->reco = make_task (data->pm, "lamino-bp");
  96. data->writer = make_task (data->pm, "writer");
  97. fwidth = ((guint) params->px) * 2;
  98. padded_width = next_power_of_two ((guint32) params->width + 1);
  99. padded_height = next_power_of_two ((guint32) params->height + 1);
  100. xl = xr = (padded_width - params->width) / 2;
  101. yt = yb = (padded_height - params->height) / 2;
  102. angle_step = (G_PI * 2.0) / params->num_radios * params->radio_step;
  103. theta_rad = params->theta / 360. * G_PI * 2;
  104. info ("Axis x=%.1f y=%.1f variation=%.1f\n",
  105. params->px, params->py, params->px_variation);
  106. info ("Lamino theta=%.3f tau=%.3f step=%.5f\n",
  107. theta_rad, params->tau, angle_step);
  108. info ("Padding size=[%d %d] (xl=%d xr=%d yt=%d yb=%d)\n",
  109. padded_width, padded_height, xl, xr, yt, yb);
  110. info ("Volume origin=[%.1f %.1f %.1f] size=[%d %d %d]\n",
  111. params->v_origin[0], params->v_origin[1], params->v_origin[2],
  112. params->v_size[0], params->v_size[1], params->v_size[2]);
  113. g_object_set (data->fft1, "dimensions", 2, NULL);
  114. g_object_set (data->fft2, "dimensions", 2, NULL);
  115. g_object_set (data->ifft, "dimensions", 2, NULL);
  116. g_object_set (data->pad,
  117. "xl", xl, "xr", xr,
  118. "yt", yt, "yb", yb,
  119. "mode", "brep",
  120. NULL);
  121. g_object_set (data->ramp,
  122. "width", padded_width,
  123. "height", padded_height,
  124. "theta", theta_rad,
  125. "tau", params->tau,
  126. "fwidth", fwidth,
  127. NULL);
  128. g_object_set (data->reco,
  129. "angle-step", angle_step,
  130. "theta", theta_rad,
  131. "psi", params->psi,
  132. "proj-ox", params->px + xl,
  133. "proj-oy", params->py + yt,
  134. "proj-ox-variation", params->px_variation,
  135. "vol-ox", params->v_size[0] / 2 + params->v_origin[0],
  136. "vol-oy", params->v_size[1] / 2 + params->v_origin[1],
  137. "vol-oz", params->v_size[2] / 2 + params->v_origin[2],
  138. "vol-sx", params->v_size[0],
  139. "vol-sy", params->v_size[1],
  140. "vol-sz", params->v_size[2],
  141. "vol-z-spacing", params->z_spacing,
  142. NULL);
  143. g_object_set (data->writer,
  144. "filename", params->output,
  145. NULL);
  146. ufo_task_graph_connect_nodes (data->graph, data->pad, data->fft1);
  147. ufo_task_graph_connect_nodes (data->graph, data->ramp, data->fft2);
  148. ufo_task_graph_connect_nodes_full (data->graph, data->fft1, data->conv, 0);
  149. ufo_task_graph_connect_nodes_full (data->graph, data->fft2, data->conv, 1);
  150. ufo_task_graph_connect_nodes (data->graph, data->conv, data->ifft);
  151. ufo_task_graph_connect_nodes (data->graph, data->ifft, data->reco);
  152. ufo_task_graph_connect_nodes (data->graph, data->reco, data->writer);
  153. return data;
  154. }
  155. static void
  156. reco_graph_free (LaminoData *data)
  157. {
  158. g_object_unref (data->pm);
  159. g_object_unref (data->graph);
  160. g_object_unref (data->pad);
  161. g_object_unref (data->fft1);
  162. g_object_unref (data->fft2);
  163. /* g_object_unref (conv); */
  164. g_object_unref (data->reco);
  165. g_object_unref (data->writer);
  166. }
  167. static void
  168. update_reader (UfoTaskNode *reader, Params *params)
  169. {
  170. g_object_set (reader,
  171. "path", params->radios,
  172. "end", params->num_radios - 1,
  173. "step", params->radio_step,
  174. NULL);
  175. }
  176. static void
  177. show_time (UfoBaseScheduler *sched)
  178. {
  179. gdouble time = 0.0;
  180. g_object_get (sched, "time", &time, NULL);
  181. g_print ("\n");
  182. info ("Finished in %3.3fs\n", time);
  183. }
  184. void
  185. run_simple_reconstruction (Params *params, gchar **argv)
  186. {
  187. LaminoData *data;
  188. UfoBaseScheduler *sched = NULL;
  189. UfoTaskNode *radio_reader = NULL;
  190. UfoTaskNode *dark_reader = NULL;
  191. UfoTaskNode *flat_reader = NULL;
  192. UfoTaskNode *ffc = NULL;
  193. GError *error = NULL;
  194. if (!params_okay (params)) {
  195. err ("Parameters missing.\n");
  196. return;
  197. }
  198. data = reco_graph_new (params);
  199. g_signal_connect (data->reco, "processed", G_CALLBACK (print_dots), NULL);
  200. /* Set up input */
  201. radio_reader = make_task (data->pm, "reader");
  202. update_reader (radio_reader, params);
  203. if (with_flat_field_correction (params)) {
  204. flat_reader = make_task (data->pm, "reader");
  205. dark_reader = make_task (data->pm, "reader");
  206. ffc = make_task (data->pm, "flat-field-correction");
  207. g_object_set (ffc,
  208. "dark-scale", params->dark_scale,
  209. "absorption-correction", TRUE,
  210. NULL);
  211. g_object_set (flat_reader, "path", params->flats, NULL);
  212. g_object_set (dark_reader, "path", params->darks, NULL);
  213. ufo_task_graph_connect_nodes_full (data->graph, radio_reader, ffc, 0);
  214. ufo_task_graph_connect_nodes_full (data->graph, dark_reader, ffc, 1);
  215. ufo_task_graph_connect_nodes_full (data->graph, flat_reader, ffc, 2);
  216. ufo_task_graph_connect_nodes (data->graph, ffc, data->pad);
  217. }
  218. else {
  219. warn ("> No flat/dark field correction\n");
  220. ufo_task_graph_connect_nodes (data->graph, radio_reader, data->pad);
  221. }
  222. /* Run reconstruction */
  223. info ("Processing ");
  224. sched = UFO_BASE_SCHEDULER (ufo_scheduler_new ());
  225. ufo_base_scheduler_run (sched, data->graph, &error);
  226. check (error);
  227. show_time (sched);
  228. /* Clean up */
  229. reco_graph_free (data);
  230. g_object_unref (sched);
  231. g_object_unref (radio_reader);
  232. if (with_flat_field_correction (params)) {
  233. g_object_unref (ffc);
  234. g_object_unref (flat_reader);
  235. g_object_unref (dark_reader);
  236. }
  237. }
  238. static void
  239. move_data (UfoTaskNode *reader, LaminoData *data)
  240. {
  241. UfoBuffer *buffer;
  242. gfloat *mem;
  243. gsize size;
  244. static int n = 0;
  245. /* FIXME: we miss one projection */
  246. /* We will block here, even though reader sent the "generated" signal */
  247. if (data->current == 0) {
  248. data->current++;
  249. return;
  250. }
  251. buffer = ufo_output_task_get_output_buffer (UFO_OUTPUT_TASK (data->output));
  252. mem = ufo_buffer_get_host_array (buffer, NULL);
  253. size = ufo_buffer_get_size (buffer);
  254. memcpy (data->params->cache + (data->current - 1) * size, mem, size);
  255. ufo_output_task_release_output_buffer (UFO_OUTPUT_TASK (data->output), buffer);
  256. data->current++;
  257. if ((n++ % 10) == 0)
  258. g_print (".");
  259. }
  260. static gpointer
  261. input_thread (LaminoData *data)
  262. {
  263. UfoBuffer *buffer;
  264. UfoRequisition req;
  265. guint current;
  266. current = 0;
  267. req.n_dims = 2;
  268. req.dims[0] = data->params->width;
  269. req.dims[1] = data->params->height;
  270. buffer = ufo_buffer_new (&req, NULL);
  271. while (current < data->params->num_radios) {
  272. gfloat *mem;
  273. gsize size;
  274. mem = ufo_buffer_get_host_array (buffer, NULL);
  275. size = ufo_buffer_get_size (buffer);
  276. memcpy (mem, data->params->cache + current * size, size);
  277. ufo_input_task_release_input_buffer (UFO_INPUT_TASK (data->input), buffer);
  278. current++;
  279. buffer = ufo_input_task_get_input_buffer (UFO_INPUT_TASK (data->input));
  280. if ((current % 10) == 0)
  281. g_print (".");
  282. }
  283. ufo_input_task_stop (UFO_INPUT_TASK (data->input));
  284. return NULL;
  285. }
  286. void
  287. run_cached_reconstruction (Params *params, gchar **argv)
  288. {
  289. LaminoData *data;
  290. GThread *thread;
  291. UfoBaseScheduler *sched = NULL;
  292. GError *error = NULL;
  293. data = reco_graph_new (params);
  294. if (params->cache == NULL) {
  295. UfoTaskGraph *read_graph;
  296. UfoTaskNode *radio_reader;
  297. UfoBaseScheduler *sched;
  298. GError *error = NULL;
  299. params->cache = g_malloc (((gsize) params->num_radios) * ((gsize) params->width) * ((gsize) params->height) * sizeof (gfloat));
  300. /* fill the cache and reconstruct simultaneously */
  301. radio_reader = make_task (data->pm, "reader");
  302. update_reader (radio_reader, params);
  303. data->output = UFO_TASK_NODE (ufo_output_task_new (2));
  304. read_graph = UFO_TASK_GRAPH (ufo_task_graph_new ());
  305. ufo_task_graph_connect_nodes (read_graph, radio_reader, data->output);
  306. g_signal_connect (radio_reader, "generated", G_CALLBACK (move_data), data);
  307. data->current = 0;
  308. sched = UFO_BASE_SCHEDULER (ufo_scheduler_new ());
  309. info ("Reading ");
  310. ufo_base_scheduler_run (sched, read_graph, &error);
  311. check (error);
  312. g_print ("\n");
  313. g_object_unref (radio_reader);
  314. g_object_unref (read_graph);
  315. g_object_unref (data->output);
  316. }
  317. data->current = 0;
  318. data->input = UFO_TASK_NODE (ufo_input_task_new ());
  319. ufo_task_graph_connect_nodes (data->graph, data->input, data->pad);
  320. /* Run reconstruction */
  321. info ("Processing ");
  322. thread = g_thread_new (NULL, (GThreadFunc) input_thread, data);
  323. sched = UFO_BASE_SCHEDULER (ufo_scheduler_new ());
  324. ufo_base_scheduler_run (sched, data->graph, &error);
  325. check (error);
  326. show_time (sched);
  327. g_thread_unref (thread);
  328. g_object_unref (data->input);
  329. reco_graph_free (data);
  330. }