r94: finished c++ conversions
[ctsim.git] / src / phm2rs.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **   Name:          phm2rs.cpp
5 **   Purpose:       Take projections of a phantom object
6 **   Programmer:    Kevin Rosenberg
7 **   Date Started:  1984
8 **
9 **  This is part of the CTSim program
10 **  Copyright (C) 1983-2000 Kevin Rosenberg
11 **
12 **  $Id: phm2rs.cpp,v 1.5 2000/06/13 16:20:31 kevin Exp $
13 **
14 **  This program is free software; you can redistribute it and/or modify
15 **  it under the terms of the GNU General Public License (version 2) as
16 **  published by the Free Software Foundation.
17 **
18 **  This program is distributed in the hope that it will be useful,
19 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 **  GNU General Public License for more details.
22 **
23 **  You should have received a copy of the GNU General Public License
24 **  along with this program; if not, write to the Free Software
25 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 ******************************************************************************/
27
28 #include "ct.h"
29 #include "timer.h"
30
31
32 enum { O_PHANTOM, O_DESC, O_NRAY, O_ROTANGLE, O_PHMFILE,
33        O_TRACE, O_VERBOSE, O_HELP, O_DEBUG, O_VERSION };
34
35 static struct option phm2rs_options[] = 
36 {
37   {"phantom", 1, 0, O_PHANTOM},
38   {"phmfile", 1, 0, O_PHMFILE},
39   {"desc", 1, 0, O_DESC},
40   {"nray", 1, 0, O_NRAY},
41   {"rotangle", 1, 0, O_ROTANGLE},
42   {"trace", 1, 0, O_TRACE},
43   {"verbose", 0, 0, O_VERBOSE},
44   {"help", 0, 0, O_HELP},
45   {"debug", 0, 0, O_DEBUG},
46   {"version", 0, 0, O_VERSION},
47   {0, 0, 0, 0}
48 };
49
50
51 void 
52 phm2rs_usage (const char *program)
53 {
54   cout << "usage: " << fileBasename(program) << " outfile ndet nview [--phantom phantom-name] [--phmfile filename] [OPTIONS]" << endl;
55   cout << "Calculate raysums (projections) through phantom object, either" << endl;
56   cout << "a predefined --phantom or a --phmfile" << endl;
57   cout << "" << endl;
58   cout << "     outfile      Name of output file for raysums" << endl;
59   cout << "     ndet         Number of detectors" << endl;
60   cout << "     nview        Number of rotated views" << endl;
61   cout << "     --phantom    Phantom to use for projection" << endl;
62   cout << "        herman    Herman head phantom" << endl;
63   cout << "        rowland   Rowland head phantom" << endl;
64   cout << "        browland  Bordered Rowland head phantom" << endl;
65   cout << "        unitpulse Unit pulse phantom" << endl;
66   cout << "     --phmfile    Get Phantom from phantom file" << endl;
67   cout << "     --desc       Description of raysum" << endl;
68   cout << "     --nray       Number of rays per detector (default = 1)" << endl;
69   cout << "     --rotangle   Degrees to rotate view through, multiple of PI (default = 1)" << endl;
70   cout << "     --trace      Trace level to use" << endl;
71   cout << "        none      No tracing (default)" << endl;
72   cout << "        text      Trace text level" << endl;
73   cout << "        phm       Trace phantom image" << endl;
74   cout << "        rays      Trace rays" << endl;
75   cout << "        plot      Trace plot" << endl;
76   cout << "        clipping  Trace clipping" << endl;
77   cout << "     --verbose    Verbose mode" << endl;
78   cout << "     --debug      Debug mode" << endl;
79   cout << "     --version    Print version" << endl;
80   cout << "     --help       Print this help message" << endl;
81 }
82
83 #ifdef HAVE_MPI
84 void GatherProjectionsMPI (MPIWorld& mpiWorld, RAYSUM *rsGlobal, RAYSUM *rsLocal, const int opt_debug);
85 #endif
86
87 int 
88 phm2rs_main (int argc, char* argv[])
89 {
90   DETECTOR *det;
91   PHANTOM *phm = NULL;
92   RAYSUM *rsGlobal = NULL;
93   char *opt_outfile = NULL;
94   char opt_desc[MAXREMARK+1];
95   char opt_phmfilename[256];
96   char *endptr, *endstr;
97   int opt_ndet, opt_nview;
98   int opt_nray = 1;
99   int opt_trace = 0;
100   int opt_phmnum = -1;
101   int opt_verbose = 0;
102   int opt_debug = 0;
103   double opt_rotangle = 1;
104
105 #ifdef HAVE_MPI
106   RAYSUM *rsLocal;
107   MPIWorld mpiWorld (argc, argv);
108 #endif
109
110   Timer timerProgram;
111
112 #ifdef HAVE_MPI
113   if (mpiWorld.getRank() == 0) {
114 #endif
115     strcpy(opt_desc, "");
116     strcpy(opt_phmfilename, "");
117     while (1) {
118       int c = getopt_long(argc, argv, "", phm2rs_options, NULL);
119       char *endptr = NULL;
120       char *endstr;
121       
122       if (c == -1)
123         break;
124       
125       switch (c) {
126       case O_PHANTOM:
127         if ((opt_phmnum = opt_set_phantom (optarg)) < 0) {
128           phm2rs_usage(argv[0]);
129           return (1);
130         }
131         phm = phm_create (opt_phmnum);
132         break;
133       case O_PHMFILE:
134 #ifdef HAVE_MPI
135         if (mpiWorld.getRank() == 0)
136           cerr << "Can not read phantom from file in MPI mode" << endl;
137         return (1);
138 #endif
139         strncpy(opt_phmfilename, optarg, sizeof(opt_phmfilename));
140         phm = phm_create_from_file(opt_phmfilename);
141         break;
142       case O_VERBOSE:
143         opt_verbose = 1;
144         break;
145       case O_DEBUG:
146         opt_debug = 1;
147         break;
148         break;
149       case O_TRACE:
150         if ((opt_trace = opt_set_trace(optarg)) < 0) {
151           phm2rs_usage(argv[0]);
152           return (1);
153         }
154         break;
155       case O_DESC:
156         strncpy(opt_desc, optarg, sizeof(opt_desc));
157         break;
158       case O_ROTANGLE:
159         opt_rotangle = strtod(optarg, &endptr);
160         endstr = optarg + strlen(optarg);
161         if (endptr != endstr) {
162           cerr << "Error setting --rotangle to " << optarg << endl;
163           phm2rs_usage(argv[0]);
164           return (1);
165         }
166         break;
167       case O_NRAY:
168         opt_nray = strtol(optarg, &endptr, 10);
169         endstr = optarg + strlen(optarg);
170         if (endptr != endstr) {
171           cerr << "Error setting --nray to %s" << optarg << endl;
172           phm2rs_usage(argv[0]);
173           return (1);
174         }
175         break;
176         case O_VERSION:
177 #ifdef VERSION
178         cout << "Version: " << VERSION << endl;
179 #else
180         cout << "Unknown version number" << endl;
181 #endif
182           exit(0);
183       case O_HELP:
184       case '?':
185         phm2rs_usage(argv[0]);
186         return (0);
187       default:
188         phm2rs_usage(argv[0]);
189         return (1);
190       }
191     }
192   
193     if (phm == NULL) {
194       cerr << "No phantom defined" << endl;
195       phm2rs_usage(argv[0]);
196       return (1);
197     }
198     if (optind + 3 != argc) {
199       phm2rs_usage(argv[0]);
200       return (1);
201     }
202
203     opt_outfile = argv[optind];
204     opt_ndet = strtol(argv[optind+1], &endptr, 10);
205     endstr = argv[optind+1] + strlen(argv[optind+1]);
206     if (endptr != endstr) {
207       cerr << "Error setting --ndet to " << argv[optind+1] << endl;
208       phm2rs_usage(argv[0]);
209       return (1);
210     }
211     opt_nview = strtol(argv[optind+2], &endptr, 10);
212     endstr = argv[optind+2] + strlen(argv[optind+2]);
213     if (endptr != endstr) {
214       cerr << "Error setting --nview to " << argv[optind+2] << endl;
215       phm2rs_usage(argv[0]);
216       return (1);
217     }
218
219     char str[256];
220     snprintf(str, sizeof(str), 
221              "Raysum_Collect: NDet=%d, Nview=%d, NRay=%d, RotAngle=%.2f, ", 
222              opt_ndet, opt_nview, opt_nray, opt_rotangle);
223     if (opt_phmfilename[0]) {
224       strncat(str, "Phantom=", sizeof(str));
225       strncat(str, opt_phmfilename, sizeof(str));
226     } else if (opt_phmnum != -1) {
227       strncat(str, "Phantom=", sizeof(str));
228       strncat(str, name_of_phantom(opt_phmnum), sizeof(str));
229     }
230     if (opt_desc[0]) {
231       strncat(str, ": ", sizeof(str));
232       strncat(str, opt_desc, sizeof(str));
233     }
234     strncpy(opt_desc, str, sizeof(opt_desc));
235 #ifdef HAVE_MPI
236   }
237 #endif
238
239 #ifdef HAVE_MPI
240   mpiWorld.getComm().Bcast (&opt_rotangle, 1, MPI::DOUBLE, 0);
241   mpiWorld.getComm().Bcast (&opt_nview, 1, MPI::INT, 0);
242   mpiWorld.getComm().Bcast (&opt_ndet, 1, MPI::INT, 0);
243   mpiWorld.getComm().Bcast (&opt_nray, 1, MPI::INT, 0);
244   mpiWorld.getComm().Bcast (&opt_phmnum, 1, MPI::INT, 0);
245   mpiWorld.getComm().Bcast (&opt_verbose, 1, MPI::INT, 0);
246   mpiWorld.getComm().Bcast (&opt_debug, 1, MPI::INT, 0);
247   mpiWorld.getComm().Bcast (&opt_trace, 1, MPI::INT, 0);
248
249   if (mpiWorld.getRank() > 0 && opt_phmnum >= 0)
250     phm = phm_create (opt_phmnum);
251 #endif
252
253   opt_rotangle *= PI;
254   det = detector_create (phm, DETECTOR_PARALLEL, opt_ndet, opt_nview, opt_nray, opt_rotangle);
255
256 #ifdef HAVE_MPI
257   mpiWorld.setTotalWorkUnits (opt_nview);
258
259   if (mpiWorld.getRank() == 0) {
260     rsGlobal = raysum_create_from_det (opt_outfile, det);
261     raysum_alloc_views(rsGlobal);
262   }
263   
264   rsLocal = raysum_create_from_det (NULL, det);
265   rsLocal->nview = mpiWorld.getMyLocalWorkUnits();
266   if (opt_debug)
267     cout << "rsLocal->nview = " << rsLocal->nview << " (process " << mpiWorld.getRank() << ")" << endl;;
268
269   TimerMPI timerProject (mpiWorld.getComm());
270   raysum_collect (rsLocal, det, phm, mpiWorld.getMyStartWorkUnit(), opt_trace, FALSE);
271   if (opt_verbose)
272     timerProject.timerEndAndReport ("Time to collect projections");
273
274   TimerMPI timerGather (mpiWorld.getComm());
275   GatherProjectionsMPI (mpiWorld, rsGlobal, rsLocal, opt_debug);
276   if (opt_verbose)
277     timerGather.timerEndAndReport ("Time to gather projections");
278 #else
279   rsGlobal = raysum_create_from_det (opt_outfile, det);
280   raysum_collect (rsGlobal, det, phm, 0, opt_trace, FALSE);
281 #endif
282   
283 #ifdef HAVE_MPI
284   if (mpiWorld.getRank() == 0) 
285 #endif
286     {
287       rsGlobal->calctime = timerProgram.timerEnd();
288       strncpy (rsGlobal->remark, opt_desc, sizeof(rsGlobal->remark));
289       raysum_write (rsGlobal);
290       raysum_close (rsGlobal);
291       if (opt_verbose) {
292         cout << "Remark: " << rsGlobal->remark << endl;
293         cout << "Run time: " << rsGlobal->calctime << " seconds" << endl;
294       }
295     }
296
297   phm_free (phm);
298   detector_free (det);
299
300   return (0);
301 }
302
303
304 /* FUNCTION
305  *    GatherProjectionsMPI
306  *
307  * SYNOPSIS
308  *    Gather's raysums from all processes in rsLocal in rsGlobal in process 0
309  */
310
311 #ifdef HAVE_MPI
312 void GatherProjectionsMPI (MPIWorld& mpiWorld, RAYSUM *rsGlobal, RAYSUM *rsLocal, const int opt_debug)
313 {
314   for (int iw = 0; iw < mpiWorld.getMyLocalWorkUnits(); iw++) {
315     mpiWorld.getComm().Send(&rsLocal->view[iw]->view_angle, 1, MPI::DOUBLE, 0, 0);
316     mpiWorld.getComm().Send(&rsLocal->view[iw]->ndet, 1, MPI::INT, 0, 0);
317     mpiWorld.getComm().Send(rsLocal->view[iw]->detval, rsLocal->ndet, MPI::FLOAT, 0, 0);
318   }
319
320   if (mpiWorld.getRank() == 0) {
321     for (int iProc = 0; iProc < mpiWorld.getNumProcessors(); iProc++) {
322       for (int iw = mpiWorld.getStartWorkUnit(iProc); iw <= mpiWorld.getEndWorkUnit(iProc); iw++) {
323         MPI::Status status;
324
325         mpiWorld.getComm().Recv(&rsGlobal->view[iw]->view_angle, 1, MPI::DOUBLE, iProc, 0, status);
326         mpiWorld.getComm().Recv(&rsGlobal->view[iw]->ndet, 1, MPI::INT, iProc, 0, status);
327         mpiWorld.getComm().Recv(rsGlobal->view[iw]->detval, rsGlobal->ndet, MPI::FLOAT, iProc, 0, status);
328       }
329     }
330   }
331
332 }
333 #endif
334
335
336 #ifndef NO_MAIN
337 int 
338 main (int argc, char* argv[])
339 {
340   return (phm2rs_main(argc, argv));
341 }
342 #endif
343