TPCCLIB
Loading...
Searching...
No Matches
misc_model.c File Reference

Miscellaneous functions for PET modelling. More...

#include "libtpcmodext.h"

Go to the source code of this file.

Functions

int dftInterpolateForIMG (DFT *input, IMG *img, int frame_nr, DFT *output, double *ti1, double *ti2, int verbose, char *status)
 
int imgTimeIntegral (IMG *img, float t1, float t2, IMG *iimg, int calc_mode, char *status, int verbose)
 
int dftAllocateWithIMG (DFT *dft, int tacNr, IMG *img)
 
int sif2dft (SIF *sif, DFT *dft)
 
int sifAllocateWithIMG (SIF *sif, IMG *img, int doCounts, int verbose)
 

Detailed Description

Miscellaneous functions for PET modelling.

Author
Vesa Oikonen

Definition in file misc_model.c.

Function Documentation

◆ dftAllocateWithIMG()

int dftAllocateWithIMG ( DFT * dft,
int tacNr,
IMG * img )

Allocate memory for DFT based on information in IMG.

See also
sifAllocateWithIMG
Returns
Returns 0 if successful, otherwise <>0.
Parameters
dftPointer to initiated DFT struct which will be allocated here.
tacNrNr of TACs to be allocated in DFT; if zero, then TACs for all IMG pixels is allocated, but it may lead to out of memory error.
imgPointer to IMG struct from where necessary information is read.

Definition at line 296 of file misc_model.c.

304 {
305 int ri, fi, ret;
306
307 // Check the input data
308 if(dft==NULL || img==NULL) return 1;
309 if(img->status!=IMG_STATUS_OCCUPIED) return 2;
310 if(img->dimt<1) return 3;
311
312 // Get tacNr from image dimensions if necessary
313 if(tacNr<1) {
314 tacNr=img->dimz*img->dimx*img->dimy;
315 if(tacNr<1) return 4;
316 }
317
318 // Allocate memory
319 ret=dftSetmem(dft, img->dimt, tacNr);
320 if(ret) return(100+ret);
321 dft->voiNr=tacNr;
322 dft->frameNr=img->dimt;
323
324 // Set header contents
326 for(fi=0; fi<dft->frameNr; fi++) {
327 dft->x[fi]=img->mid[fi];
328 dft->x1[fi]=img->start[fi];
329 dft->x2[fi]=img->end[fi];
330 }
331 dft->isweight=0;
332 strncpy(dft->unit, imgUnit(img->unit), MAX_UNITS_LEN);
333 dft->timeunit=TUNIT_SEC;
335 for(ri=0; ri<dft->voiNr; ri++) {
336 snprintf(dft->voi[ri].voiname, 6, "%06d", ri+1);
337 strcpy(dft->voi[ri].name, dft->voi[ri].voiname);
338 }
340
341 return 0;
342}
int dftSetmem(DFT *data, int frameNr, int voiNr)
Definition dft.c:57
char * imgUnit(int dunit)
Definition imgunits.c:315
#define DFT_FORMAT_STANDARD
#define DFT_TIME_STARTEND
#define IMG_STATUS_OCCUPIED
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition strext.c:245
#define MAX_STUDYNR_LEN
Definition libtpcmisc.h:163
#define MAX_UNITS_LEN
Definition libtpcmisc.h:95
int _type
int timetype
Voi * voi
int timeunit
char studynr[MAX_STUDYNR_LEN+1]
double * x1
int voiNr
double * x2
int frameNr
int isweight
double * x
char unit[MAX_UNITS_LEN+1]
unsigned short int dimx
char unit
char status
unsigned short int dimt
float * start
unsigned short int dimz
unsigned short int dimy
float * end
char studyNr[MAX_STUDYNR_LEN+1]
float * mid
char voiname[MAX_REGIONSUBNAME_LEN+1]
char name[MAX_REGIONNAME_LEN+1]

Referenced by imgMaskPixelTACs().

◆ dftInterpolateForIMG()

int dftInterpolateForIMG ( DFT * input,
IMG * img,
int frame_nr,
DFT * output,
double * ti1,
double * ti2,
int verbose,
char * status )

