parse_func_mex.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. /* parse_func.cpp */
  2. /* Checks the validity of the arguments input to the convolution routine and
  3. transfers the Matlab-style arguments to the C structures defined in defs.h. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <malloc.h>
  7. #include <math.h>
  8. #include <string.h>
  9. #include "mex.h"
  10. #include "defs.h"
  11. void check_MATLAB_KERNELS(const mxArray *Kernels)
  12. /* Ensures that the MATLAB_KERNELS structure has the following format:
  13. MATLAB_KERNEL =
  14. radii: [1xNradii float]
  15. angles: [1xNangles float]
  16. energies: [1xNenergies float]
  17. primary: [Nradii x Nangles x Nenergies float]
  18. first_scatter: [Nradii x Nangles x Nenergies float]
  19. second_scatter: [Nradii x Nangles x Nenergies float]
  20. multiple_scatter: [Nradii x Nangles x Nenergies float]
  21. brem_annih: [Nradii x Nangles x Nenergies float]
  22. total: [Nradii x Nangles x Nenergies float]
  23. mean_radii: [Nradii x Nangles x Nenergies float] (not used)
  24. mean_angles: [Nradii x Nangles x Nenergies float] (not used)
  25. helpfield: [any x any char]
  26. fluence: [1xNenergies float]
  27. mu: [1xNenergies float]
  28. mu_en: [1xNenergies float]
  29. */
  30. {
  31. mxArray *tmp;
  32. int Nenergies, Nangles, Nradii, length;
  33. const int *dims;
  34. char err_msg[100];
  35. // check 'energies' field
  36. if ( (tmp=mxGetField(Kernels,0,"energies")) == NULL)
  37. mexErrMsgTxt("Missing 'energies' field in Kernels structure.");
  38. else
  39. Nenergies = MAXX(mxGetM(tmp),mxGetN(tmp));
  40. // check fields that are dependent on 'energies' field ('fluence','mu','mu_en')
  41. if ( (tmp=mxGetField(Kernels,0,"fluence")) == NULL)
  42. mexErrMsgTxt("Missing 'fluence' field in Kernels structure.");
  43. else
  44. {
  45. length = MAXX(mxGetM(tmp),mxGetN(tmp));
  46. if (length != Nenergies)
  47. mexErrMsgTxt("'energies' field and 'fluence' field in Kernels structure must have the same length");
  48. }
  49. if ( (tmp=mxGetField(Kernels,0,"mu")) == NULL)
  50. mexErrMsgTxt("Missing 'mu' field in Kernels structure.");
  51. else
  52. {
  53. length = MAXX(mxGetM(tmp),mxGetN(tmp));
  54. if (length != Nenergies)
  55. mexErrMsgTxt("'energies' field and 'mu' field in Kernels structure must have the same length");
  56. }
  57. if ( (tmp=mxGetField(Kernels,0,"mu_en")) == NULL)
  58. mexErrMsgTxt("Missing 'mu_en' field in Kernels structure.");
  59. else
  60. {
  61. length = MAXX(mxGetM(tmp),mxGetN(tmp));
  62. if (length != Nenergies)
  63. mexErrMsgTxt("'energies' field and 'mu_en' field in Kernels structure must have the same length");
  64. }
  65. // check 'angles' field
  66. if ( (tmp=mxGetField(Kernels,0,"angles")) == NULL)
  67. mexErrMsgTxt("Missing 'angles' field in Kernels structure.");
  68. else
  69. Nangles = MAXX(mxGetM(tmp),mxGetN(tmp));
  70. // check 'radii' field
  71. if ( (tmp=mxGetField(Kernels,0,"radii")) == NULL)
  72. mexErrMsgTxt("Missing 'radii' field in Kernels structure.");
  73. else
  74. Nradii = MAXX(mxGetM(tmp),mxGetN(tmp));
  75. // check kernels, which are dependent on 'radii', 'angles', and 'energies' fields
  76. // check primary kernel
  77. if ( (tmp=mxGetField(Kernels,0,"primary")) == NULL)
  78. mexErrMsgTxt("Missing 'primary' kernel in Kernels structure.");
  79. else
  80. {
  81. length = mxGetNumberOfDimensions(tmp);
  82. dims = mxGetDimensions(tmp);
  83. if ((length != 3) || (dims[0] != Nradii) || (dims[1] != Nangles)
  84. || (dims[2] != Nenergies))
  85. {
  86. sprintf(err_msg,"'primary' kernel in Kernels structure must be a %d x %d x %d matrix",
  87. Nradii, Nangles, Nenergies);
  88. mexErrMsgTxt(err_msg);
  89. }
  90. }
  91. // check first scatter kernel
  92. if ( (tmp=mxGetField(Kernels,0,"first_scatter")) == NULL)
  93. mexErrMsgTxt("Missing 'first_scatter' kernel in Kernels structure.");
  94. else
  95. {
  96. length = mxGetNumberOfDimensions(tmp);
  97. dims = mxGetDimensions(tmp);
  98. if ((length != 3) || (dims[0] != Nradii) || (dims[1] != Nangles)
  99. || (dims[2] != Nenergies))
  100. {
  101. sprintf(err_msg,"'first_scatter' kernel in Kernels structure must be a %d x %d x %d matrix",
  102. Nradii, Nangles, Nenergies);
  103. mexErrMsgTxt(err_msg);
  104. }
  105. }
  106. // check second scatter kernel
  107. if ( (tmp=mxGetField(Kernels,0,"second_scatter")) == NULL)
  108. mexErrMsgTxt("Missing 'second_scatter' kernel in Kernels structure.");
  109. else
  110. {
  111. length = mxGetNumberOfDimensions(tmp);
  112. dims = mxGetDimensions(tmp);
  113. if ((length != 3) || (dims[0] != Nradii) || (dims[1] != Nangles)
  114. || (dims[2] != Nenergies))
  115. {
  116. sprintf(err_msg,"'second_scatter' kernel in Kernels structure must be a %d x %d x %d matrix",
  117. Nradii, Nangles, Nenergies);
  118. mexErrMsgTxt(err_msg);
  119. }
  120. }
  121. // check multiple scatter kernel
  122. if ( (tmp=mxGetField(Kernels,0,"multiple_scatter")) == NULL)
  123. mexErrMsgTxt("Missing 'multiple_scatter' kernel in Kernels structure.");
  124. else
  125. {
  126. length = mxGetNumberOfDimensions(tmp);
  127. dims = mxGetDimensions(tmp);
  128. if ((length != 3) || (dims[0] != Nradii) || (dims[1] != Nangles)
  129. || (dims[2] != Nenergies))
  130. {
  131. sprintf(err_msg,"'multiple_scatter' kernel in Kernels structure must be a %d x %d x %d matrix",
  132. Nradii, Nangles, Nenergies);
  133. mexErrMsgTxt(err_msg);
  134. }
  135. }
  136. // check bremstrahlung & annihilation in flight kernel
  137. if ( (tmp=mxGetField(Kernels,0,"brem_annih")) == NULL)
  138. mexErrMsgTxt("Missing 'brem_annih' kernel in Kernels structure.");
  139. else
  140. {
  141. length = mxGetNumberOfDimensions(tmp);
  142. dims = mxGetDimensions(tmp);
  143. if ((length != 3) || (dims[0] != Nradii) || (dims[1] != Nangles)
  144. || (dims[2] != Nenergies))
  145. {
  146. sprintf(err_msg,"'brem_annih' kernel in Kernels structure must be a %d x %d x %d matrix",
  147. Nradii, Nangles, Nenergies);
  148. mexErrMsgTxt(err_msg);
  149. }
  150. }
  151. // check total kernel
  152. if ( (tmp=mxGetField(Kernels,0,"total")) == NULL)
  153. mexErrMsgTxt("Missing 'total' kernel in Kernels structure.");
  154. else
  155. {
  156. length = mxGetNumberOfDimensions(tmp);
  157. dims = mxGetDimensions(tmp);
  158. if ((length != 3) || (dims[0] != Nradii) || (dims[1] != Nangles)
  159. || (dims[2] != Nenergies))
  160. {
  161. sprintf(err_msg,"'total' kernel in Kernels structure must be a %d x %d x %d matrix",
  162. Nradii, Nangles, Nenergies);
  163. mexErrMsgTxt(err_msg);
  164. }
  165. }
  166. // the mean_radii and mean_angles fields are not needed, so don't check for them
  167. }
  168. void check_GEOMETRY(const mxArray *Geometry)
  169. /* Ensure that the GEOMETRY structure has the following format:
  170. Geometry =
  171. start: [3 element float]
  172. voxel_size: [3 element float]
  173. data: [M x N x Q float]
  174. beam: [1xB cell array]
  175. Geometry.beam =
  176. ip: [3 element float]
  177. jp: [3 element float]
  178. kp: [3 element float]
  179. y_vec: [3 element float]
  180. xp: [float scalar]
  181. yp: [float scalar]
  182. del_xp: [float scalar]
  183. del_yp: [float scalar]
  184. SAD: [float scalar]
  185. */
  186. {
  187. mxArray *tmp1, *tmp2, *cell;
  188. int length, B, b;
  189. // beam's eye view axis unit vectors, must be orthonormal and form a right-handed
  190. // coordinate system.
  191. float *ip, *jp, *kp;
  192. const int *dims;
  193. char errstr[200];
  194. // check that Geometry.start is a 3 element vector
  195. if ( (tmp1 = mxGetField(Geometry,0,"start")) == NULL)
  196. mexErrMsgTxt("Missing 'start' field in Geometry structure.");
  197. else
  198. if (mxGetNumberOfDimensions(tmp1) != 2)
  199. mexErrMsgTxt("Geometry.start must have 2 dimensions but be a vector.");
  200. else
  201. if (mxGetM(tmp1)*mxGetN(tmp1) != 3)
  202. mexErrMsgTxt("Geometry.start must be a 3 element vector.");
  203. // check that Geometry.voxel_size is a 3 element vector
  204. if ( (tmp1 = mxGetField(Geometry,0,"voxel_size")) == NULL)
  205. mexErrMsgTxt("Missing 'voxel_size' field in Geometry structure.");
  206. else
  207. if (mxGetNumberOfDimensions(tmp1) != 2)
  208. mexErrMsgTxt("Geometry.voxel_size must have 2 dimensions but be a vector.");
  209. else
  210. if (mxGetM(tmp1)*mxGetN(tmp1) != 3)
  211. mexErrMsgTxt("Geometry.voxel_size must be a 3 element vector.");
  212. // check that all parts of 'beam' field are present
  213. if ( (tmp1 = mxGetField(Geometry,0,"beam")) == NULL)
  214. mexErrMsgTxt("Missing 'beam' field in Geometry structure.");
  215. else
  216. {
  217. if (!mxIsCell(tmp1) || (mxGetNumberOfDimensions(tmp1) != 2))
  218. mexErrMsgTxt("'beam' field in Geometry structure must be a 2-D cell array.");
  219. else
  220. {
  221. dims = mxGetDimensions(tmp1); // dimensions of cell array
  222. B = dims[0]*dims[1]; // total number of cells
  223. for (b=0;b<B;b++) // check all of the beam fields
  224. {
  225. if((cell = mxGetCell(tmp1,b)) == NULL || !mxIsStruct(cell))
  226. {
  227. sprintf(errstr,"Geometry.beam{%d} either doesn't exist or isn't a structure.",b+1);
  228. mexErrMsgTxt(errstr);
  229. }
  230. // start checking the beam fields
  231. if((tmp2 = mxGetField(cell,0,"ip")) == NULL)
  232. {
  233. sprintf(errstr,"Geometry.beam{%d} must contain a ip field.",b+1);
  234. mexErrMsgTxt(errstr);
  235. }
  236. else if (mxGetNumberOfDimensions(tmp2) != 2)
  237. {
  238. sprintf(errstr,"Geometry.beam{%d}.ip must have 2 dimensions but be a vector.",b+1);
  239. mexErrMsgTxt(errstr);
  240. }
  241. else if (mxGetM(tmp2)*mxGetN(tmp2) != 3)
  242. {
  243. sprintf(errstr,"Geometry.beam{%d}.ip must be a 3 element vector.",b+1);
  244. mexErrMsgTxt(errstr);
  245. }
  246. else
  247. ip = (float *)mxGetData(tmp2);
  248. if((tmp2 = mxGetField(cell,0,"jp")) == NULL)
  249. {
  250. sprintf(errstr,"Geometry.beam{%d} must contain a jp field.",b+1);
  251. mexErrMsgTxt(errstr);
  252. }
  253. else if (mxGetNumberOfDimensions(tmp2) != 2)
  254. {
  255. sprintf(errstr,"Geometry.beam{%d}.jp must have 2 dimensions but be a vector.",b+1);
  256. mexErrMsgTxt(errstr);
  257. }
  258. else if (mxGetM(tmp2)*mxGetN(tmp2) != 3)
  259. {
  260. sprintf(errstr,"Geometry.beam{%d}.jp must be a 3 element vector.",b+1);
  261. mexErrMsgTxt(errstr);
  262. }
  263. else
  264. jp = (float *)mxGetData(tmp2);
  265. if((tmp2 = mxGetField(cell,0,"kp")) == NULL)
  266. {
  267. sprintf(errstr,"Geometry.beam{%d} must contain a ip field.",b+1);
  268. mexErrMsgTxt(errstr);
  269. }
  270. else if (mxGetNumberOfDimensions(tmp2) != 2)
  271. {
  272. sprintf(errstr,"Geometry.beam{%d}.kp must have 2 dimensions but be a vector.",b+1);
  273. mexErrMsgTxt(errstr);
  274. }
  275. else if (mxGetM(tmp2)*mxGetN(tmp2) != 3)
  276. {
  277. sprintf(errstr,"Geometry.beam{%d}.kp must be a 3 element vector.",b+1);
  278. mexErrMsgTxt(errstr);
  279. }
  280. else
  281. kp = (float *)mxGetData(tmp2);
  282. // ensure that ip,jp,kp are orthonormal and form a right-handed coordinate system
  283. if ( (fabs(ip[0]*ip[0] + ip[1]*ip[1] + ip[2]*ip[2] - 1.0) > 1e-6)
  284. || (fabs(jp[0]*jp[0] + jp[1]*jp[1] + jp[2]*jp[2] - 1.0) > 1e-6)
  285. || (fabs(kp[0]*kp[0] + kp[1]*kp[1] + kp[2]*kp[2] - 1.0) > 1e-6)
  286. || (fabs(ip[0]*jp[0] + ip[1]*jp[1] + ip[2]*jp[2]) > 1e-6)
  287. || (fabs(ip[0]*kp[0] + ip[1]*kp[1] + ip[2]*kp[2]) > 1e-6)
  288. || (fabs(jp[0]*kp[0] + jp[1]*kp[1] + jp[2]*kp[2]) > 1e-6))
  289. {
  290. sprintf(errstr,"Beam's eye view unit vectors ip, jp, and kp for beam %d must be orthonormal.",b+1);
  291. mexErrMsgTxt(errstr);
  292. }
  293. // check that cross(ip,jp) = kp
  294. if ( (fabs(ip[1]*jp[2] - ip[2]*jp[1] - kp[0]) > 1e-6)
  295. || (fabs(ip[2]*jp[0] - ip[0]*jp[2] - kp[1]) > 1e-6)
  296. || (fabs(ip[0]*jp[1] - ip[1]*jp[0] - kp[2]) > 1e-6))
  297. {
  298. sprintf(errstr,"Must have cross(ip,jp) = kp for beam %d in beam's eye view.",b+1);
  299. mexErrMsgTxt(errstr);
  300. }
  301. if((tmp2 = mxGetField(cell,0,"y_vec")) == NULL)
  302. {
  303. sprintf(errstr,"Geometry.beam{%d} must contain a y_vec field.",b+1);
  304. mexErrMsgTxt(errstr);
  305. }
  306. else
  307. if (mxGetNumberOfDimensions(tmp2) != 2)
  308. {
  309. sprintf(errstr,"Geometry.beam{%d}.y_vec must have 2 dimensions but be a vector.",b+1);
  310. mexErrMsgTxt(errstr);
  311. }
  312. else
  313. if (mxGetM(tmp2)*mxGetN(tmp2) != 3)
  314. {
  315. sprintf(errstr,"Geometry.beam{%d}.y_vec must be a 3 element vector.",b+1);
  316. mexErrMsgTxt(errstr);
  317. }
  318. if((tmp2 = mxGetField(cell,0,"xp")) == NULL)
  319. {
  320. sprintf(errstr,"Geometry.beam{%d} must contain a xp field.",b+1);
  321. mexErrMsgTxt(errstr);
  322. }
  323. else
  324. if (mxGetNumberOfDimensions(tmp2) != 2)
  325. {
  326. sprintf(errstr,"Geometry.beam{%d}.xp must have 2 dimensions but be a scalar.",b+1);
  327. mexErrMsgTxt(errstr);
  328. }
  329. else
  330. if (mxGetM(tmp2)*mxGetN(tmp2) != 1)
  331. {
  332. sprintf(errstr,"Geometry.beam{%d}.xp must be a scalar.",b+1);
  333. mexErrMsgTxt(errstr);
  334. }
  335. if((tmp2 = mxGetField(cell,0,"yp")) == NULL)
  336. {
  337. sprintf(errstr,"Geometry.beam{%d} must contain a yp field.",b+1);
  338. mexErrMsgTxt(errstr);
  339. }
  340. else
  341. if (mxGetNumberOfDimensions(tmp2) != 2)
  342. {
  343. sprintf(errstr,"Geometry.beam{%d}.yp must have 2 dimensions but be a scalar.",b+1);
  344. mexErrMsgTxt(errstr);
  345. }
  346. else
  347. if (mxGetM(tmp2)*mxGetN(tmp2) != 1)
  348. {
  349. sprintf(errstr,"Geometry.beam{%d}.yp must be a scalar.",b+1);
  350. mexErrMsgTxt(errstr);
  351. }
  352. if((tmp2 = mxGetField(cell,0,"del_xp")) == NULL)
  353. {
  354. sprintf(errstr,"Geometry.beam{%d} must contain a del_xp field.",b+1);
  355. mexErrMsgTxt(errstr);
  356. }
  357. else
  358. if (mxGetNumberOfDimensions(tmp2) != 2)
  359. {
  360. sprintf(errstr,"Geometry.beam{%d}.del_xp must have 2 dimensions but be a scalar.",b+1);
  361. mexErrMsgTxt(errstr);
  362. }
  363. else
  364. if (mxGetM(tmp2)*mxGetN(tmp2) != 1)
  365. {
  366. sprintf(errstr,"Geometry.beam{%d}.del_xp must be a scalar.",b+1);
  367. mexErrMsgTxt(errstr);
  368. }
  369. if((tmp2 = mxGetField(cell,0,"del_yp")) == NULL)
  370. {
  371. sprintf(errstr,"Geometry.beam{%d} must contain a del_yp field.",b+1);
  372. mexErrMsgTxt(errstr);
  373. }
  374. else
  375. if (mxGetNumberOfDimensions(tmp2) != 2)
  376. {
  377. sprintf(errstr,"Geometry.beam{%d}.del_yp must have 2 dimensions but be a scalar.",b+1);
  378. mexErrMsgTxt(errstr);
  379. }
  380. else
  381. if (mxGetM(tmp2)*mxGetN(tmp2) != 1)
  382. {
  383. sprintf(errstr,"Geometry.beam{%d}.del_yp must be a scalar.",b+1);
  384. mexErrMsgTxt(errstr);
  385. }
  386. if((tmp2 = mxGetField(cell,0,"SAD")) == NULL)
  387. {
  388. sprintf(errstr,"Geometry.beam{%d} must contain an SAD field.",b+1);
  389. mexErrMsgTxt(errstr);
  390. }
  391. else
  392. if (mxGetNumberOfDimensions(tmp2) != 2)
  393. {
  394. sprintf(errstr,"Geometry.beam{%d}.SAD must have 2 dimensions but be a scalar.",b+1);
  395. mexErrMsgTxt(errstr);
  396. }
  397. else
  398. if (mxGetM(tmp2)*mxGetN(tmp2) != 1)
  399. {
  400. sprintf(errstr,"Geometry.beam{%d}.SAD must be a scalar.",b+1);
  401. mexErrMsgTxt(errstr);
  402. }
  403. }
  404. }
  405. }
  406. // check that data matrix is present and 3-D
  407. //(3-D part maybe not necessary for calculation itself, I'm looking into this)
  408. if ( (tmp1 = mxGetField(Geometry,0,"data")) == NULL)
  409. mexErrMsgTxt("Missing 'data' field in Geometry structure.");
  410. else
  411. {
  412. length = mxGetNumberOfDimensions(tmp1);
  413. if (length != 3)
  414. mexErrMsgTxt("Geometry.data must be a 3-D matrix.");
  415. }
  416. }
  417. void load_kernels(const mxArray *Kernels, MONO_KERNELS *mono_kernels)
  418. /* Turns Matlab structures into C structures. */
  419. {
  420. int i, Nenergies, Nangles, Nradii;
  421. float *dataPtr;
  422. mxArray *tmp;
  423. /* find number of energies to consider in the spectrum */
  424. tmp = mxGetField(Kernels,0,"energies");
  425. Nenergies = MAXX(mxGetM(tmp),mxGetN(tmp));
  426. mono_kernels->energy = (float *)mxGetData(tmp);
  427. mono_kernels->nkernels = Nenergies; // one kernel for each energy
  428. tmp = mxGetField(Kernels,0,"fluence");
  429. mono_kernels->fluence = (float *)mxGetData(tmp);
  430. tmp = mxGetField(Kernels,0,"mu");
  431. mono_kernels->mu = (float *)mxGetData(tmp);
  432. tmp = mxGetField(Kernels,0,"mu_en");
  433. mono_kernels->mu_en = (float *)mxGetData(tmp);
  434. /* Load kernels in one at a time */
  435. for (i=0; i<Nenergies; i++)
  436. {
  437. tmp = mxGetField(Kernels,0,"radii");
  438. Nradii = MAXX(mxGetM(tmp),mxGetN(tmp));
  439. mono_kernels->kernel[i].nradii = Nradii;
  440. mono_kernels->kernel[i].radial_boundary = (float *)mxGetData(tmp);
  441. tmp = mxGetField(Kernels,0,"angles");
  442. Nangles = MAXX(mxGetM(tmp),mxGetN(tmp));
  443. mono_kernels->kernel[i].ntheta = Nangles;
  444. mono_kernels->kernel[i].angular_boundary = (float *)mxGetData(tmp);
  445. /* Assign data pointers. Data are in Nradii x Nangles x Nenergies matrices */
  446. tmp = mxGetField(Kernels,0,"primary");
  447. dataPtr = (float *)mxGetData(tmp);
  448. mono_kernels->kernel[i].matrix[0] = &dataPtr[Nradii*Nangles*i];
  449. tmp = mxGetField(Kernels,0,"first_scatter");
  450. dataPtr = (float *)mxGetData(tmp);
  451. mono_kernels->kernel[i].matrix[1] = &dataPtr[Nradii*Nangles*i];
  452. tmp = mxGetField(Kernels,0,"second_scatter");
  453. dataPtr = (float *)mxGetData(tmp);
  454. mono_kernels->kernel[i].matrix[2] = &dataPtr[Nradii*Nangles*i];
  455. tmp = mxGetField(Kernels,0,"multiple_scatter");
  456. dataPtr = (float *)mxGetData(tmp);
  457. mono_kernels->kernel[i].matrix[3] = &dataPtr[Nradii*Nangles*i];
  458. tmp = mxGetField(Kernels,0,"brem_annih");
  459. dataPtr = (float *)mxGetData(tmp);
  460. mono_kernels->kernel[i].matrix[4] = &dataPtr[Nradii*Nangles*i];
  461. tmp = mxGetField(Kernels,0,"total");
  462. dataPtr = (float *)mxGetData(tmp);
  463. mono_kernels->kernel[i].total_matrix = &dataPtr[Nradii*Nangles*i];
  464. }
  465. }
  466. void load_Geometry(const mxArray *Geometry, FLOAT_GRID *density)
  467. // Loads the non-beam information of the Geometry Matab structure into a C structure.
  468. // Note that the CT matrix is specified in units of density, not Hounsfield units.
  469. // All Hounsfield unit conversions must be done before the convolution program is called.
  470. /* Ensure that the GEOMETRY structure has the following format:
  471. Geometry =
  472. start: [3 element float]
  473. voxel_size: [3 element float]
  474. data: [M x N x Q float]
  475. beam: [1x1 struct]
  476. */
  477. {
  478. const int *dimensions;
  479. int i;
  480. float *dataPtr;
  481. mxArray *tmp1, *tmp2;
  482. /* Geometry is a Matlab structure with fields that correspond to the
  483. C structures defined for this program. */
  484. tmp1 = mxGetField(Geometry,0,"start");
  485. dataPtr = (float *)mxGetData(tmp1);
  486. density->start.x = dataPtr[0];
  487. density->start.y = dataPtr[1];
  488. density->start.z = dataPtr[2];
  489. /* read in voxel size */
  490. tmp1 = mxGetField(Geometry,0,"voxel_size");
  491. dataPtr = (float *)mxGetData(tmp1);
  492. density->inc.x = dataPtr[0];
  493. density->inc.y = dataPtr[1];
  494. density->inc.z = dataPtr[2];
  495. /* get pointer to CT data matrix */
  496. /* Data stored in an (x,y,z) matrix */
  497. tmp1 = mxGetField(Geometry,0,"data");
  498. density->matrix = (float *)mxGetData(tmp1);
  499. dimensions = mxGetDimensions(tmp1);
  500. density->x_count = dimensions[0];
  501. density->y_count = dimensions[1];
  502. density->z_count = dimensions[2];
  503. }
  504. void load_beam(const mxArray *Geometry, int beam_ind, BEAM *beam)
  505. // Loads Geometry.beam{beam_ind} into a BEAM structure. To avoid errors
  506. // ensure that check_Geometry was run before this function.
  507. /* Ensure that the 'beam' structure has the proper format:
  508. Geometry.beam =
  509. ip: [3 element float]
  510. jp: [3 element float]
  511. kp: [3 element float]
  512. y_vec: [3 element float]
  513. xp: [float scalar]
  514. yp: [float scalar]
  515. del_xp: [float scalar]
  516. del_yp: [float scalar] */
  517. {
  518. const int *dimensions;
  519. int i;
  520. float *dataPtr;
  521. mxArray *cell, *struc;
  522. /* read in beam information */
  523. cell = mxGetCell(mxGetField(Geometry,0,"beam"),beam_ind);
  524. struc = mxGetField(cell,0,"ip");
  525. dataPtr = (float *)mxGetData(struc);
  526. for (i=0;i<=2;i++) beam->ip[i] = dataPtr[i];
  527. struc = mxGetField(cell,0,"jp");
  528. dataPtr = (float *)mxGetData(struc);
  529. for (i=0;i<=2;i++) beam->jp[i] = dataPtr[i];
  530. struc = mxGetField(cell,0,"kp");
  531. dataPtr = (float *)mxGetData(struc);
  532. for (i=0;i<=2;i++) beam->kp[i] = dataPtr[i];
  533. struc = mxGetField(cell,0,"y_vec");
  534. dataPtr = (float *)mxGetData(struc);
  535. for (i=0;i<=2;i++) beam->y_vec[i] = dataPtr[i];
  536. struc = mxGetField(cell,0,"xp");
  537. beam->xp = (float)mxGetScalar(struc);
  538. struc = mxGetField(cell,0,"yp");
  539. beam->yp = (float)mxGetScalar(struc);
  540. struc = mxGetField(cell,0,"del_xp");
  541. beam->del_xp = (float)mxGetScalar(struc);
  542. struc = mxGetField(cell,0,"del_yp");
  543. beam->del_yp = (float)mxGetScalar(struc);
  544. struc = mxGetField(cell,0,"SAD");
  545. beam->SAD = (float)mxGetScalar(struc);
  546. }