/tomo/pyhst

To get this branch, use:
bzr branch http://darksoft.org/webbzr/tomo/pyhst
4 by csa
Initial import
1
/* ##  The PyHST program   is Copyright (C) 2002-2008 of the  */
2
/* ##  European Synchrotron Radiation Facility (ESRF). */
3
4
/* ##  You may use, distribute and copy the PyMCA XRF Toolkit under the terms of */
78 by Suren A. Chilingaryan
Add COPYING and fix license statements
5
/* ##  GNU General Public License version 3 or (at your any later version. */
4 by csa
Initial import
6
7
8
#define _FILE_OFFSET_BITS  64
9
10
11
#include"Python.h"
12
13
14
#ifndef _LARGEFILE_SOURCE
15
#define _LARGEFILE_SOURCE
16
#endif
17
18
#include <stdlib.h>
19
#include <stdio.h>
5 by csa
Join CPU and GPU versions with ifdefs in order to limit dublicating code
20
#include<string.h>
4 by csa
Initial import
21
#include <math.h>
22
5 by csa
Join CPU and GPU versions with ifdefs in order to limit dublicating code
23
#include<semaphore.h>
4 by csa
Initial import
24
10 by csa
Timing measurements and various fixes
25
#include <glib.h>
26
4 by csa
Initial import
27
#include"structmember.h"
28
34 by csa
Migration to numpy
29
#include "numpy/arrayobject.h"
4 by csa
Initial import
30
5 by csa
Join CPU and GPU versions with ifdefs in order to limit dublicating code
31
18 by csa
Big redesign (early commit)
32
#include "hst.h"
7 by csa
more consistent logging
33
#include "debug.h"
5 by csa
Join CPU and GPU versions with ifdefs in order to limit dublicating code
34
4 by csa
Initial import
35
/*
36
#ifdef LINUX
37
 #define _FILE_OFFSET_BITS  64
38
#endif
39
*/
40
41
42
43
/*
44
 * The error object to expose 
45
 */
46
47
static PyObject *ErrorObject;
48
#define onError(message)\
49
  { PyErr_SetString(ErrorObject, message); return NULL;}
50
51
52
53
typedef struct {
54
  PyObject_HEAD
18 by csa
Big redesign (early commit)
55
  HSTSetup setup;
56
  HSTContextPtr hst;
57
  
58
  FILE *output;              	/*  Identifier for file outp   */ 
152 by Suren A. Chilingaryan
Support fast writter
59
#ifdef HST_USE_FASTWRITER  
60
  fastwriter_t *fw;
61
#endif /* HST_USE_FASTWRITER */
7 by csa
more consistent logging
62
  PyObject *logger;		/* Message logger object (logging) */
38 by csa
Preload data from EDF images while computing slices
63
  void *ibuffer1, *ibuffer2;	/* Pinned storage for the sinograms */
64
  PyObject *SINO, *SINO1, *SINO2;
18 by csa
Big redesign (early commit)
65
  PyObject *SINOGRAMS;          /* Storage for the sinogram. Dimensions:  */
66
                                /* (num_bins,num_projections,dim_slices)  */
67
  PyObject *axis_corrections;   /*  Dimensions:  */
68
                                /* (num_projections)  */
228 by Suren A. Chilingaryan
Quality fixes (tex-based)
69
  int astra_scaling;
18 by csa
Big redesign (early commit)
70
  int BICUBIC;			/* ignored at the moment */
4 by csa
Initial import
71
72
  int do_custom_angles;
73
  float * angles_data;
74
75
  PyObject *FilterFunct  ; /* object coming from python adn defining the filter */
76
  int FilterFunctHasRamp;
77
  PyObject * FilterOwnerInstance   ;
132 by Suren A. Chilingaryan
Pipelined preprocessing (normalize & transpose)
78
#ifdef HW_USE_PARALLEL_IO
79
  PyObject ** Projections;
80
#endif /* HW_USE_PARALLEL_IO */
10 by csa
Timing measurements and various fixes
81
82
#ifdef PYHST_MEASURE_TIMINGS
83
  double recon_timer;
43 by csa
Option to disable preloading of image files, additional timers
84
  double comp_timer;
85
  double io_timer;
22 by csa
Timing reporting, few bug fixes
86
  PyObject *recon_info;	 //!< Information about used reconstructors (PyListObject)
10 by csa
Timing measurements and various fixes
87
#endif /* PYHST_MEASURE_TIMINGS */
88
4 by csa
Initial import
89
} PyHST;
90
91
staticforward PyTypeObject PyHSTtype;
92
93
#define is_PyHST(v) ((v)->ob_type == &tPyHSType )
94
10 by csa
Timing measurements and various fixes
95
7 by csa
more consistent logging
96
static void 
22 by csa
Timing reporting, few bug fixes
97
PyHST_log_handler(const gchar *log_domain, GLogLevelFlags log_levels, const gchar *message, PyObject *logger) {
7 by csa
more consistent logging
98
//  PyObject *arglist;
99
//  arglist = Py_BuildValue("(s)", message);
100
22 by csa
Timing reporting, few bug fixes
101
  if (log_levels&G_LOG_LEVEL_ERROR) PyObject_CallMethod(logger, "critical", "(s)", message);
102
  else if (log_levels&G_LOG_LEVEL_CRITICAL) PyObject_CallMethod(logger, "error", "(s)", message);
103
  else if (log_levels&G_LOG_LEVEL_WARNING) PyObject_CallMethod(logger, "warning", "(s)", message);
104
  else if (log_levels&G_LOG_LEVEL_MESSAGE) PyObject_CallMethod(logger, "info", "(s)", message);
105
  else if (log_levels&G_LOG_LEVEL_INFO) PyObject_CallMethod(logger, "info", "(s)", message);
106
  else PyObject_CallMethod(logger, "debug", "(s)", message);
7 by csa
more consistent logging
107
108
//  Py_DECREF(arglist);
109
}
110
4 by csa
Initial import
111
112
/*
113
 * kind of destructor called by garbage collector
114
 */