Interpolate (and integrate) TAC data to sample times that are given with IMG data. Input frame lengths are taken into account if they are available in DFT or if the framing is the same as in IMG data.

Returns
Returns 0 if successful, and <>0 in case of an error.
Parameters
inputData which is interpolated.
imgData to which (sample times) the interpolation is done.
frame_nrNumber of IMG frames that are needed; can be set to 0 if all frames can be included.
outputPointer to initiated DFT into which interpolated values and integrals will be written at input sample times and units.
ti1First time of input data before interpolation (in input time units); use this to check that required time range was measured; NULL if not needed.
ti2Last time of input data before interpolation (in input time units); use this to check that required time range was measured; NULL if not needed.
verboseVerbose level; set to zero to not to print any comments.
statusPointer to a string (allocated for at least 64 chars) where error message or other execution status will be written; enter NULL, if not needed.

Definition at line 17 of file misc_model.c.

38 {
39 /* Check input */
40 if(verbose>0) {
41 printf("%s(*inp, *img, %d, *out, *ti1, *ti2, %d, status)\n", __func__, frame_nr, verbose);
42 fflush(stdout);
43 }
44 if(input==NULL || img==NULL || output==NULL) {
45 if(status!=NULL) strcpy(status, "program error");
46 return 1;
47 }
48 if(input->frameNr<1 || input->voiNr<1 || img->dimt<1) {
49 if(status!=NULL) strcpy(status, "no pet data");
50 return 2;
51 }
52 if(input->timeunit!=TUNIT_MIN && input->timeunit!=TUNIT_SEC) {
53 if(status!=NULL) strcpy(status, "unknown time units");
54 return 3;
55 }
56 if(frame_nr<1 || frame_nr>img->dimt) frame_nr=img->dimt;
57 /* Set ti1 and ti2 */
58 if(ti1!=NULL) {
59 if(input->timetype==DFT_TIME_STARTEND)
60 *ti1=input->x1[0]; else *ti1=input->x[0];
61 }
62 if(ti2!=NULL) {
63 if(input->timetype==DFT_TIME_STARTEND) *ti2=input->x2[input->frameNr-1];
64 else *ti2=input->x[input->frameNr-1];
65 }
66
67 /* Delete any previous data */
68 dftEmpty(output);
69
70 /* Allocate memory for interpolated data */
71 if(verbose>10) printf("allocating memory for interpolated data\n");
72 if(dftAllocateWithHeader(output, frame_nr, input->voiNr, input)) {
73 if(status!=NULL) strcpy(status, "memory allocation error");
74 return 11;
75 }
76 output->voiNr=input->voiNr; output->frameNr=frame_nr;
77
78 /* Set output times */
79 if(copy_times_from_img_to_dft(img, output, verbose)!=0) {
80 if(status!=NULL) strcpy(status, "frame time error");
81 dftEmpty(output); return 12;
82 }
83 if(verbose>10) {
84 printf("time range := %g - %g %s\n", output->x[0],
85 output->x[output->frameNr-1], petTunit(output->timeunit));
86 printf(" timetype := %d\n", output->timetype);
87 }
88
89 // Check if input and output data do have the same frame times already
90 if(check_times_dft_vs_dft(input, output, verbose)==1 && input->frameNr>=output->frameNr) {
91 // copy the values directly and integrate in place
92 if(verbose>10) printf("frame times are assumed to be the same\n");
93 int ret=0;
94 for(int ri=0; ri<output->voiNr && ret==0; ri++) {
95 for(int fi=0; fi<output->frameNr; fi++)
96 output->voi[ri].y[fi]=input->voi[ri].y[fi];
97 ret=petintegral(output->x1, output->x2, output->voi[ri].y,
98 output->frameNr, output->voi[ri].y2, output->voi[ri].y3);
99 }
100 if(ret) {
101 if(status!=NULL) sprintf(status, "cannot interpolate (%d)", ret);
102 dftEmpty(output); return 15;
103 }
104 return 0; // that's it then
105 }
106 if(verbose>10) printf("frame times are not the same\n");
107
108 // Check that there is no need for extrapolation in the start
109 if(dftInterpolateCheckStart(input, output, status, verbose)<0) {
110 dftEmpty(output); return 16;
111 }
112 // Check that there is no need for excess extrapolation in the end either
113 if(dftInterpolateCheckEnd(input, output, status, verbose)<0) {
114 dftEmpty(output); return 17;
115 }
116
117 // Interpolate and integrate input data to tissue sample times,
118 // taking into account tissue frame lengths
119 {
120 int ret=0;
121 for(int ri=0; ri<output->voiNr && ret==0; ri++) {
122 ret=interpolate4pet(input->x, input->voi[ri].y, input->frameNr,
123 output->x1, output->x2, output->voi[ri].y, output->voi[ri].y2,
124 output->voi[ri].y3, output->frameNr);
125 }
126 if(ret) {
127 if(status!=NULL) sprintf(status, "cannot interpolate (%d)", ret);
128 dftEmpty(output); return 18;
129 }
130 }
131
132 return 0;
133}
void dftEmpty(DFT *data)
Definition dft.c:20
int dftAllocateWithHeader(DFT *dft, int frameNr, int voiNr, DFT *dft_from)
Definition dft.c:702
int dftInterpolateCheckStart(DFT *input, DFT *output, char *status, int verbose)
Definition dftint.c:17
int dftInterpolateCheckEnd(DFT *input, DFT *output, char *status, int verbose)
Definition dftint.c:82
int copy_times_from_img_to_dft(IMG *img, DFT *dft, int verbose)
Definition fittime.c:246
int check_times_dft_vs_dft(DFT *dft1, DFT *dft2, int verbose)
Definition fittime.c:169
int petintegral(double *x1, double *x2, double *y, int nr, double *ie, double *iie)
Integrate PET TAC data to frame mid times.
Definition integr.c:771
int interpolate4pet(double *x, double *y, int nr, double *newx1, double *newx2, double *newy, double *newyi, double *newyii, int newnr)
Interpolate and integrate TAC to PET frames.
Definition integr.c:510
char * petTunit(int tunit)
Definition petunits.c:226
double * y2
double * y
double * y3

