r56: Improved option processing
[ctsim.git] / src / phm2rs.c
1 /*****************************************************************************
2 **  This is part of the CTSim program
3 **  Copyright (C) 1983-2000 Kevin Rosenberg
4 **
5 ** PURPOSE
6 **   Generate raysum projections from phantom object
7 **
8 ** HISTORY
9 **   1984 -- Final DOS version  
10 **   1999 -- First UNIX version
11 **
12 **  $Id: phm2rs.c,v 1.11 2000/05/16 04:33:59 kevin Exp $
13 **  $Log: phm2rs.c,v $
14 **  Revision 1.11  2000/05/16 04:33:59  kevin
15 **  Improved option processing
16 **
17 **  Revision 1.9  2000/05/08 20:02:32  kevin
18 **  ANSI C changes
19 **
20 **  Revision 1.8  2000/05/04 18:16:34  kevin
21 **  renamed filter definitions
22 **
23 **  Revision 1.7  2000/05/03 08:49:50  kevin
24 **  Code cleanup
25 **
26 **  Revision 1.6  2000/04/30 18:23:53  kevin
27 **  Code cleaning
28 **
29 **  Revision 1.5  2000/04/30 10:13:27  kevin
30 **  Fixed MPI bugs
31 **
32 **  Revision 1.4  2000/04/30 04:06:13  kevin
33 **  Update Raysum i/o routines
34 **  Fix MPI bug in ctrec (scatter_raysum) that referenced rs_global
35 **
36 **  Revision 1.3  2000/04/29 23:24:56  kevin
37 **  *** empty log message ***
38 **
39 **  Revision 1.2  2000/04/28 13:50:45  kevin
40 **  Removed Makefile Makefile.in that are automatically generated by autoconf
41 **
42 **  Revision 1.1.1.1  2000/04/28 13:02:44  kevin
43 **  Initial CVS import for first public release
44 **
45 **
46 **
47 **  This program is free software; you can redistribute it and/or modify
48 **  it under the terms of the GNU General Public License (version 2) as
49 **  published by the Free Software Foundation.
50 **
51 **  This program is distributed in the hope that it will be useful,
52 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
53 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
54 **  GNU General Public License for more details.
55 **
56 **  You should have received a copy of the GNU General Public License
57 **  along with this program; if not, write to the Free Software
58 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
59 ******************************************************************************/
60
61
62 #include "ct.h"
63
64 enum { O_PHANTOM, O_DESC, O_NRAY, O_ROTANGLE, O_PHMFILE,
65        O_TRACE, O_VERBOSE, O_HELP, O_DEBUG, O_VERSION };
66
67 static struct option phm2rs_options[] = 
68 {
69   {"phantom", 1, 0, O_PHANTOM},
70   {"phmfile", 1, 0, O_PHMFILE},
71   {"desc", 1, 0, O_DESC},
72   {"nray", 1, 0, O_NRAY},
73   {"rotangle", 1, 0, O_ROTANGLE},
74   {"trace", 1, 0, O_TRACE},
75   {"verbose", 0, 0, O_VERBOSE},
76   {"help", 0, 0, O_HELP},
77   {"debug", 0, 0, O_DEBUG},
78   {"version", 0, 0, O_VERSION},
79   {0, 0, 0, 0}
80 };
81
82
83 void 
84 phm2rs_usage (const char *program)
85 {
86 #ifdef MPI_CT
87 if (mpi_ct.my_rank == 0)
88   {
89 #endif  
90   fprintf(stdout,"usage: %s outfile ndet nview [--phantom phantom-name] [--phmfile filename] [OPTIONS]\n", kbasename(program));
91   fprintf(stdout,"Calculate raysums (projections) through phantom object, either\n");
92   fprintf(stdout,"a predefined --phantom or a --phmfile\n");
93   fprintf(stdout,"\n");
94   fprintf(stdout,"     outfile      Name of output file for raysums\n");
95   fprintf(stdout,"     ndet         Number of detectors\n");
96   fprintf(stdout,"     nview        Number of rotated views\n");
97   fprintf(stdout,"     --phantom    Phantom to use for projection\n");
98   fprintf(stdout,"        herman    Herman head phantom\n");
99   fprintf(stdout,"        rowland   Rowland head phantom\n");
100   fprintf(stdout,"        browland  Bordered Rowland head phantom\n");
101   fprintf(stdout,"        unitpulse Unit pulse phantom\n");
102   fprintf(stdout,"     --phmfile    Get Phantom from phantom file\n");
103   fprintf(stdout,"     --desc       Description of raysum\n");
104   fprintf(stdout,"     --nray       Number of rays per detector (default = 1)\n");
105   fprintf(stdout,"     --rotangle   Degrees to rotate view through, multiple of PI (default = 1)\n");
106   fprintf(stdout,"     --trace      Trace level to use\n");
107   fprintf(stdout,"        none      No tracing (default)\n");
108   fprintf(stdout,"        text      Trace text level\n");
109   fprintf(stdout,"        phm       Trace PHANTOM\n");
110   fprintf(stdout,"        rays      Trace rays\n");
111   fprintf(stdout,"        plot      Trace plot\n");
112   fprintf(stdout,"        clipping  Trace clipping\n");
113   fprintf(stdout,"     --verbose    Verbose mode\n");
114   fprintf(stdout,"     --debug      Debug mode\n");
115   fprintf(stdout,"     --version    Print version\n");
116   fprintf(stdout,"     --help       Print this help message\n");
117 #ifdef MPI_CT
118   }
119   MPI_Abort(mpi_ct.comm, 1);
120 #endif
121 }
122
123 #ifdef MPI_CT
124 void mpi_gather_rs (RAYSUM *rs_global, RAYSUM *rs_local, const int opt_debug);
125 #endif
126
127 int 
128 phm2rs_main (const int argc, char *const argv[])
129 {
130   DETECTOR *det;
131   PHANTOM *phm = NULL;
132   RAYSUM *rs_global = NULL;
133   char str[256], *opt_outfile = NULL, opt_desc[MAXREMARK+1];
134   char opt_phmfilename[256];
135   char *endptr, *endstr;
136   int opt_ndet, opt_nview;
137   int opt_nray = 1;
138   int opt_trace = 0, opt_phmnum = -1;
139   int opt_verbose = 0;
140   int opt_debug = 0;
141   double opt_rotangle = 1;
142   double time_start = 0, time_end = 0;
143
144 #ifndef MPI_CT
145   time_start = td_current_sec();
146 #else
147   RAYSUM *rs_local;
148   int mpi_argc = argc;
149   char **mpi_argv = (char **) argv;
150   double mpi_t1 = 0, mpi_t2 = 0, mpi_t, mpi_t_g;
151
152   MPI_Init(&mpi_argc, &mpi_argv);
153   MPI_Comm_dup (MPI_COMM_WORLD, &mpi_ct.comm);
154   MPI_Comm_size(mpi_ct.comm, &mpi_ct.nproc);
155   MPI_Comm_rank(mpi_ct.comm, &mpi_ct.my_rank);
156
157   if (mpi_ct.nproc > MPI_MAX_PROCESS) {
158     sys_error(ERR_FATAL, "Number of mpi processes (%d) exceeds max processes (%d)", mpi_ct.nproc, MPI_MAX_PROCESS);
159     exit(1);
160   }
161   time_start = MPI_Wtime();
162 #endif
163   
164 #ifdef MPI_CT
165   if (mpi_ct.my_rank == 0) {
166 #endif
167     strcpy(opt_desc, "");
168     strcpy(opt_phmfilename, "");
169     while (1) {
170       int c = getopt_long(argc, argv, "", phm2rs_options, NULL);
171       char *endptr = NULL;
172       char *endstr;
173       
174       if (c == -1)
175         break;
176       
177       switch (c) {
178       case O_PHANTOM:
179         if ((opt_phmnum = opt_set_phantom (optarg)) < 0) {
180           phm2rs_usage(argv[0]);
181           return (1);
182         }
183         phm = phm_create (opt_phmnum);
184         break;
185       case O_PHMFILE:
186 #ifdef MPI_CT
187         if (mpi_ct.my_rank == 0)
188           fprintf(stderr, "Can not read phantom from file in MPI mode\n");
189         return (1);
190 #endif
191         strncpy(opt_phmfilename, optarg, sizeof(opt_phmfilename));
192         phm = phm_create_from_file(opt_phmfilename);
193         break;
194       case O_VERBOSE:
195         opt_verbose = 1;
196         break;
197       case O_DEBUG:
198         opt_debug = 1;
199         break;
200         break;
201       case O_TRACE:
202         if ((opt_trace = opt_set_trace(optarg)) < 0) {
203           phm2rs_usage(argv[0]);
204           return (1);
205         }
206         break;
207       case O_DESC:
208         strncpy(opt_desc, optarg, sizeof(opt_desc));
209         break;
210       case O_ROTANGLE:
211         opt_rotangle = strtod(optarg, &endptr);
212         endstr = optarg + strlen(optarg);
213         if (endptr != endstr) {
214           fprintf(stderr,"Error setting --rotangle to %s\n", optarg);
215           phm2rs_usage(argv[0]);
216           return (1);
217         }
218         break;
219       case O_NRAY:
220         opt_nray = strtol(optarg, &endptr, 10);
221         endstr = optarg + strlen(optarg);
222         if (endptr != endstr) {
223           fprintf(stderr,"Error setting --nray to %s\n", optarg);
224           phm2rs_usage(argv[0]);
225           return (1);
226         }
227         break;
228         case O_VERSION:
229 #ifdef VERSION
230           fprintf(stdout, "Version %s\n", VERSION);
231 #else
232           fprintf(stderr, "Unknown version number");
233 #endif
234           exit(0);
235       case O_HELP:
236       case '?':
237         phm2rs_usage(argv[0]);
238         return (0);
239       default:
240         phm2rs_usage(argv[0]);
241         return (1);
242       }
243     }
244   
245     if (phm == NULL) {
246       fprintf(stderr, "No phantom defined\n");
247       phm2rs_usage(argv[0]);
248       return (1);
249     }
250     if (optind + 3 != argc) {
251       phm2rs_usage(argv[0]);
252       return (1);
253     }
254
255     opt_outfile = argv[optind];
256     opt_ndet = strtol(argv[optind+1], &endptr, 10);
257     endstr = argv[optind+1] + strlen(argv[optind+1]);
258     if (endptr != endstr) {
259       fprintf(stderr,"Error setting --ndet to %s\n", argv[optind+1]);
260       phm2rs_usage(argv[0]);
261       return (1);
262     }
263     opt_nview = strtol(argv[optind+2], &endptr, 10);
264     endstr = argv[optind+2] + strlen(argv[optind+2]);
265     if (endptr != endstr) {
266       fprintf(stderr,"Error setting --nview to %s\n", argv[optind+2]);
267       phm2rs_usage(argv[0]);
268       return (1);
269     }
270
271     snprintf(str, sizeof(str), 
272              "Raysum_Collect: NDet=%d, Nview=%d, NRay=%d, RotAngle=%.2f, ", 
273              opt_ndet, opt_nview, opt_nray, opt_rotangle);
274     if (opt_phmfilename[0]) {
275       strncat(str, "Phantom=", sizeof(str));
276       strncat(str, opt_phmfilename, sizeof(str));
277     } else if (opt_phmnum != -1) {
278       strncat(str, "Phantom=", sizeof(str));
279       strncat(str, name_of_phantom(opt_phmnum), sizeof(str));
280     }
281     if (opt_desc[0]) {
282       strncat(str, ": ", sizeof(str));
283       strncat(str, opt_desc, sizeof(str));
284     }
285     strncpy(opt_desc, str, sizeof(opt_desc));
286 #ifdef MPI_CT
287   }
288 #endif
289
290 #ifdef MPI_CT
291   MPI_Barrier(mpi_ct.comm);
292   MPI_Bcast(&opt_rotangle, 1, MPI_DOUBLE, 0, mpi_ct.comm);
293   MPI_Bcast(&opt_nview, 1, MPI_INT, 0, mpi_ct.comm);
294   MPI_Bcast(&opt_ndet, 1, MPI_INT, 0, mpi_ct.comm);
295   MPI_Bcast(&opt_nray, 1, MPI_INT, 0, mpi_ct.comm);
296   MPI_Bcast(&opt_phmnum, 1, MPI_INT, 0, mpi_ct.comm);
297   MPI_Bcast(&opt_verbose, 1, MPI_INT, 0, mpi_ct.comm);
298   MPI_Bcast(&opt_debug, 1, MPI_INT, 0, mpi_ct.comm);
299   MPI_Bcast(&opt_trace, 1, MPI_INT, 0, mpi_ct.comm);
300
301   if (mpi_ct.my_rank > 0 && opt_phmnum >= 0)
302     phm = phm_create (opt_phmnum);
303 #endif
304
305   opt_rotangle *= PI;
306   det = detector_create (phm, DETECTOR_PARALLEL, opt_ndet, opt_nview, opt_nray, opt_rotangle);
307
308 #ifdef MPI_CT
309   mpi_ct_calc_work_units(opt_nview);
310   if (mpi_ct.my_rank == 0) {
311     rs_global = raysum_create_from_det (opt_outfile, det);
312     raysum_alloc_views(rs_global);
313   }
314   
315   rs_local = raysum_create_from_det (NULL, det);
316   rs_local->nview = mpi_ct.local_work_units[mpi_ct.my_rank];
317   if (opt_debug)
318     printf("rs_local->nview = %d (process %d)\n", rs_local->nview, mpi_ct.my_rank);
319
320   if (opt_verbose)
321     mpi_t1 = MPI_Wtime();
322   raysum_collect (rs_local, det, phm, mpi_ct.start_work_unit[mpi_ct.my_rank], opt_trace, FALSE);
323   if (opt_verbose) {
324     mpi_t2 = MPI_Wtime();
325     mpi_t = mpi_t2 - mpi_t1;
326     MPI_Reduce(&mpi_t, &mpi_t_g, 1, MPI_DOUBLE, MPI_MAX, 0, mpi_ct.comm);
327     if (mpi_ct.my_rank == 0)
328       printf("Time to collect rs = %f secs, Max = %f secs\n", mpi_t, mpi_t_g);
329   }
330
331   if (opt_verbose)
332     mpi_t1 = MPI_Wtime();
333   mpi_gather_rs(rs_global, rs_local, opt_debug);
334   if (opt_verbose) {
335     mpi_t2 = MPI_Wtime();
336     mpi_t = mpi_t2 - mpi_t1;
337     MPI_Reduce(&mpi_t, &mpi_t_g, 1, MPI_DOUBLE, MPI_MAX, 0, mpi_ct.comm);
338     if (mpi_ct.my_rank == 0)
339       printf("Time to gather rs = %f secs, Max = %f secs\n", mpi_t, mpi_t_g);
340   }
341 #else
342   rs_global = raysum_create_from_det (opt_outfile, det);
343   raysum_collect (rs_global, det, phm, 0, opt_trace, FALSE);
344 #endif
345   
346 #ifndef MPI_CT
347   time_end = td_current_sec();
348 #else
349   time_end = MPI_Wtime();
350   if (mpi_ct.my_rank == 0) 
351 #endif
352     {
353       rs_global->calctime = time_end - time_start;
354       strncpy (rs_global->remark, opt_desc, sizeof(rs_global->remark));
355       if (opt_verbose) {
356         fprintf(stdout, "Remark: %s\n", rs_global->remark);
357         fprintf(stdout, "Time active = %.2f secs\n", rs_global->calctime);
358       }
359     }
360
361 #ifdef MPI_CT
362   if (mpi_ct.my_rank == 0) 
363 #endif
364     {
365       raysum_write (rs_global);
366       raysum_close (rs_global);
367     }
368
369   phm_free (phm);
370   detector_free (det);
371
372   return (0);
373 }
374
375
376 /* FUNCTION
377  *    mpi_gather_rs
378  *
379  * SYNOPSIS
380  *    Gather's raysums from all processes in rs_local in rs_global in process 0
381  */
382
383 #ifdef MPI_CT
384 void mpi_gather_rs (RAYSUM *rs_global, RAYSUM *rs_local, const int opt_debug)
385 {
386   int iproc;
387   int end_work_unit;
388   int iw;
389
390   end_work_unit = mpi_ct.local_work_units[mpi_ct.my_rank] - 1;
391   for (iw = 0; iw <= end_work_unit; iw++) {
392     MPI_Send(&rs_local->view[iw]->view_angle, 1, MPI_DOUBLE, 0, 0, mpi_ct.comm);
393     MPI_Send(&rs_local->view[iw]->ndet, 1, MPI_INT, 0, 0, mpi_ct.comm);
394     MPI_Send(rs_local->view[iw]->detval, rs_local->ndet, MPI_FLOAT, 0, 0, mpi_ct.comm);
395   }
396
397   if (mpi_ct.my_rank == 0) {
398     for (iproc = 0; iproc < mpi_ct.nproc; iproc++) {
399       end_work_unit = mpi_ct.start_work_unit[iproc] 
400         + mpi_ct.local_work_units[iproc] 
401         - 1;
402
403       if (opt_debug)
404         fprintf(stdout, "Recv rs data from process %d\n", iproc);
405
406       for (iw = mpi_ct.start_work_unit[iproc]; iw <= end_work_unit; iw++) {
407         MPI_Status status;
408
409         MPI_Recv(&rs_global->view[iw]->view_angle, 1, MPI_DOUBLE, iproc, 0, mpi_ct.comm, &status);
410         MPI_Recv(&rs_global->view[iw]->ndet, 1, MPI_INT, iproc, 0, mpi_ct.comm, &status);
411         MPI_Recv(rs_global->view[iw]->detval, rs_global->ndet, MPI_FLOAT, iproc, 0, mpi_ct.comm, &status);
412       }
413     }
414   }
415
416 }
417 #endif
418
419
420 #ifndef NO_MAIN
421 int 
422 main (const int argc, char *const argv[])
423 {
424   return (phm2rs_main(argc, argv));
425 }
426 #endif
427