115
static void
116
PyHST_dealloc(PyHST *self)
117
{
22 by csa
Timing reporting, few bug fixes
118
#ifdef PYHST_MEASURE_TIMINGS
38 by csa
Preload data from EDF images while computing slices
119
  if (self->recon_info) Py_DECREF(self->recon_info);
22 by csa
Timing reporting, few bug fixes
120
#endif /* PYHST_MEASURE_TIMINGS */
38 by csa
Preload data from EDF images while computing slices
121
  
122
  if (self->hst) hst_destroy_context(self->hst);
18 by csa
Big redesign (early commit)
123
  
152 by Suren A. Chilingaryan
Support fast writter
124
125
#ifdef HST_USE_FASTWRITER  
126
  if (self->fw) {
127
    fastwriter_close(self->fw);
128
    fastwriter_destroy(self->fw);
129
  }
130
#endif /* HST_USE_FASTWRITER */
18 by csa
Big redesign (early commit)
131
  if (self->output) fclose(self->output);
10 by csa
Timing measurements and various fixes
132
152 by Suren A. Chilingaryan
Support fast writter
133
38 by csa
Preload data from EDF images while computing slices
134
  if (self->ibuffer2) {
135
    if (self->SINO2) Py_XDECREF(self->SINO2);
136
    hst_pinned_free(self->ibuffer2);
137
  }
138
  
139
  if (self->ibuffer1) {
140
    if (self->SINO1) Py_XDECREF(self->SINO1);
141
    hst_pinned_free(self->ibuffer1);
142
  } 
143
  
144
  if (self->SINO) Py_XDECREF(self->SINO);
145
  if (self->axis_corrections) Py_XDECREF(self->axis_corrections);
146
  if (self->logger) Py_XDECREF(self->logger);
132 by Suren A. Chilingaryan
Pipelined preprocessing (normalize & transpose)
147
148
#ifdef HW_USE_PARALLEL_IO
149
  if (self->Projections) free(self->Projections);
150
#endif /* HW_USE_PARALLEL_IO */
7 by csa
more consistent logging
151
 
4 by csa
Initial import
152
  if(self && 0 )
153
    free(self);
154
}
155
156
/*
157
 * creation and initialization of a new 
158
 */
159
160
static char PyHST_new_doc[]=""\
161
"/*"\
162
" * creation and initialization of a new PyHST. Lots of arguments:"\
163
"  if(!PyArg_ParseTuple(args,\"siiiiifffiiiOii:PyHST_new\", &outputname, &(res->oversampling),&(res->start_x),&(res->start_y),"\
164
"		       &(res->num_x),&(res->num_y),"\
165
"		       &(res->axis_position),&(res->angle_offset),&(res->angle_increment),"\
166
"			   &(res->no_filtering),"\
167
"		       &(res->num_bins),&(res->num_projections),"\
168
"		       &(res->SINOGRAMS),"\
169
"                       &(res->axis_corrections),"\
170
"                       &(res->BICUBIC),"\
171
"                       &(res->SUMRULE)"\
172
" ))"\
173
"    return NULL;"\
174
"   */";
175
176
static PyObject *
177
PyHST_new( PyObject *self, PyObject *args)
178
     /* return a new instance of edfobject */