Referenced by imgReadModelingData().

◆ imgTimeIntegral()

int imgTimeIntegral ( IMG * img,
float t1,
float t2,
IMG * iimg,
int calc_mode,
char * status,
int verbose )

Integration of dynamic image from time1 to time2, storing integrals in iimg, which is allocated here. Frames do not have to be continuous in time. Time unit in integral is sec. Raw data (sinogram) must be divided by frame durations before calling this. You may want to test the time range before applying this routine, because this function accepts relatively large extrapolation.

See also
imgFrameIntegral, dftInterpolateForIMG, imgExistentTimes
Returns
Returns errstatus, which is STATUS_OK (0) when call was successful, and >0 in case of an error.
Parameters
imgIMG data; preferably dynamic, if static, then the specified time range must match with the frame time.
t1Time where to start integration (sec).
t2Time to stop integration (sec); must be higher than t1.
iimgPointer to initiated but empty AUC IMG data.
calc_modeCalculate integral or average: 0=integral, 1=average.
statusPointer to a string (allocated for at least 128 chars) where error message or other execution status will be written; enter NULL, if not needed.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 147 of file misc_model.c.

164 {
165 int ret;
166 double accept_tdif=1.0; // in seconds
167
168 if(verbose>0) {
169 printf("%s(img, %g, %g, iimg, %d, status, %d)\n", __func__, t1, t2, calc_mode, verbose);
170 fflush(stdout);
171 }
172
173 /* Check the arguments */
174 if(status!=NULL) sprintf(status, "program error");
175 if(img==NULL || iimg==NULL || t1<0.0 || t2<0.0) return STATUS_FAULT;
176 if(img->status!=IMG_STATUS_OCCUPIED) return STATUS_FAULT;
177 float fdur=t2-t1; if(fdur<=0.0) return STATUS_FAULT;
178 if(img->dimt<1) return STATUS_FAULT;
179
180 /* Check that time range matches with image frame */
181 if(img->dimt==1) { // static image (one frame only)
182 /* check that specified times match with image frame times, but accept 1 s differences */
183 if(fabs(img->end[0]-t2)>accept_tdif || fabs(img->start[0]-t1)>accept_tdif) {
184 if(status!=NULL) sprintf(status,
185 "for static image the integration time range must be exactly as long as the scan");
186 return STATUS_FAULT;
187 }
188 /* Set the times, in case there was a small difference */
189 img->end[0]=t2; img->start[0]=t1; img->mid[0]=0.5*(t1+t2);
190 } else { // Dynamic image (more than one frame)
191 /* First PET frame must start before 1/3 of the integration time */
192 /* Last PET frame must end after 2/3 of integration time */
193 if(img->start[0]>(0.66*t1+0.34*t2) || img->end[img->dimt-1]<(0.34*t1+0.66*t2)) {
194 if(status!=NULL) sprintf(status, "integration time range oversteps data range");
195 return STATUS_FAULT;
196 }
197 }
198 if(verbose>10) printf("t1=%g t2=%g fdur=%g\n", t1, t2, fdur);
199
200 /* Get the first and last frame index that resides inside integration time */
201 int f1, f2;
202 if(img->dimt==1) {
203 f1=f2=0;
204 } else {
205 f1=f2=-1;
206 for(int fi=0; fi<img->dimt; fi++) {
207 if(f1<0) {if(img->start[fi]>=t1 && img->end[fi]<=t2) f1=f2=fi;}
208 if(f1>=0) {if(t2>=img->end[fi]) f2=fi;}
209 }
210 }
211 if(verbose>10) printf("f1=%d f2=%d\n", f1, f2);
212
213 float aucroi, t[2], auc[2];
214 if(f1>=0 && f2>=0) {
215
216 /* Integrate over the frames that are included in time range as a whole */
217 ret=imgFrameIntegral(img, f1, f2, iimg, verbose-1);
218 if(ret) {
219 if(status!=NULL) sprintf(status, "cannot integrate (%d)", ret);
220 return STATUS_FAULT;
221 }
222
223 /* If necessary, add the partial integrals */
224 if(img->start[f1]>t1) {
225 t[0]=t1; t[1]=img->start[f1];
226 if(verbose>20) printf("t[0]=%g t[1]=%g\n", t[0], t[1]);
227 for(int zi=0; zi<img->dimz; zi++)
228 for(int yi=0; yi<img->dimy; yi++)
229 for(int xi=0; xi<img->dimx; xi++) {
230 ret=finterpolate(img->mid, img->m[zi][yi][xi], img->dimt, t, NULL, auc, NULL, 2);
231 if(ret) aucroi=0.0; else aucroi=auc[1]-auc[0];
232 iimg->m[zi][yi][xi][0]+=aucroi;
233 }
234 }
235 if(t2>img->end[f2]) {
236 t[0]=img->end[f2]; t[1]=t2;
237 if(verbose>20) printf("t[0]=%g t[1]=%g\n", t[0], t[1]);
238 for(int zi=0; zi<img->dimz; zi++)
239 for(int yi=0; yi<img->dimy; yi++)
240 for(int xi=0; xi<img->dimx; xi++) {
241 ret=finterpolate(img->mid, img->m[zi][yi][xi], img->dimt, t, NULL, auc, NULL, 2);
242 if(ret) aucroi=0.0; else aucroi=auc[1]-auc[0];
243 iimg->m[zi][yi][xi][0]+=aucroi;
244 }
245 }
246
247 } else { // no full frames inside integration range
248
249 /* Create the AUC image */
250 ret=imgAllocateWithHeader(iimg, img->dimz, img->dimy, img->dimx, 1, img);
251 if(ret!=0) {
252 if(status!=NULL) sprintf(status, "cannot setup integral image");
253 return STATUS_FAULT;
254 }
255
256 t[0]=t1; t[1]=t2;
257 for(int zi=0; zi<img->dimz; zi++)
258 for(int yi=0; yi<img->dimy; yi++)
259 for(int xi=0; xi<img->dimx; xi++) {
260 ret=finterpolate(img->mid, img->m[zi][yi][xi], img->dimt, t, NULL, auc, NULL, 2);
261 if(ret) aucroi=0.0; else aucroi=auc[1]-auc[0];
262 iimg->m[zi][yi][xi][0]+=aucroi;
263 }
264
265 }
266
267 /* Set output image time frame */
268 iimg->end[0]=t2; iimg->start[0]=t1; iimg->mid[0]=0.5*(t1+t2);
269
270 /* If required, then calculate average by dividing integral with time. */
271 /* Set units accordingly */
272 if(calc_mode!=0) { // average
273 ret=imgArithmConst(iimg, fdur, ':', 1.0E+10, verbose-1);
274 if(ret!=0) {
275 if(status!=NULL) sprintf(status, "cannot divide integral image");
276 return STATUS_FAULT;
277 }
278 iimg->unit=img->unit;
279 if(status!=NULL) sprintf(status, "average image [%g,%g] calculated",t1,t2);
280 } else { // integral
281 if(img->unit==CUNIT_KBQ_PER_ML) iimg->unit=CUNIT_SEC_KBQ_PER_ML;
282 else iimg->unit=CUNIT_UNKNOWN;
283 if(status!=NULL) sprintf(status, "integral image [%g,%g] calculated",t1,t2);
284 }
285
286 imgSetStatus(iimg, STATUS_OK);
287 return(0);
288}
int imgAllocateWithHeader(IMG *image, int planes, int rows, int columns, int frames, IMG *image_from)
Definition img.c:279
void imgSetStatus(IMG *img, int status_index)
Definition img.c:345
int imgFrameIntegral(IMG *img, int first, int last, IMG *iimg, int verbose)
Definition imgarithm.c:346
int imgArithmConst(IMG *img, float operand, char operation, float ulimit, int verbose)
Definition imgarithm.c:100
int finterpolate(float *x, float *y, int nr, float *newx, float *newy, float *newyi, float *newyii, int newnr)
float version of interpolate().
Definition integr.c:161
float **** m

◆ sif2dft()

int sif2dft ( SIF * sif,
DFT * dft )

Convert SIF data to DFT data.

See also
sifAllocateWithIMG, dftAllocateWithIMG
Returns
Returns 0 if successful, otherwise >0.
Parameters
sifPointer to SIF struct containing data to be converted.
dftPointer to initiated but empty DFT struct.

Definition at line 350 of file misc_model.c.

355 {
356 int fi, ri, tacNr, ret;
357
358 /* Check input */
359 if(dft==NULL || sif==NULL) return 1;
360 if(sif->frameNr<1) return 2;
361 tacNr=sif->colNr-2; if(tacNr<=0) tacNr=1;
362
363 /* Allocate memory */
364 ret=dftSetmem(dft, sif->frameNr, tacNr);
365 if(ret) return(100+ret);
366 dft->voiNr=tacNr;
367 dft->frameNr=sif->frameNr;
368
369 // Set header contents
372 for(fi=0; fi<dft->frameNr; fi++) {
373 dft->x[fi]=0.5*(sif->x1[fi]+sif->x2[fi]);
374 dft->x1[fi]=sif->x1[fi];
375 dft->x2[fi]=sif->x2[fi];
376 }
377 dft->timeunit=TUNIT_SEC;
378 dft->isweight=0;
379 strcpy(dft->unit, imgUnit(CUNIT_COUNTS));
380 for(ri=0; ri<dft->voiNr; ri++) {
381 /* Set ROI name */
382 if(ri==0) sprintf(dft->voi[ri].voiname, "Prompt");
383 else if(ri==1) sprintf(dft->voi[ri].voiname, "Random");
384 else if(ri==2) sprintf(dft->voi[ri].voiname, "True");
385 else if(ri==3) sprintf(dft->voi[ri].voiname, "Weight");
386 else snprintf(dft->voi[ri].voiname, 7, "%06d", ri+1);
387 strcpy(dft->voi[ri].name, dft->voi[ri].voiname);
388 /* Copy TAC values */
389 if(ri==0 && ri<sif->colNr-2) {
390 for(fi=0; fi<dft->frameNr; fi++) dft->voi[ri].y[fi]=sif->prompts[fi];
391 } else if(ri==1 && ri<sif->colNr-2) {
392 for(fi=0; fi<dft->frameNr; fi++) dft->voi[ri].y[fi]=sif->randoms[fi];
393 } else if(ri==2 && ri<sif->colNr-2) {
394 for(fi=0; fi<dft->frameNr; fi++) dft->voi[ri].y[fi]=sif->trues[fi];
395 } else if(ri==3 && ri<sif->colNr-2) {
396 for(fi=0; fi<dft->frameNr; fi++) dft->voi[ri].y[fi]=sif->weights[fi];
397 } else {
398 for(fi=0; fi<dft->frameNr; fi++) dft->voi[ri].y[fi]=0.0;
399 }
400 }
401 strcpy(dft->studynr, sif->studynr);
402 strcpy(dft->isotope, hlCorrectIsotopeCode(sif->isotope_name));
403
404 return 0;
405}
char * hlCorrectIsotopeCode(char *isocode)
Definition halflife.c:141
char isotope[8]
double * x1
double * prompts
int frameNr
double * x2
char studynr[MAX_STUDYNR_LEN+1]
char isotope_name[8]
double * weights
int colNr
double * randoms
double * trues