179
{
37 by csa
Optimizations of EDF reading
180
  int err = 0;
4 by csa
Initial import
181
  PyHST* res;
182
  char * outputname;
168 by Suren A. Chilingaryan
Placeholders for DFI implementation
183
  char * method;
4 by csa
Initial import
184
185
  PyObject *custom_angles  ;
7 by csa
more consistent logging
186
  PyObject *result;
132 by Suren A. Chilingaryan
Pipelined preprocessing (normalize & transpose)
187
  PyObject *normalise;
7 by csa
more consistent logging
188
  int log_level;
4 by csa
Initial import
189
22 by csa
Timing reporting, few bug fixes
190
#ifdef PYHST_MEASURE_TIMINGS
191
  int i, j;
192
  HSTReconstructorConstContextPtr *reconstructors;
193
  HSTConstString recon_title;
194
  HSTConstString *timer_names;
195
  double *timer_values;
196
  
197
  PyObject *recon_dict;
198
  PyObject *timers_list;
199
  PyObject *pystr;
200
#endif /* PYHST_MEASURE_TIMINGS */
201
38 by csa
Preload data from EDF images while computing slices
202
  res = (PyHST*) PyObject_NEW(PyHST, &PyHSTtype);
203
204
  res->hst = NULL;
205
  res->output = NULL;
153 by Suren A. Chilingaryan
Compilation without fastwriter
206
#ifdef HST_USE_FASTWRITER  
152 by Suren A. Chilingaryan
Support fast writter
207
  res->fw = NULL;
153 by Suren A. Chilingaryan
Compilation without fastwriter
208
#endif /* HST_USE_FASTWRITER */
38 by csa
Preload data from EDF images while computing slices
209
  res->ibuffer1 = NULL;
210
  res->ibuffer2 = NULL;
211
  
212
#ifdef PYHST_MEASURE_TIMINGS
213
  res->recon_info = NULL;
214
#endif /* PYHST_MEASURE_TIMINGS */
4 by csa
Initial import
215
228 by Suren A. Chilingaryan
Quality fixes (tex-based)
216
#ifdef PYHST_ASTRA_SCALING
217
    res->astra_scaling = 1;
218
#else
219
    res->astra_scaling = 0;
220
#endif
221
168 by Suren A. Chilingaryan
Placeholders for DFI implementation
222
  if(!PyArg_ParseTuple(args,"OissiiiiiiiifffiiiOOiiOfiO:PyHST_new", 
18 by csa
Big redesign (early commit)
223
		       &(res->logger), 
151 by Suren A. Chilingaryan
Multislice mode: preload into the GPU memory complete slices
224
		       &(res->setup.max_slices),
18 by csa
Big redesign (early commit)
225
		       &outputname, 
168 by Suren A. Chilingaryan
Placeholders for DFI implementation
226
		       &method,
227
		       &(res->setup.fft_oversampling),
228
		       &(res->setup.dfi_kernel_size),
229
		       &(res->setup.dfi_kernel_points),
18 by csa
Big redesign (early commit)
230
		       &(res->setup.oversampling),
231
		       &(res->setup.start_x),
232
		       &(res->setup.start_y),
233
		       &(res->setup.num_x),
234
		       &(res->setup.num_y),
235
		       &(res->setup.axis_position),
236
		       &(res->setup.angle_offset),
237
		       &(res->setup.angle_increment),
238
		       &(res->setup.no_filtering),
239
		       &(res->setup.num_bins),
240
		       &(res->setup.num_projections),
38 by csa
Preload data from EDF images while computing slices
241
		       &(res->SINO),
4 by csa
Initial import
242
		       &(res->axis_corrections),
243
		       &(res->BICUBIC),
18 by csa
Big redesign (early commit)
244
		       &(res->setup.sum_rule),
4 by csa
Initial import
245
		       &custom_angles,
18 by csa
Big redesign (early commit)
246
		       &(res->setup.pente_zone),
132 by Suren A. Chilingaryan
Pipelined preprocessing (normalize & transpose)
247
		       &(res->setup.zerooffmask),
248
		       &normalise
38 by csa
Preload data from EDF images while computing slices
249
  )) {
250
    res->SINO = NULL;
251
    res->logger = NULL;
252
    res->axis_corrections = NULL;
253
254
    Py_DECREF(res);
4 by csa
Initial import
255
    return NULL;
38 by csa
Preload data from EDF images while computing slices
256
  }
132 by Suren A. Chilingaryan
Pipelined preprocessing (normalize & transpose)
257
258
  float *norm = (float*) ((PyArrayObject *) normalise)->data;
259
  res->setup.norm = norm[0];
260
38 by csa
Preload data from EDF images while computing slices
261
  Py_INCREF(res->logger);
262
  Py_INCREF(res->axis_corrections);
263
  Py_INCREF(res->SINO);
7 by csa
more consistent logging
264
  
18 by csa
Big redesign (early commit)
265
	// Configuring the logging subsystem 
7 by csa
more consistent logging
266
  result = PyObject_CallMethod(res->logger, "getEffectiveLevel", "()");
267
  if (result) {
268
     if (PyInt_Check(result)) log_level = PyInt_AsLong(result);
269
     else log_level = 0;
270
//     ||(!PyArg_ParseTuple(result, "i", &log_level))) log_level = 0;
271
     Py_DECREF(result);
272
  } else log_level = 0;
273
  
22 by csa
Timing reporting, few bug fixes
274
  pyhst_configure_logger(log_level, (GLogFunc)PyHST_log_handler, res->logger);
18 by csa
Big redesign (early commit)
275
132 by Suren A. Chilingaryan
Pipelined preprocessing (normalize & transpose)
276
#ifdef HW_USE_PARALLEL_IO
277
 res->Projections = (PyObject**)malloc(res->setup.num_projections * sizeof(PyObject*));
278
 if (!res->Projections) onError("Memory allocation");
279
#endif /* HW_USE_PARALLEL_IO */
280
18 by csa
Big redesign (early commit)
281
	// Processing various options
4 by csa
Initial import
282
  if(PyArray_Check( custom_angles)) {
283
    res->do_custom_angles = 1;
284
    if( ((PyArrayObject *)custom_angles  )  ->descr->type_num != PyArray_FLOAT ) onError("arg custom_angles  is not an array of float " ) ;
285
    res->angles_data = (float *) ((PyArrayObject *)custom_angles  )->data;
18 by csa
Big redesign (early commit)
286
    if(  ((PyArrayObject *)custom_angles  )->dimensions[0] <  res->setup.num_projections         ) {
4 by csa
Initial import
287
      onError("arg custom_angles  has not the good lenght " ) ;
288
    }
289
  } else {
290
    res->do_custom_angles = 0;
291
    res->angles_data =0;
292
  }
293
  
18 by csa
Big redesign (early commit)
294
  res->FilterFunct=0;
295
  res->FilterOwnerInstance=0;
296
38 by csa
Preload data from EDF images while computing slices
297
  if (res->SINO->ob_type == &PyList_Type) {
298
    int x, y, z, double_buffer = 1;
299
    
300
    PyObject *tuple = PyList_AsTuple(res->SINO);
301
    
302
    switch (((PyListObject*)(res->SINO))->ob_size) {
303
	case 3:
304
	    if ((tuple)&&(PyArg_ParseTuple(tuple, "iii", &x, &y, &z))) break;
305
	    else err = 1;
306
	break;
307
	case 4:
308
	    if ((tuple)&&(PyArg_ParseTuple(tuple, "iiii", &double_buffer, &x, &y, &z))) break;
309
	    else err = 1;
310
	break;
311
	default:
312
	    err = 1;
313
    }
314
    
228 by Suren A. Chilingaryan
Quality fixes (tex-based)
315
38 by csa
Preload data from EDF images while computing slices
316
    //pyhst_warning("double buffer: %i\n", double_buffer);
4 by csa
Initial import
317
38 by csa
Preload data from EDF images while computing slices
318
    if (err) {	    
319
	pyhst_error("ERROR : parsing buffer size");
320
	Py_DECREF(res);
321
	return NULL;
322
    } else {
37 by csa
Optimizations of EDF reading
323
	npy_intp dims[3] = {x, y, z};
133 by Suren A. Chilingaryan
Pinned OpenCL memory
324
	res->ibuffer1 = hst_pinned_malloc(x * y * z * sizeof(float), HST_PINNED_R);
38 by csa
Preload data from EDF images while computing slices
325
	if (res->ibuffer1) {
326
	    res->SINO1 = PyArray_SimpleNewFromData(3, dims, PyArray_FLOAT, res->ibuffer1);
327
	    if (!res->SINO1) err = 1;
37 by csa
Optimizations of EDF reading
328
	} else err = 1;
38 by csa
Preload data from EDF images while computing slices
329
	
330
	if (double_buffer > 1) {
133 by Suren A. Chilingaryan
Pinned OpenCL memory
331
	    res->ibuffer2 = hst_pinned_malloc(x * y * z * sizeof(float), HST_PINNED_R);
38 by csa
Preload data from EDF images while computing slices
332
	    if (res->ibuffer2) {
333
		res->SINO2 = PyArray_SimpleNewFromData(3, dims, PyArray_FLOAT, res->ibuffer2);
334
		if (!res->SINO2) err = 1;
335
	    } else err = 1;
336
	}
337
	
338
        if (err) {
339
	    pyhst_error("ERROR : allocating pinned memory");
340
	    Py_DECREF(res);
341
	    return NULL;
342
	} 
37 by csa
Optimizations of EDF reading
343
    }
344
  
38 by csa
Preload data from EDF images while computing slices
345
    res->SINOGRAMS = res->SINO1;
346
  } else {
347
    res->SINOGRAMS = res->SINO;
37 by csa
Optimizations of EDF reading
348
  }
349
168 by Suren A. Chilingaryan
Placeholders for DFI implementation
350
  if (!strcasecmp(method, "FBP")) {
351
    res->setup.method = HST_METHOD_FBP;
352
  } else if (!strcasecmp(method, "DFI")) {
353
    res->setup.method = HST_METHOD_DFI;
354
  } else {
355
      pyhst_error("ERROR : could not open file %s", outputname);
356
      Py_DECREF(res);
357
      return NULL;
358
  }
359
4 by csa
Initial import
360
  if(strlen(outputname)>0){  
152 by Suren A. Chilingaryan
Support fast writter
361
#ifdef HST_USE_FASTWRITER  
362
    res->fw = fastwriter_init(outputname, FASTWRITER_FLAGS_OVERWRITE);
363
    if (res->fw) {
155 by Suren A. Chilingaryan
Force long types
364
        fastwriter_set_buffer_size(res->fw, HST_USE_FASTWRITER * 1024ll * 1024ll);
152 by Suren A. Chilingaryan
Support fast writter
365
        if (fastwriter_open(res->fw, outputname, FASTWRITER_FLAGS_OVERWRITE)) {
366
            fastwriter_destroy(res->fw);
367
            res->fw = NULL;
368
        }
369
    }
370
    if (!res->fw) {
371
#else /* HST_USE_FASTWRITER */
4 by csa
Initial import
372
    res->output=fopen(outputname,"w");
373
    if(!res->output) {
152 by Suren A. Chilingaryan
Support fast writter
374
#endif /* HST_USE_FASTWRITER */
8 by csa
remove extra line breaks in log messages
375
      pyhst_error("ERROR : could not open file %s", outputname);
37 by csa
Optimizations of EDF reading
376
      Py_DECREF(res);
4 by csa
Initial import
377
      return NULL;
378
    }
38 by csa
Preload data from EDF images while computing slices
379
  } 
18 by csa
Big redesign (early commit)
380
  
381
  res->hst = hst_create_context();
382
  if ((!res->hst)||(hst_init_context(res->hst, &res->setup, res->do_custom_angles?res->angles_data:NULL, (float*) ((PyArrayObject *) res->axis_corrections)->data))) {
37 by csa
Optimizations of EDF reading
383
    Py_DECREF(res);
18 by csa
Big redesign (early commit)
384
    return NULL;
385
  }
152 by Suren A. Chilingaryan
Support fast writter
386
387
#ifdef HST_USE_FASTWRITER  
388
  hst_set_fastwriter(res->hst, res->fw);
389
#else /* HST_USE_FASTWRITER */
18 by csa
Big redesign (early commit)
390
  hst_set_output_file(res->hst, res->output);
152 by Suren A. Chilingaryan
Support fast writter
391
#endif /* HST_USE_FASTWRITER */
392
10 by csa
Timing measurements and various fixes
393
#ifdef PYHST_MEASURE_TIMINGS
394
  res->recon_timer = 0;
22 by csa
Timing reporting, few bug fixes
395
396
  reconstructors = hst_get_configured_reconstructors(res->hst);
397
  for (i = 0; reconstructors[i]; i++);
398
  
399
  res->recon_info = PyList_New(i);//(PyArrayObject*)PyArray_FromDims(1, &i, PyArray_OBJECT);
400
  if (res->recon_info) {
401
     for (i = 0; reconstructors[i]; i++) {
402
        recon_dict = PyDict_New();
403
	if (recon_dict) {
404
	    recon_title = hst_reconstructor_get_title(reconstructors[i]);
405
	    pystr = PyString_FromString(recon_title?recon_title:"Reconstructor");
406
	    if (pystr) {
407
		PyDict_SetItemString(recon_dict, "title", pystr);
408
		Py_DECREF(pystr);
409
	    }
410
	    
411
	    timer_names = hst_reconstructor_get_timers(reconstructors[i], NULL);
412
	    if (timer_names) {
413
		for (j = 0; timer_names[j]; j++);
414
		if (j) {
34 by csa
Migration to numpy
415
		    npy_intp dims = j;
416
		    timers_list = PyArray_SimpleNew(1, &dims, PyArray_DOUBLE);
22 by csa
Timing reporting, few bug fixes
417
		    if (timers_list) {
418
			timer_values = (double *) ((PyArrayObject*)timers_list)->data; 
419
			for (j = 0; timer_names[j]; j++) {
420
			    timer_values[j] = 0;
421
			}
422
			PyDict_SetItemString(recon_dict, "timers", timers_list);
423
			Py_DECREF(timers_list);
424
		    }
425
		    
426
		    if (timers_list) timers_list = PyList_New(j);
427
		    
428
		    if (timers_list) {
429
			for (j = 0; timer_names[j]; j++) {
430
			    pystr = PyString_FromString(timer_names[j]);
431
			    if (pystr) {
432
				    // A reference is stollen by this function
433
				PyList_SetItem(timers_list, j, pystr);
434
			    } else {
435
				Py_INCREF(Py_None);
436
				PyList_SetItem(timers_list, j, Py_None);
437
			    }
438
			}
439
			PyDict_SetItemString(recon_dict, "timer_names", timers_list);
440
			Py_DECREF(timers_list);
441
		    }
442
		    
443
		    timers_list = PyInt_FromLong(0);
444
		    if (timers_list) {
445
			PyDict_SetItemString(recon_dict, "slices", timers_list);
446
			Py_DECREF(timers_list);
447
		    }
448
		}
449
	    }
450
	    
451
	    PyList_SetItem(res->recon_info, i, recon_dict);
452
	    // SetItem steals a reference, we do not need Py_DECREF(recon_dict);
453
	} else {
454
	    Py_INCREF(Py_None);
455
	    PyList_SetItem(res->recon_info, i, Py_None);
456
	}
457
    }
458
  } else {
459
    Py_INCREF(Py_None);
460
    res->recon_info = Py_None;
461
  }
10 by csa
Timing measurements and various fixes
462
#endif /* PYHST_MEASURE_TIMINGS */
463
4 by csa
Initial import
464
  return (PyObject*) res;
465
}
466
45 by csa
Fixes measurements of I/O timings
467
4 by csa
Initial import
468
static PyObject *
469
PyHST_close( PyObject *self, PyObject *args)
470
     /* return a new instance of edfobject */
471
{
45 by csa
Fixes measurements of I/O timings
472
#ifdef PYHST_MEASURE_TIMINGS
473
  PyHST *ctx;
474
  GTimer *timer;
475
  double time;
476
   
477
  ctx = (PyHST *)self;
478
  timer = g_timer_new();
479
#endif /* PYHST_MEASURE_TIMINGS */
480
18 by csa
Big redesign (early commit)
481
  if (((PyHST *) self)->output) {
482
     hst_set_output_file(((PyHST*)self)->hst, NULL);
152 by Suren A. Chilingaryan
Support fast writter
483
#ifdef HST_USE_FASTWRITER  
484
    fastwriter_close(((PyHST*)self)->fw);
485
    fastwriter_destroy(((PyHST*)self)->fw);
486
#else /* HST_USE_FASTWRITER */
18 by csa
Big redesign (early commit)
487
     fclose( ( (PyHST *) self)->output);
488
     ((PyHST *) self)->output = NULL;
152 by Suren A. Chilingaryan
Support fast writter
489
#endif /* HST_USE_FASTWRITER */
18 by csa
Big redesign (early commit)
490
  }
45 by csa
Fixes measurements of I/O timings
491
492
#ifdef PYHST_MEASURE_TIMINGS
493
  g_timer_stop(timer);
494
  time = g_timer_elapsed(timer, NULL);
495
  ctx->io_timer += time;
496
  ctx->recon_timer += time;
141 by Suren A. Chilingaryan
Counter optimization
497
//  ctx->comp_timer += time;
45 by csa
Fixes measurements of I/O timings
498
  g_timer_destroy(timer);
499
#endif /* PYHST_MEASURE_TIMINGS */
500
4 by csa
Initial import
501
  Py_INCREF( Py_None);
502
  return Py_None;
503
504
}
505
506
18 by csa
Big redesign (early commit)
507
void PyHST_setFilter(PyHST *self, int dim_fft, float *FILTER) {
508
    int j;
509
510
    PyObject *FilterFunct;
511
    PyObject *FilterOwnerInstance;
512
    int FilterFunctHasRamp;
513
514
    PyObject * pyargs, *pyres;
515
516
    FilterFunct = self->FilterFunct;
517
    FilterOwnerInstance = self->FilterOwnerInstance; 
518
    FilterFunctHasRamp = self->FilterFunctHasRamp;
519
520
    if(FilterFunctHasRamp==0) {
521
      pyargs = Py_BuildValue("(O,f)", FilterOwnerInstance,0.5);
522
      pyres  = PyEval_CallObject(FilterFunct, pyargs);
523
    } else {
524
      pyargs = Py_BuildValue("(O,l,l)", FilterOwnerInstance,dim_fft/2, dim_fft);
525
      pyres  = PyEval_CallObject(FilterFunct, pyargs);
526
    }
527
528
    if (pyres==NULL) pyhst_fail("Filter have failed");
529
530
    if(FilterFunctHasRamp==0) {
531
      FILTER[1]= PyFloat_AsDouble(pyres)/dim_fft; ;             /* This is the real part of the highest frequency */
532
    } else {
533
      FILTER[1]= PyFloat_AsDouble(pyres)*2.0/dim_fft; ;             /* This is the real part of the highest frequency */
534
    }
535
536
    Py_DECREF(pyargs);
537
    Py_DECREF(pyres );
538
539
    if(FilterFunctHasRamp) {
23 by csa
Perform pair of convolutions using a single complex fourier transformation in CUDA reconstruction module (early commit)
540
      pyargs = Py_BuildValue("(O,i,i)", FilterOwnerInstance, 0, dim_fft);
18 by csa
Big redesign (early commit)
541
      pyres  = PyEval_CallObject(FilterFunct, pyargs);
542
      FILTER[0]= PyFloat_AsDouble(pyres)*2.0/dim_fft; ;             /* This is the real part of the highest frequency */ 
543
    } else {
544
      FILTER[0] = 0;
545
    }
546
547
    for(j=1;j<dim_fft / 2; j++) {
548
      if(FilterFunctHasRamp==0) {
549
550
	pyargs = Py_BuildValue("(O,f)",FilterOwnerInstance,j * 1.0 / dim_fft );
551
	pyres  = PyEval_CallObject(FilterFunct, pyargs);
552
553
	FILTER[2 * j] =   PyFloat_AsDouble(pyres)*    j * 2.0 / dim_fft/ dim_fft     ;
554
	FILTER[2 * j+1] = FILTER[2 * j];    
555
      } else {
556
557
	pyargs = Py_BuildValue("(O,i,i)",FilterOwnerInstance,j , dim_fft);
558
	pyres  = PyEval_CallObject(FilterFunct, pyargs);
559
560
561
	FILTER[2 * j] =   PyFloat_AsDouble(pyres)*     2.0/dim_fft     ;
562
	FILTER[2 * j+1] = FILTER[2 * j];    
563
      }
564
565
      
566
      Py_DECREF(pyargs);
567
      Py_DECREF(pyres );
568
569
    }
570
}
571
572
4 by csa
Initial import
573
static char PyHST_SetFilterFunct_doc[]=""\
574
"/*  Set the Filter with a python Function."\
575
"    needs one argument : a function(x)"\
576
"    X goes from -0.5 to 0.5 "\
577
"    the function must return a float"\
578
" */"\
579
"";
580
581
582
static PyObject * PyHST_SetFilterFunct(PyObject *self_a, PyObject *args)
583
{
584
  PyHST *self;
585
  self = (PyHST *) self_a;
586
  if(!PyArg_ParseTuple(args,"OOi:PyHST_SetFilterFunct",&self->FilterOwnerInstance  , &self->FilterFunct, &self->FilterFunctHasRamp) ) {
587
    return NULL;
588
  }
589
  Py_XINCREF(self->FilterFunct);
590
  Py_XINCREF(self->FilterOwnerInstance);
591
18 by csa
Big redesign (early commit)
592
  hst_set_filter(self->hst, self->FilterFunct?(HSTFilterFunction)PyHST_setFilter:NULL, self);
593
4 by csa
Initial import
594
  Py_INCREF( Py_None);
595
  return Py_None;
596
597
}
598
599
600
static char PyHST_calcSlices_doc[]=""\
601
"/* calculate a number of slices given as argument"\
602
"  Takes two arguments : "\
603
"if(!PyArg_ParseTuple(args,\"ii:PyHST_calcSlices\", &num_slices ))"\
604
"    return NULL;"\
605
" */"\
606
"";
607
608
/* l ' ordinamento dimensioni per SINOGRAMS est num_slices self->num_projections  self->num_bins 
609
610
  sarebbe saggio verificare en passant che corrisponde alle dimensioni di self->SINOGRAMS
611
*/
612
static char PyHST_calcMedian_doc[]="";
613
614
#define swap_float( a,b) tmp_swap=(a); (a)=(b); (b)=tmp_swap;
615
616
 int compare_floats (const void * A,
617
                           const void * B)
618
{
619
620
  float *a, *b;
621
  a=(float *)A;
622
  b=(float *)B;
623
624
625
  if (*a > *b)
626
    return 1;
627
  else if (*a < *b)
628
    return -1;
629
  else
630
    return 0;
631
}
632
633
float getmedian(float *room_for_median, int dim2 ) {
634
635
  qsort ( room_for_median , dim2 , sizeof(float), compare_floats );
636
637
638
  return 0.5*( room_for_median[ dim2/2 ]
639
	       + room_for_median[ (int)(dim2/2.0-0.1 )] 
640
	       ) ;
641
642
643
}
644
  
645
static PyObject *
646
PyHST_calcMedian(PyObject *self_a, PyObject *args)
647
{
648
  int num_slices;
649
  float *SLICE;
650
  int first_slice;
651
  int last_slice;
652
  PyHST *self;
653
  PyObject *options , *arr_a ; 
654
655
656
  char *padding;
657
  char *axis_to_the_center;
658
659
660
  int offset, stride;
661
  float * data, * toorder;
662
  int iv,ix,i;
663
  int nd;
37 by csa
Optimizations of EDF reading
664
  int dims[2];
4 by csa
Initial import
665
  int domean;
666
  double sum;
667
8 by csa
remove extra line breaks in log messages
668
  pyhst_debug(" sono in median ");
4 by csa
Initial import
669
670
  first_slice=0;
671
  options = 0 ; 
672
  padding = "E"; /* E as extrema, other value is 0 (zero) */
673
  axis_to_the_center = "N"; /* 'Y' or 'N' */
674
675
  self = (PyHST *) self_a;
676
677
  if(!PyArg_ParseTuple(args,"ii|O:PyHST_calcSlices", &num_slices, &domean, &options))
678
    return NULL;
679
  last_slice=first_slice+num_slices-1;
680
18 by csa
Big redesign (early commit)
681
  SLICE=malloc( num_slices * self->setup.num_bins* sizeof(float) );
4 by csa
Initial import
682
18 by csa
Big redesign (early commit)
683
  if( ((PyArrayObject *) self->SINOGRAMS)->dimensions[1] !=  self->setup.num_projections) {
684
    pyhst_fail("  ((PyArrayObject *) self->SINOGRAMS)->dimensions[0] !=  self->num_projections   %d %d  ",  ((PyArrayObject *) self->SINOGRAMS)->dimensions[1] ,  self->setup.num_projections );
4 by csa
Initial import
685
  }
18 by csa
Big redesign (early commit)
686
  if( ((PyArrayObject *) self->SINOGRAMS)->dimensions[2] !=  self->setup.num_bins) {
687
    pyhst_fail("  ((PyArrayObject *) self->SINOGRAMS)->dimensions[2] !=  self->num_bins  %d %d  ",  ((PyArrayObject *) self->SINOGRAMS)->dimensions[2] ,  self->setup.num_bins );
4 by csa
Initial import
688
  }
689
690
  /*   if( ((PyArrayObject *) self->SINOGRAMS)->dimensions[0] !=  num_slices ) { */
8 by csa
remove extra line breaks in log messages
691
  /*     pyhst_debug("  ((PyArrayObject *) self->SINOGRAMS)->dimensions[0] !=  num_slices   %d %d  ",  ((PyArrayObject *) self->SINOGRAMS)->dimensions[0] , num_slices  ); */
4 by csa
Initial import
692
  /*     exit(0); */
693
  /*   } */
694
  
695
696
  data = (float*) ((PyArrayObject *) self->SINOGRAMS)->data;
18 by csa
Big redesign (early commit)
697
  toorder = malloc(  self->setup.num_projections*  sizeof(float));
4 by csa
Initial import
698
  for(iv=0; iv<num_slices; iv++) {
18 by csa
Big redesign (early commit)
699
    for(ix=0; ix<self->setup.num_bins; ix++) {
4 by csa
Initial import
700
      
18 by csa
Big redesign (early commit)
701
      offset = iv*self->setup.num_bins*self->setup.num_projections + ix;
702
      stride = self->setup.num_bins;
703
      for(i=0; i<self->setup.num_projections;i++) {
4 by csa
Initial import
704
	toorder[i] = data[offset+i*stride];
705
      }
706
      if(domean==0){
18 by csa
Big redesign (early commit)
707
	SLICE[iv*self->setup.num_bins  + ix] =getmedian(toorder, self->setup.num_projections);
4 by csa
Initial import
708
      } else {
709
	sum=0;
18 by csa
Big redesign (early commit)
710
	for(i=0; i<self->setup.num_projections;i++) {
4 by csa
Initial import
711
	  sum += toorder[i];
712
	}
18 by csa
Big redesign (early commit)
713
	SLICE[iv*self->setup.num_bins  + ix] = sum / self->setup.num_projections;
4 by csa
Initial import
714
      }
715
    }
716
  }
717
 
718
  nd=2;
719
  dims[0] =num_slices ;
18 by csa
Big redesign (early commit)
720
  dims[1] = self->setup.num_bins;
4 by csa
Initial import
721
  arr_a = PyArray_FromDims(nd,dims,PyArray_FLOAT ) ;
18 by csa
Big redesign (early commit)
722
  memcpy( ((PyArrayObject *) arr_a)->data, SLICE  ,   num_slices * self->setup.num_bins*sizeof(float) );
4 by csa
Initial import
723
724
  free(toorder);
725
  free(SLICE);
726
  return PyArray_Return((PyArrayObject *) arr_a);
727
728
}
729
18 by csa
Big redesign (early commit)
730
static PyObject *
731
PyHST_RECON(PyHST *self, int num_slices, PyObject *options, PyArrayObject *Oslice) {
6 by csa
GPU based FFT: first test
732
  int err;
18 by csa
Big redesign (early commit)
733
  
11 by csa
Eextensive pointer usage is reduced and c_hst_recon is beutificated with astyle
734
  PyObject * dic_key;
735
  PyObject * dic_value;
736
737
  char *padding;
738
  char *axis_to_the_center;
739
740
#ifdef PYHST_MEASURE_TIMINGS
741
  GTimer *timer;
22 by csa
Timing reporting, few bug fixes
742
743
  int i;
744
  HSTReconstructorConstContextPtr *reconstructors;
745
  PyObject *recon_dict;
746
  PyObject *timers;
747
  PyObject *slices;
11 by csa
Eextensive pointer usage is reduced and c_hst_recon is beutificated with astyle
748
#endif /* PYHST_MEASURE_TIMINGS */
749
750
  padding = "E"; /* E as extrema, other value is 0 (zero) */
751
  axis_to_the_center = "N"; /* 'Y' or 'N' */
752
753
  if(options!=0) {
754
    dic_key   =  PyString_FromString("padding");
755
    dic_value =  PyDict_GetItem(options, dic_key);
756
    if( dic_value  ) {
757
      padding   =  PyString_AsString(dic_value );  
758
    }
759
    Py_DECREF(dic_key);
760
    dic_key   =  PyString_FromString("axis_to_the_center");
761
    dic_value =  PyDict_GetItem(options, dic_key);
762
    if( dic_value  ) {
763
      axis_to_the_center   =  PyString_AsString(dic_value );  
764
    }
765
    Py_DECREF(dic_key);
766
  }
767
18 by csa
Big redesign (early commit)
768
    // padding[0]=='E' pads with extrema, '0' ( zero ) with zeros , defaults to 'E'
769
  hst_set_padding(self->hst, *padding == '0');
770
771
    // /* 'Y' or 'N' */
772
  hst_set_axis_mode(self->hst, *axis_to_the_center == 'Y');
11 by csa
Eextensive pointer usage is reduced and c_hst_recon is beutificated with astyle
773
774
#ifdef PYHST_MEASURE_TIMINGS
775
  timer = g_timer_new();
776
#endif /* PYHST_MEASURE_TIMINGS */
777
38 by csa
Preload data from EDF images while computing slices
778
  if ((Oslice)||(!self->ibuffer2)) {
779
     err = hst_reconstruct_slices(self->hst,
780
    	num_slices,
18 by csa
Big redesign (early commit)
781
        Oslice?(float*)Oslice->data:NULL,
782
	(float*) ((PyArrayObject *) self->SINOGRAMS)->data
38 by csa
Preload data from EDF images while computing slices
783
    );
784
  } else {
785
     hst_reconstruct_wait(self->hst);
786
     
787
     err = hst_reconstruct_start(self->hst, num_slices, (float*) ((PyArrayObject *) self->SINOGRAMS)->data);
788
     
789
     if (self->SINOGRAMS == self->SINO1) self->SINOGRAMS = self->SINO2;
790
     else self->SINOGRAMS = self->SINO1;
791
  }
792
18 by csa
Big redesign (early commit)
793
  check_code(err, "hst_reconstruct_slices");
11 by csa
Eextensive pointer usage is reduced and c_hst_recon is beutificated with astyle
794
795
#ifdef PYHST_MEASURE_TIMINGS
796
  if (timer) {
797
    self->recon_timer += g_timer_elapsed(timer, NULL);
798
    g_timer_destroy(timer);
799
  }
43 by csa
Option to disable preloading of image files, additional timers
800
801
  self->comp_timer = hst_get_recon_timer(self->hst);
802
  self->io_timer = hst_get_io_timer(self->hst);
22 by csa
Timing reporting, few bug fixes
803
  
804
  if (self->recon_info) {
805
     reconstructors = hst_get_configured_reconstructors(self->hst);
806
     for (i = 0; reconstructors[i]; i++) {
807
        recon_dict = PyList_GetItem(self->recon_info, i);
808
	if (recon_dict) {
809
	    timers = PyDict_GetItemString(recon_dict, "timers");
810
	    if (timers) {
811
		hst_reconstructor_get_timers(reconstructors[i], (double *) ((PyArrayObject*)timers)->data);
812
	    }
813
	    
814
	    slices  = PyInt_FromLong(reconstructors[i]->processed_slices);
815
	    if (slices) {
816
		PyDict_SetItemString(recon_dict, "slices", slices);
817
		Py_DECREF(slices);
818
	    }
819
	}
820
    }
821
  }
11 by csa
Eextensive pointer usage is reduced and c_hst_recon is beutificated with astyle
822
#endif /* PYHST_MEASURE_TIMINGS */
823
824
  Py_INCREF( Py_None);
825
  return Py_None;
826
}
827
828
829
static PyObject *
830
PyHST_calcSlices(PyObject *self_a, PyObject *args)
831
{
832
  PyHST *self;
833
834
  int num_slices;
835
  PyObject *options ; 
836
837
  self = (PyHST *) self_a;
838
839
  if(!PyArg_ParseTuple(args,"i|O:PyHST_calcSlices", &num_slices,  &options))
840
    return NULL;
841
842
  return PyHST_RECON(self, num_slices, options, NULL);
843
}
844
132 by Suren A. Chilingaryan
Pipelined preprocessing (normalize & transpose)
845
846
847
static char PyHST_startPreprocessing_doc[]="";
848
static PyObject *
849
PyHST_startPreprocessing(PyObject *self_a, PyObject *args) {
850
  PyHST *self;
851
852
  int num_slices;
853
854
  self = (PyHST *) self_a;
855
856
  if(!PyArg_ParseTuple(args,"i:PyHST_calcSlices", &num_slices))
857
    return NULL;
858
859
  hst_preprocess_start(self->hst, num_slices, (float*) ((PyArrayObject *) self->SINOGRAMS)->data);
860
  
861
  Py_INCREF( Py_None);
862
  return Py_None;
863
}
864
865
static char PyHST_waitPreprocessing_doc[]="";
866
static PyObject *
867
PyHST_waitPreprocessing(PyObject *self_a, PyObject *args) {
868
  int i;
869
  PyHST *self;
870
871
  self = (PyHST *) self_a;
872
873
  hst_preprocess_wait(self->hst);
874
  
875
#ifdef HW_USE_PARALLEL_IO
876
  for (i = 0; i < self->setup.num_projections; i++) {
877
    Py_DECREF(self->Projections[i]);
878
  }
879
#endif /* HW_USE_PARALLEL_IO */
880
  
881
  Py_INCREF( Py_None);
882
  return Py_None;
883
}
884
885
886
static char PyHST_transposeSlices_doc[]=""\
887
"/* transposes a number of slices given as argument"\
888
" */"\
889
"";
890
static PyObject *
891
PyHST_transposeSlices(PyObject *self_a, PyObject *args)
892
{
893
  PyHST *self;
894
895
  int err;
896
  int proj;
897
  PyObject *item; 
898
899
  self = (PyHST *) self_a;
900
901
  if(!PyArg_ParseTuple(args,"Oi:PyHST_calcSlices", &item, &proj))
902
    return NULL;
903
904
  Py_INCREF(item);
905
  
906
  float *in = (float*) ((PyArrayObject *) item)->data;
907
  err =  hst_preprocess_projection(self->hst, proj, in);
908
909
#ifdef HW_USE_PARALLEL_IO
910
  self->Projections[proj] = item;
911
#else /* HW_USE_PARALLEL_IO */
912
  Py_DECREF(item);
913
#endif /* HW_USE_PARALLEL_IO */
914
915
  Py_INCREF( Py_None);
916
  return Py_None;
917
}
918
919
920
11 by csa
Eextensive pointer usage is reduced and c_hst_recon is beutificated with astyle
921
static char PyHST_calcSlicesMemory_doc[]=""\
922
"/* calculate a number of slices given as argument"\
923
"  Takes three arguments : "\
924
"if(!PyArg_ParseTuple(args,\"iiO:PyHST_calcSlices\", &num_slices,  &Oslice))"\
925
"    return NULL;"\
926
" */"\
927
"";
928
static PyObject *
929
PyHST_calcSlicesMemory(PyObject *self_a, PyObject *args)
930
{
931
  PyHST *self;
932
933
  int num_slices;
934
  PyObject *options ; 
935
  PyArrayObject * Oslice ; 
936
937
  self = (PyHST *) self_a;
938
939
  if(!PyArg_ParseTuple(args,"iO|O:PyHST_calcSlicesMemory", &num_slices,  &Oslice, &options )  )  
940
    return NULL;
941
942
  return PyHST_RECON(self, num_slices, options, Oslice);
943
}
944
132 by Suren A. Chilingaryan
Pipelined preprocessing (normalize & transpose)
945
946
38 by csa
Preload data from EDF images while computing slices
947
static PyObject *
948
PyHST_waitCompletion(PyObject *self_a, PyObject *args)
949
{
950
  PyHST *self;
951
  self = (PyHST *) self_a;
952
42 by csa
Fix measuring overall reconstruction time
953
#ifdef PYHST_MEASURE_TIMINGS
43 by csa
Option to disable preloading of image files, additional timers
954
  int i;
955
  HSTReconstructorConstContextPtr *reconstructors;
956
  PyObject *recon_dict;
957
  PyObject *timers;
958
  PyObject *slices;
959
42 by csa
Fix measuring overall reconstruction time
960
  GTimer *timer;
961
962
  timer = g_timer_new();
963
#endif /* PYHST_MEASURE_TIMINGS */
964
38 by csa
Preload data from EDF images while computing slices
965
  hst_reconstruct_wait(self->hst);
966
42 by csa
Fix measuring overall reconstruction time
967
#ifdef PYHST_MEASURE_TIMINGS
968
  if (timer) {
969
    self->recon_timer += g_timer_elapsed(timer, NULL);
970
    g_timer_destroy(timer);
971
  }
43 by csa
Option to disable preloading of image files, additional timers
972
973
  self->comp_timer = hst_get_recon_timer(self->hst);
974
  self->io_timer = hst_get_io_timer(self->hst);
975
  
976
  if (self->recon_info) {
977
     reconstructors = hst_get_configured_reconstructors(self->hst);
978
     for (i = 0; reconstructors[i]; i++) {
979
        recon_dict = PyList_GetItem(self->recon_info, i);
980
	if (recon_dict) {
981
	    timers = PyDict_GetItemString(recon_dict, "timers");
982
	    if (timers) {
983
		hst_reconstructor_get_timers(reconstructors[i], (double *) ((PyArrayObject*)timers)->data);
984
	    }
985
	    
986
	    slices  = PyInt_FromLong(reconstructors[i]->processed_slices);
987
	    if (slices) {
988
		PyDict_SetItemString(recon_dict, "slices", slices);
989
		Py_DECREF(slices);
990
	    }
991
	}
992
    }
993
  }
994
42 by csa
Fix measuring overall reconstruction time
995
#endif /* PYHST_MEASURE_TIMINGS */
996
38 by csa
Preload data from EDF images while computing slices
997
  Py_INCREF( Py_None);
998
  return Py_None;
999
}
1000
11 by csa
Eextensive pointer usage is reduced and c_hst_recon is beutificated with astyle
1001
1002
static PyMethodDef PyHST_methods[]={
132 by Suren A. Chilingaryan
Pipelined preprocessing (normalize & transpose)
1003
  {"startPreprocessing",(PyCFunction) PyHST_startPreprocessing, METH_VARARGS,PyHST_startPreprocessing_doc},
1004
  {"waitPreprocessing",(PyCFunction) PyHST_waitPreprocessing, METH_VARARGS,PyHST_waitPreprocessing_doc},
1005
  {"transposeSlices",(PyCFunction) PyHST_transposeSlices, METH_VARARGS,PyHST_transposeSlices_doc},
11 by csa
Eextensive pointer usage is reduced and c_hst_recon is beutificated with astyle
1006
  {"calcSlices",(PyCFunction) PyHST_calcSlices, METH_VARARGS,PyHST_calcSlices_doc},
1007
  {"calcMedian",(PyCFunction) PyHST_calcMedian, METH_VARARGS,PyHST_calcMedian_doc},
1008
  {"calcSlicesMemory",(PyCFunction) PyHST_calcSlicesMemory, METH_VARARGS,PyHST_calcSlicesMemory_doc},
38 by csa
Preload data from EDF images while computing slices
1009
  {"waitCompletion",(PyCFunction) PyHST_waitCompletion, METH_VARARGS,NULL},
11 by csa
Eextensive pointer usage is reduced and c_hst_recon is beutificated with astyle
1010
  {"setFilterFunct",(PyCFunction) PyHST_SetFilterFunct, METH_VARARGS,PyHST_SetFilterFunct_doc},
1011
  {"close", (PyCFunction) PyHST_close,  METH_VARARGS, NULL    },
1012
  { NULL, NULL}
1013
};
1014
1015
1016
static struct memberlist PyHST_memberlist[]={
37 by csa
Optimizations of EDF reading
1017
    {"SINOGRAMS", T_OBJECT, offsetof(PyHST, SINOGRAMS)},
228 by Suren A. Chilingaryan
Quality fixes (tex-based)
1018
    {"astra_scaling", T_INT, offsetof(PyHST, astra_scaling)},
41 by csa
Bug fixes
1019
#ifdef PYHST_MEASURE_TIMINGS
11 by csa
Eextensive pointer usage is reduced and c_hst_recon is beutificated with astyle
1020
    {"recon_timer", T_DOUBLE, offsetof(PyHST, recon_timer)},
43 by csa
Option to disable preloading of image files, additional timers
1021
    {"comp_timer", T_DOUBLE, offsetof(PyHST, comp_timer)},
1022
    {"io_timer", T_DOUBLE, offsetof(PyHST, io_timer)},
22 by csa
Timing reporting, few bug fixes
1023
    {"recon", T_OBJECT, offsetof(PyHST, recon_info)},
11 by csa
Eextensive pointer usage is reduced and c_hst_recon is beutificated with astyle
1024
#endif /* PYHST_MEASURE_TIMINGS */
1025
    { NULL }
1026
};
1027
1028
static PyMethodDef PyHST_functions[] = {
1029
  {"PyHST", PyHST_new, METH_VARARGS, PyHST_new_doc },
1030
  { NULL, NULL}
1031
};
1032
1033
1034
1035
static PyObject *
1036
PyHST_getattr(PyHST *self, char *attr) 
1037
{
1038
  PyObject *res;
1039
1040
  res= Py_FindMethod(PyHST_methods, (PyObject*) self, attr);
1041
  if(NULL !=res)
1042
    return res;
1043
  else {
1044
    PyErr_Clear();
1045
    return PyMember_Get((char*) self,PyHST_memberlist, attr);
1046
  }
1047
}
1048
1049
1050
22 by csa
Timing reporting, few bug fixes
1051
static PyObject *logger = NULL;
1052
20 by csa
do more correct initialization
1053
void finiPyHST_c(void)
1054
{
1055
  hst_free();
22 by csa
Timing reporting, few bug fixes
1056
  if (logger) {
1057
     pyhst_configure_logger(0, (GLogFunc)NULL, NULL);
1058
     Py_DECREF(logger);
1059
  }
20 by csa
do more correct initialization
1060
}
1061
11 by csa
Eextensive pointer usage is reduced and c_hst_recon is beutificated with astyle
1062
void initPyHST_c(void)
1063
{
22 by csa
Timing reporting, few bug fixes
1064
  PyObject *logger_mod;
11 by csa
Eextensive pointer usage is reduced and c_hst_recon is beutificated with astyle
1065
  PyObject *m, *d;
142 by Suren A. Chilingaryan
Adjust number of slices per block to number of reconstructors
1066
  size_t n_rec;
22 by csa
Timing reporting, few bug fixes
1067
  
11 by csa
Eextensive pointer usage is reduced and c_hst_recon is beutificated with astyle
1068
  m = Py_InitModule("PyHST_c", PyHST_functions);
1069
  d = PyModule_GetDict(m);
1070
  ErrorObject = Py_BuildValue("s","PyHST_c.error");
1071
  PyDict_SetItemString(d,"error", ErrorObject);
1072
  if(PyErr_Occurred())
1073
    Py_FatalError("can't initialize module PyHST_c");
20 by csa
do more correct initialization
1074
  else {
22 by csa
Timing reporting, few bug fixes
1075
    logger_mod = PyImport_ImportModule("logger");
1076
    if (logger_mod) {
1077
	logger = PyObject_GetAttrString(logger_mod, "logger");
1078
	Py_DECREF(logger_mod);
1079
	if (logger) {
1080
	    pyhst_configure_logger(0, (GLogFunc)PyHST_log_handler, logger);
1081
	}
1082
    }
1083
20 by csa
do more correct initialization
1084
    hst_init();
142 by Suren A. Chilingaryan
Adjust number of slices per block to number of reconstructors
1085
    n_rec = hst_get_balanced_number_of_reconstructors();
1086
    PyModule_AddIntConstant(m, "RECONSTRUCTORS", n_rec);
1087
    
20 by csa
do more correct initialization
1088
    Py_AtExit(finiPyHST_c);
1089
  }
11 by csa
Eextensive pointer usage is reduced and c_hst_recon is beutificated with astyle
1090
#ifdef import_array
1091
  import_array();
1092
#endif
1093
}
1094
1095
1096
1097
static PyTypeObject PyHSTtype = {
1098
  PyObject_HEAD_INIT(&PyType_Type)
1099
  0,
1100
  "PyHST",
1101
  sizeof(PyHST),
1102
  0,
1103
  (destructor) PyHST_dealloc,
1104
  0,
1105
  (getattrfunc) PyHST_getattr,
1106
};
1107