◆ sifAllocateWithIMG()

int sifAllocateWithIMG ( SIF * sif,
IMG * img,
int doCounts,
int verbose )

Allocate memory for SIF based on information in IMG.

Frame times are set, 'counts' are optionally set to mean of voxel values times frame lengths, scaled to 0-1E7. Weights are not calculated.

See also
sif2dft, dftAllocateWithIMG
Returns
Returns 0 if successful, otherwise <>0.
Parameters
sifPointer to initiated SIF struct which will be allocated here.
imgPointer to IMG struct from where necessary information is read.
doCountsSet (1) or do not set (0) counts, based on sum of all image voxel values and frame lengths.
verboseVerbose level; if zero, then only warnings are printed into stderr.

Definition at line 418 of file misc_model.c.

427 {
428 int fi, ret;
429 float *cs;
430 double f, mf;
431
432 if(verbose>0) {printf("%s(*sif, *img, %d, ...)\n", __func__, doCounts); fflush(stdout);}
433 /* Check the input data */
434 if(sif==NULL || img==NULL) return 1;
435 if(img->status!=IMG_STATUS_OCCUPIED) return 2;
436 if(img->dimt<1) return 3;
437 if(doCounts<0 || doCounts>1) return 4;
438
439 /* Delete any previous SIF contents */
440 sifEmpty(sif);
441
442 /* Allocate memory for SIF data */
443 ret=sifSetmem(sif, img->dimt); if(ret!=0) return(10+ret);
444
445 /* Set SIF information */
446 sif->version=1;
447 sif->colNr=4;
448 strcpy(sif->isotope_name, imgIsotope(img));
449 strcpy(sif->studynr, img->studyNr);
450 sif->scantime=img->scanStart;
451 for(fi=0; fi<img->dimt; fi++) {sif->x1[fi]=img->start[fi]; sif->x2[fi]=img->end[fi];}
452
453 if(doCounts==0) return 0; // that's it then
454
455 /* Calculate average curve of all pixels */
456 if(verbose>1) printf("calculate image average curve.\n");
457 cs=(float*)malloc(img->dimt*sizeof(float));
458 if(cs==NULL) {sifEmpty(sif); return(20);}
459 ret=imgAverageTAC(img, cs); if(ret!=0) {sifEmpty(sif); return(20+ret);}
460 /* Multiply average curve with frame durations, and get the max */
461 for(fi=0, mf=0.0; fi<sif->frameNr; fi++) {
462 f=sif->x2[fi]-sif->x1[fi]; if(f<=0.1) f=0.1;
463 cs[fi]*=f; if(cs[fi]>mf) mf=cs[fi];
464 }
465 /* Put scaled counts into SIF */
466 if(mf>0.0) f=1.0E+007/mf; else f=1.0;
467 for(fi=0, mf=0.0; fi<sif->frameNr; fi++) {
468 sif->prompts[fi]=sif->trues[fi]=cs[fi]*f;
469 sif->randoms[fi]=0.0;
470 }
471 free(cs);
472 if(verbose>2) sifPrint(sif);
473 return 0;
474}
char * imgIsotope(IMG *img)
Definition imgdecayc.c:76
int imgAverageTAC(IMG *img, float *tac)
Definition imgeval.c:15
void sifPrint(SIF *data)
Definition sifio.c:234
int sifSetmem(SIF *data, int frameNr)
Definition sif.c:56
void sifEmpty(SIF *data)
Definition sif.c:33
time_t scanStart
int version
time_t scantime

Referenced by imgSetWeights().