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

Time delay between PET tissue and blood curve. More...

#include "tpcclibConfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <string.h>
#include "tpcextensions.h"
#include "tpctac.h"
#include "tpcli.h"
#include "tpclinopt.h"
#include "tpctacmod.h"

Go to the source code of this file.

Functions

int tacDelay (TAC *tac, double dt, int ti, TPCSTATUS *status)
 Move TAC y values (concentrations) in time, keeping sample times (x values) intact.
void initDelayCMFitData (DELAYCMFITDATA *d)
 Before first use, initiate the data structure for delay time estimation.
void freeDelayCMFitData (DELAYCMFITDATA *d)
 After last use, free memory in the data structure for delay time estimation.
int tacDelayCMFit (TAC *btac, TAC *ttac, int ci, double dtmin, double dtmax, double fitend, double dtstep, double *dt, int mode, int model, DELAYCMFITDATA *tdata, TPCSTATUS *status)
 Fit time delay between PET tissue and plasma or blood curve.

Detailed Description

Time delay between PET tissue and blood curve.

Definition in file delay.c.

Function Documentation

◆ freeDelayCMFitData()

void freeDelayCMFitData ( DELAYCMFITDATA * d)

After last use, free memory in the data structure for delay time estimation.

See also
tacDelayCMFit, initDelayCMFitData
Parameters
dPointer to the data structure to be initialized.

Definition at line 150 of file delay.c.

153 {
154 if(d==NULL) return;
155 d->iNr=d->tNr=d->moveNr=0;
156 tacFree(&d->dtac); tacFree(&d->ditac); tacFree(&d->diitac); tacFree(&d->ddtac); tacFree(&d->dddtac);
157 d->mode=0; d->model=0;
158 d->llsq_n=d->llsq_m=0;
159 free(d->llsq_a); free(d->llsq_mat);
160 free(d->llsq_b); free(d->llsq_x); free(d->llsq_wp); free(d->llsq_zz);
161 free(d->llsq_i);
162 return;
163}
unsigned int iNr
Definition tpctacmod.h:33
unsigned int moveNr
Definition tpctacmod.h:53
double ** llsq_a
Definition tpctacmod.h:80
double * llsq_b
Definition tpctacmod.h:82
unsigned int tNr
Definition tpctacmod.h:35
double * llsq_mat
Definition tpctacmod.h:78
double * llsq_zz
Definition tpctacmod.h:88
double * llsq_x
Definition tpctacmod.h:84
double * llsq_wp
Definition tpctacmod.h:86
void tacFree(TAC *tac)
Definition tac.c:106

Referenced by tacDelayCMFit().

◆ initDelayCMFitData()

void initDelayCMFitData ( DELAYCMFITDATA * d)

Before first use, initiate the data structure for delay time estimation.

See also
tacDelayCMFit, freeDelayCMFitData
Parameters
dPointer to the data structure to be initialized.

Definition at line 131 of file delay.c.

134 {
135 if(d==NULL) return;
136 d->iNr=d->tNr=d->moveNr=0;
137 tacInit(&d->dtac); tacInit(&d->ditac); tacInit(&d->diitac); tacInit(&d->ddtac); tacInit(&d->dddtac);
138 d->mode=0; d->model=0;
139 d->llsq_n=d->llsq_m=0;
140 d->llsq_mat=NULL;
141 d->llsq_a=NULL;
142 d->llsq_b=d->llsq_x=d->llsq_wp=d->llsq_zz=NULL;
143 d->llsq_i=NULL;
144 return;
145}
void tacInit(TAC *tac)
Definition tac.c:24

Referenced by tacDelayCMFit().

◆ tacDelay()

int tacDelay ( TAC * tac,
double dt,
int ti,
TPCSTATUS * status )

Move TAC y values (concentrations) in time, keeping sample times (x values) intact.

If TAC has frame start and end times, this function tries to retain the AUC with stepwise frame interpretation. If you wish to prevent this, then set tac->isframe=0 before calling this function and after it set back tac->isframe=1.

See also
tacDelayCMFit, tacInterpolate, tacFramesToSteps, simDispersion, liInterpolate, tacVb
Returns
enum tpcerror (TPCERROR_OK when successful).
Parameters
tacPointer to TAC structure.
Precondition
Data must be sorted by increasing x. No gaps or overlap between frames allowed.
See also
tacSortByTime, tacSetXContiguous
Postcondition
Data y values are modified, x values will stay the same.
Parameters
dtTime (in TAC tunit's) to move the TAC forward (negative time moves TAC backward).
tiIndex [0..tacNr-1] of the TAC to move, or <0 to move all TACs.
statusPointer to status data; enter NULL if not needed.

Definition at line 29 of file delay.c.

41 {
42 int verbose=0; if(status!=NULL) verbose=status->verbose;
43 if(verbose>0) printf("%s(tac, %g, %d)\n", __func__, dt, ti);
44 /* Check the function input */
45 if(tac==NULL || tac->sampleNr<1 || tac->tacNr<1) {
46 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_DATA);
47 return TPCERROR_NO_DATA;
48 }
49 if(ti>=tac->tacNr) {
50 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_FAIL);
51 return TPCERROR_FAIL;
52 }
53 if(fabs(dt)<1.0E-12) {
54 if(verbose>1) printf(" requested delay time is zero; nothing done.\n");
55 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
56 return(TPCERROR_OK);
57 }
58 /* Check that input does not have any missing values */
59 if(tacXNaNs(tac)>0 || tacYNaNs(tac, ti)>0) {
60 if(verbose>1) printf(" data contains NaN(s).\n");
61 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_MISSING_DATA);
63 }
64
65 /* Get and check the x range */
66 double xmin=nan(""), xmax=nan("");
67 if(tacXRange(tac, &xmin, &xmax)!=0 || dt>=xmax || dt<=-xmax) {
68 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_XRANGE);
70 }
71 if(verbose>2) printf(" xrange: %g - %g\n", xmin, xmax);
72
73
74 /* If TAC contains just frame mid times, then simple dot-to-dot interpolation */
75 if(tac->isframe==0) {
76 /* Make temporary x array */
77 double tx[tac->sampleNr];
78 for(int i=0; i<tac->sampleNr; i++) tx[i]=tac->x[i]+dt;
79 /* One TAC at a time */
80 for(int j=0; j<tac->tacNr; j++) if(ti<0 || ti==j) {
81 /* Make temporary y array */
82 double ty[tac->sampleNr];
83 for(int i=0; i<tac->sampleNr; i++) ty[i]=tac->c[j].y[i];
84 /* Interpolate temporary data to original times */
85 if(liInterpolate(tx, ty, tac->sampleNr, tac->x, tac->c[j].y, NULL, NULL, tac->sampleNr, 0, 1,
86 verbose-10)!=0)
87 {
88 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_VALUE);
90 }
91 }
92 /* That's it then */
93 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
94 return(TPCERROR_OK);
95 }
96
97 /* We have frame start and end times */
98 /* Convert the data into stepwise dot-to-dot data */
99 TAC stac; tacInit(&stac);
100 {
101 int ret=tacFramesToSteps(tac, &stac, NULL);
102 if(ret!=TPCERROR_OK) {
103 tacFree(&stac);
104 statusSet(status, __func__, __FILE__, __LINE__, ret);
105 return(ret);
106 }
107 }
108 /* Change times of the stepwise data */
109 for(int i=0; i<stac.sampleNr; i++) stac.x[i]+=dt;
110 /* Interpolate stepwise data into original frame times, one TAC at a time */
111 for(int j=0; j<tac->tacNr; j++) if(ti<0 || ti==j) {
112 if(liInterpolateForPET(stac.x, stac.c[j].y, stac.sampleNr, tac->x1, tac->x2, tac->c[j].y,
113 NULL, NULL, tac->sampleNr, 0, 1, verbose-10))
114 {
115 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_VALUE);
117 }
118 }
119 tacFree(&stac);
120
121
122 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
123 return(TPCERROR_OK);
124}
int liInterpolate(double *x, double *y, const int nr, double *newx, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
Linear interpolation and/or integration with trapezoidal method.
int liInterpolateForPET(double *x, double *y, const int nr, double *newx1, double *newx2, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
Linear TAC interpolation and/or integration to PET frames.
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
Definition statusmsg.c:142
double * y
Definition tpctac.h:75
Definition tpctac.h:87
double * x
Definition tpctac.h:97
int sampleNr
Definition tpctac.h:89
int isframe
Definition tpctac.h:95
TACC * c
Definition tpctac.h:117
double * x2
Definition tpctac.h:101
double * x1
Definition tpctac.h:99
int tacNr
Definition tpctac.h:91
int verbose
Verbose level, used by statusPrint() etc.
int tacYNaNs(TAC *tac, const int i)
Definition tacnan.c:47
int tacXNaNs(TAC *tac)
Definition tacnan.c:23
int tacFramesToSteps(TAC *inp, TAC *out, TPCSTATUS *status)
Transform TAC with frames into TAC with frames represented with stepwise changing dot-to-dot data.
Definition tacx.c:942
int tacXRange(TAC *d, double *xmin, double *xmax)
Get the range of x values (times) in TAC structure.
Definition tacx.c:124
@ TPCERROR_INVALID_XRANGE
Invalid sample time range.
@ TPCERROR_INVALID_VALUE
Invalid value.
@ TPCERROR_FAIL
General error.
@ TPCERROR_OK
No error.
@ TPCERROR_NO_DATA
File contains no data.
@ TPCERROR_MISSING_DATA
File contains missing values.

◆ tacDelayCMFit()

int tacDelayCMFit ( TAC * btac,
TAC * ttac,
int ci,
double dtmin,
double dtmax,
double fitend,
double dtstep,
double * dt,
int mode,
int model,
DELAYCMFITDATA * tdata,
TPCSTATUS * status )

Fit time delay between PET tissue and plasma or blood curve.

Initial part of tissue curve is fitted with a range of input curves moved in time, using linearised one or two-tissue compartment model with blood volume term. The time that provides the best fit is selected. It is assumed that tissue heterogeneity, dispersion of the blood curve, metabolites, and variable plasma-to-blood ratio will only minimally impact the time delay estimate, since only the initial part of the data is fitted, especially if reversible two-tissue model (R2tCM) is used.

See also
tacDelay, simDispersion
Returns
enum tpcerror (TPCERROR_OK when successful).
Author
Vesa Oikonen
Parameters
btacPointer to input data (blood or plasma curve). Units of input and tissue TAC must match. All but first curve in TAC are ignored. Enter NULL in subsequent runs
ttacPointer to tissue data. Units of input and tissue TAC must match. All but first curve in TAC are ignored.
ciIndex [0..ttac->tacNr-1] of tissue tac to use.
dtminMinimum delay to be tested, for example -10 s, in the same units as in TACs. Not used in subsequent runs with tdata.
dtmaxMaximum delay to be tested, for example +50 s, in the same units as in TACs. Not used in subsequent runs with tdata.
fitendFitting uses data from 0 to end time, for example 120 s, in the same units as in TACs. In case of short PET scan, end time may need to be reduced so that input TAC with negative delay extends to the fit end. Not used in subsequent runs with tdata.
dtstepThe step length for moving the input curve, for example 1 s, in the same units as in TACs. Not used in subsequent runs with tdata.
dtPointer for the time delay estimate. Positive delay time means that tissue curve is delayed as compared to the input curve, and vice versa. Thus, input curve needs to be moved by the delay time to match the tissue curve.
modeMode for multilinear equations: 0=integrals and 2nd integrals, 1=derivates and 2nd derivates (experimental), 2=integrals and derivates (experimental).
modelModel: 0=R1TCM, 1=I2TCM, 2=R2TCM.
tdataPointer to temporary data structure, which quickens subsequent runs with other tissue TACs; enter NULL if not needed.
See also
initDelayCMFitData, freeDelayCMFitData
Parameters
statusPointer to status data; enter NULL if not needed.

Definition at line 179 of file delay.c.

219 {
220 int verbose=0; if(status!=NULL) verbose=status->verbose;
221 if(verbose>2) {
222 printf("%s(inp, tis, %d, %g, %g, %g, %g, %d, ...)\n", __func__, ci, dtmin, dtmax, fitend, dtstep, mode);
223 fflush(stdout);
224 }
225
226
227 /* Check provided data */
228 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_FAIL);
229 if(ttac==NULL || (btac==NULL && tdata==NULL)) return(TPCERROR_FAIL);
230 if(btac!=NULL && (btac->tacNr<1 || btac->sampleNr<4)) return(TPCERROR_FAIL);
231 if(ci<0 || ci>=ttac->tacNr || ttac->sampleNr<4) return(TPCERROR_FAIL);
232 if(model<0 || model>2) return(TPCERROR_FAIL);
233 if(dt!=NULL) *dt=nan("");
234
235 /* Initiate (possibly reused) data structure */
236 DELAYCMFITDATA *b, ltdata; initDelayCMFitData(&ltdata);
237 if(tdata!=NULL) {
238 b=tdata;
239 if(verbose>3) {
240 if(b->moveNr==0) printf(" given temp data will be filled\n");
241 else printf(" filled temp data will be used\n");
242 fflush(stdout);
243 }
244 } else {
245 b=&ltdata;
246 if(verbose>4) {printf(" local temp data created\n"); fflush(stdout);}
247 }
248
249 /* Check and set temp data when run first time with the given TTAC */
250 if(btac!=NULL || b->moveNr==0) {
251 /* Delay range and steps*/
252 if(!(dtmax>dtmin) || !(dtstep>0.001)) {
253 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_XRANGE);
255 }
256 b->dtmin=dtmin; b->dtmax=dtmax; b->dtstep=dtstep;
257 /* How many delayed curves needed */
258 b->moveNr=1+(b->dtmax-b->dtmin)/b->dtstep;
259 if(verbose>3) printf(" moveNr := %d\n", b->moveNr);
260 if(b->moveNr<5 || b->moveNr>5000) {
261 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_XRANGE);
263 }
264 /* Get x range */
265 if(tacXRange(ttac, &b->ttac_xmin, &b->ttac_xmax)!=0 || tacXRange(btac, &b->btac_xmin, &b->btac_xmax)!=0) {
266 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_XRANGE);
268 }
269 if(verbose>3) printf(" TTAC range := %g - %g\n BTAC range := %g - %g\n",
270 b->ttac_xmin, b->btac_xmax, b->ttac_xmin, b->btac_xmax);
271 /* Check that time units do match */
272 if(btac->tunit!=ttac->tunit) {
273 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_X);
274 return(TPCERROR_INVALID_X);
275 }
276 /* Check that input curve is long enough to fit duration */
277 if(!(fitend>0.0)) {
278 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_XRANGE);
280 }
281 b->fitend=fitend;
282 if(b->fitend>b->ttac_xmax) b->fitend=b->ttac_xmax;
283 if(b->fitend>b->btac_xmax) b->fitend=b->btac_xmax;
284 if(b->dtmin<0.0 && b->btac_xmax<(b->fitend+b->dtmin))
285 b->fitend+=b->dtmin;
286 if(verbose>3) printf("fitend=%g -> %g\n", fitend, b->fitend);
287 b->iNr=0; for(unsigned int i=0; i<(unsigned int)btac->sampleNr; i++) if(btac->x[i]<=b->fitend) b->iNr++; else break;
288 b->tNr=0; for(unsigned int i=0; i<(unsigned int)ttac->sampleNr; i++) if(ttac->x[i]<=b->fitend) b->tNr++; else break;
289 //printf("iNr=%u tNr=%u\n", b->iNr, b->tNr);
290 if(b->iNr<5 || b->tNr<5) {
291 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_XRANGE);
293 }
294
295 /* Further, when run the first time, make input TACs moved in time, interpolated and integrated
296 to tissue times */
297 if(verbose>5) {printf(" preparing delayed input data\n"); fflush(stdout);}
298 b->mode=mode;
299 b->model=model;
300 int ret;
301 ret=tacAllocate(&b->dtac, b->tNr, b->moveNr+1); // additional place for tissue curve
302 if(ret!=TPCERROR_OK) {
303 freeDelayCMFitData(&ltdata);
304 statusSet(status, __func__, __FILE__, __LINE__, ret);
306 }
307 b->dtac.sampleNr=b->tNr;
308 b->dtac.tacNr=b->moveNr+1; // tissue as the last curve
309 b->dtac.isframe=ttac->isframe;
310 for(int i=0; i<b->dtac.sampleNr; i++) {
311 b->dtac.x1[i]=ttac->x1[i]; b->dtac.x[i]=ttac->x[i]; b->dtac.x2[i]=ttac->x2[i];}
312 ret=tacDuplicate(&b->dtac, &b->ditac);
313 if(ret==TPCERROR_OK) ret=tacDuplicate(&b->dtac, &b->diitac);
314 if(ret==TPCERROR_OK) ret=tacDuplicate(&b->dtac, &b->ddtac);
315 if(ret==TPCERROR_OK) ret=tacDuplicate(&b->dtac, &b->dddtac);
316 if(ret!=TPCERROR_OK) {
317 freeDelayCMFitData(&ltdata);
318 statusSet(status, __func__, __FILE__, __LINE__, ret);
319 return(ret);
320 }
321 /* Integrate/derivate input data, change times, and interpolate to tissue data */
322 double bd[btac->sampleNr], bdd[btac->sampleNr];
323 double bi[btac->sampleNr], bii[btac->sampleNr];
324 if(liDerivate3(btac->x, btac->c[0].y, btac->sampleNr, bd, bdd, 0)) {
325 freeDelayCMFitData(&ltdata);
326 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_VALUE);
328 }
329 if(btac->isframe==0) {
330 if(liIntegrate(btac->x, btac->c[0].y, btac->sampleNr, bi, 3, 0) ||
331 liIntegrate(btac->x, bi, btac->sampleNr, bii, 3, 0))
333 } else {
334 if(liIntegrateFE(btac->x1, btac->x2, btac->c[0].y, btac->sampleNr, bi, bii, 0))
336 }
337 if(ret) {
338 freeDelayCMFitData(&ltdata);
339 statusSet(status, __func__, __FILE__, __LINE__, ret);
340 return(ret);
341 }
342 double dx[btac->sampleNr], dx2[btac->sampleNr], *dxp;
343 if(btac->isframe==0) dxp=dx; else dxp=dx2;
344 for(int di=0; di<b->dtac.tacNr-1; di++) {
345 for(int i=0; i<btac->sampleNr; i++) {
346 dx[i]=btac->x[i]+b->dtmin+di*b->dtstep;
347 dx2[i]=btac->x2[i]+b->dtmin+di*b->dtstep;
348 }
349 if(b->dtac.isframe==0) {
350 ret=liInterpolate(dx, btac->c[0].y, btac->sampleNr, b->dtac.x, b->dtac.c[di].y,
351 NULL, NULL, b->dtac.sampleNr, 3, 1, 0);
352
353 if(!ret) ret=liInterpolate(dxp, bi, btac->sampleNr, b->dtac.x, b->ditac.c[di].y,
354 NULL, NULL, b->dtac.sampleNr, 3, 1, 0);
355 if(!ret) ret=liInterpolate(dxp, bii, btac->sampleNr, b->dtac.x, b->diitac.c[di].y,
356 NULL, NULL, b->dtac.sampleNr, 3, 1, 0);
357 if(!ret) ret=liInterpolate(dx, bd, btac->sampleNr, b->dtac.x, b->ddtac.c[di].y,
358 NULL, NULL, b->dtac.sampleNr, 3, 1, 0);
359 if(!ret) ret=liInterpolate(dx, bdd, btac->sampleNr, b->dtac.x, b->dddtac.c[di].y,
360 NULL, NULL, b->dtac.sampleNr, 3, 1, 0);
361 } else {
362 ret=liInterpolateForPET(dx, btac->c[0].y, btac->sampleNr, b->dtac.x1, b->dtac.x2,
363 b->dtac.c[di].y, NULL, NULL, b->dtac.sampleNr, 3, 1, 0);
364 if(!ret) ret=liInterpolateForPET(dxp, bi, btac->sampleNr, b->dtac.x1, b->dtac.x2,
365 b->ditac.c[di].y, NULL, NULL, b->dtac.sampleNr, 3, 1, 0);
366 if(!ret) ret=liInterpolateForPET(dxp, bii, btac->sampleNr, b->dtac.x1, b->dtac.x2,
367 b->diitac.c[di].y, NULL, NULL, b->dtac.sampleNr, 3, 1, 0);
368 if(!ret) ret=liInterpolateForPET(dx, bd, btac->sampleNr, b->dtac.x1, b->dtac.x2,
369 b->ddtac.c[di].y, NULL, NULL, b->dtac.sampleNr, 3, 1, 0);
370 if(!ret) ret=liInterpolateForPET(dx, bdd, btac->sampleNr, b->dtac.x1, b->dtac.x2,
371 b->dddtac.c[di].y, NULL, NULL, b->dtac.sampleNr, 3, 1, 0);
372 }
373 if(ret) {
374 freeDelayCMFitData(&ltdata);
375 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_XRANGE);
377 }
378 }
379 if(verbose>6) {
380 printf("integrated input curve 1:\n");
381 for(int i=0; i<b->dtac.sampleNr; i++)
382 printf("%g %g %g %g\n", b->dtac.x[i], b->dtac.c[0].y[i], b->ditac.c[0].y[i], b->diitac.c[0].y[i]);
383 fflush(stdout);
384 }
385
386
387 /* Allocate memory for linear LSQ */
388 if(verbose>5) {printf(" preparing data for LLSQ\n"); fflush(stdout);}
389 b->llsq_n=3+b->model;
390 b->llsq_m=b->dtac.sampleNr;
391 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OUT_OF_MEMORY);
392 b->llsq_mat=(double*)malloc((b->llsq_n*b->llsq_m)*sizeof(double));
393 if(b->llsq_mat==NULL) {freeDelayCMFitData(&ltdata); return(TPCERROR_OUT_OF_MEMORY);}
394 b->llsq_a=(double**)malloc(b->llsq_n*sizeof(double*));
395 if(b->llsq_a==NULL) {freeDelayCMFitData(&ltdata); return(TPCERROR_OUT_OF_MEMORY);}
396 for(int ni=0; ni<b->llsq_n; ni++) b->llsq_a[ni]=b->llsq_mat+ni*b->llsq_m;
397 b->llsq_b=(double*)malloc(b->llsq_m*sizeof(double));
398 b->llsq_x=(double*)malloc(b->llsq_n*sizeof(double));
399 b->llsq_wp=(double*)malloc(b->llsq_n*sizeof(double));
400 b->llsq_zz=(double*)malloc(b->llsq_m*sizeof(double));
401 b->llsq_i=(int*)malloc(b->llsq_n*sizeof(int));
402 if(b->llsq_b==NULL || b->llsq_x==NULL || b->llsq_wp==NULL || b->llsq_zz==NULL || b->llsq_i==NULL) {
403 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OUT_OF_MEMORY);
405 }
406
407 /* Integrate tissue curve */
408 {
409 if(verbose>5) {printf(" preparing tissue data\n"); fflush(stdout);}
410 int ti=b->dtac.tacNr-1; // index of tissue curve after the input curves
411 for(int i=0; i<b->dtac.sampleNr; i++) b->dtac.c[ti].y[i]=ttac->c[ci].y[i];
412
413 int ret=liDerivate(b->dtac.x, b->dtac.c[ti].y, b->dtac.sampleNr, b->ddtac.c[ti].y, b->dddtac.c[ti].y, 0);
414 if(b->dtac.isframe==0) {
415 if(!ret) ret=liIntegrate(b->dtac.x, b->dtac.c[ti].y, b->dtac.sampleNr, b->ditac.c[ti].y, 3, 0);
416 if(!ret) ret=liIntegrate(b->dtac.x, b->ditac.c[ti].y, b->dtac.sampleNr, b->diitac.c[ti].y, 3, 0);
417 } else {
418 if(!ret) ret=liIntegrateFE(b->dtac.x1, b->dtac.x2, b->dtac.c[ti].y, b->dtac.sampleNr,
419 b->ditac.c[ti].y, b->diitac.c[ti].y, 0);
420 }
421 if(ret) {
422 freeDelayCMFitData(&ltdata);
423 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_XRANGE);
425 }
426
427 if(verbose>10) {
428 printf("integrated tissue curves:\n");
429 for(int i=0; i<b->dtac.sampleNr; i++)
430 printf("%g %g %g %g\n", b->dtac.x[i], b->dtac.c[ti].y[i], b->ditac.c[ti].y[i], b->diitac.c[ti].y[i]);
431 fflush(stdout);
432 }
433 }
434
435
436 /* Multilinear fitting with each delayed input */
437 if(verbose>5) {printf(" LLSQ\n"); fflush(stdout);}
438 double ss, ssmin=nan("");
439 int mini=-1;
440 for(int di=0; di<b->dtac.tacNr-1; di++) {
441 /* Setup data matrix A and vector B */
442 for(int mi=0; mi<b->llsq_m; mi++) {
443 b->llsq_b[mi]=b->dtac.c[b->dtac.tacNr-1].y[mi]; // TTAC
444 b->llsq_mat[mi]=b->dtac.c[di].y[mi]; // BTAC
445 if(mode==1) {
446 b->llsq_mat[mi+1*b->llsq_m]=b->ddtac.c[di].y[mi]; // BTAC derivate
447 b->llsq_mat[mi+2*b->llsq_m]=-b->ddtac.c[b->dtac.tacNr-1].y[mi]; // TTAC derivate
448 if(b->llsq_n>3) b->llsq_mat[mi+3*b->llsq_m]=b->dddtac.c[di].y[mi]; // BTAC derivate
449 if(b->llsq_n>4) b->llsq_mat[mi+4*b->llsq_m]=-b->dddtac.c[b->dtac.tacNr-1].y[mi]; // TTAC derivate
450 } else if(mode==2) {
451 b->llsq_mat[mi+1*b->llsq_m]=b->ditac.c[di].y[mi]; // BTAC integral
452 b->llsq_mat[mi+2*b->llsq_m]=-b->ditac.c[b->dtac.tacNr-1].y[mi]; // TTAC integral
453 if(b->llsq_n>3) b->llsq_mat[mi+3*b->llsq_m]=b->ddtac.c[di].y[mi]; // BTAC derivate
454 if(b->llsq_n>4) b->llsq_mat[mi+4*b->llsq_m]=-b->ddtac.c[b->dtac.tacNr-1].y[mi]; // TTAC derivate
455 } else { // mode 0
456 b->llsq_mat[mi+1*b->llsq_m]=b->ditac.c[di].y[mi]; // BTAC integral
457 b->llsq_mat[mi+2*b->llsq_m]=-b->ditac.c[b->dtac.tacNr-1].y[mi]; // TTAC integral
458 if(b->llsq_n>3) b->llsq_mat[mi+3*b->llsq_m]=b->diitac.c[di].y[mi]; // BTAC 2nd integral
459 if(b->llsq_n>4) b->llsq_mat[mi+4*b->llsq_m]=-b->diitac.c[b->dtac.tacNr-1].y[mi]; // TTAC 2nd integral
460 }
461 b->llsq_mat[mi]=b->dtac.c[di].y[mi]; // BTAC
462 b->llsq_mat[mi+1*b->llsq_m]=b->ditac.c[di].y[mi]; // BTAC integral
463 b->llsq_mat[mi+2*b->llsq_m]=-b->ditac.c[b->dtac.tacNr-1].y[mi]; // TTAC integral
464 if(b->llsq_n>3) b->llsq_mat[mi+3*b->llsq_m]=b->diitac.c[di].y[mi]; // BTAC 2nd integral
465 if(b->llsq_n>4) b->llsq_mat[mi+4*b->llsq_m]=-b->diitac.c[b->dtac.tacNr-1].y[mi]; // TTAC 2nd integral
466 }
467 if(verbose>3) {
468 int failnr=0;
469 for(int mi=0; mi<b->llsq_m; mi++) {
470 if(!isfinite(b->llsq_b[mi])) failnr++;
471 if(!isfinite(b->llsq_mat[mi])) failnr++;
472 if(!isfinite(b->llsq_mat[mi+1*b->llsq_m])) failnr++;
473 if(!isfinite(b->llsq_mat[mi+2*b->llsq_m])) failnr++;
474 if(!isfinite(b->llsq_mat[mi+3*b->llsq_m])) failnr++;
475 if(!isfinite(b->llsq_mat[mi+4*b->llsq_m])) failnr++;
476 }
477 if(failnr>0) printf("%d bad values\n", failnr);
478 }
479 if(verbose>9 && b->llsq_m<100) {
480 printf("---- B x A ----\n");
481 for(int mi=0; mi<b->llsq_m; mi++) {
482 printf(" %g ", b->llsq_b[mi]);
483 for(int ni=0; ni<b->llsq_n; ni++)
484 printf(" %g", b->llsq_mat[mi+ni*b->llsq_m]);
485 printf("\n");
486 }
487 }
488
489 int ret=nnls(b->llsq_a, b->llsq_m, b->llsq_n, b->llsq_b, b->llsq_x, &ss, b->llsq_wp, b->llsq_zz, b->llsq_i);
490 if(ret<2 && isfinite(ss)) {
491 if(!isfinite(ssmin) || ssmin>ss) {ssmin=ss; mini=di;}
492 if(verbose>2) printf(" %d %d %g %g\n", di, mini, ss, ssmin);
493 } else {
494 if(verbose>1) printf(" failed NNLS\n");
495 }
496 }
497 if(mini<0) {
498 if(verbose>1) fprintf(stderr, "Error: all fits failed.\n");
499 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_BAD_FIT);
500 freeDelayCMFitData(&ltdata); return(TPCERROR_BAD_FIT);
501 }
502 if(dt!=NULL && mini>=0) *dt=b->dtmin+mini*b->dtstep;
503
504 freeDelayCMFitData(&ltdata); // the local one, not the one possibly given by caller
505 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
506 return(TPCERROR_OK);
507}
void freeDelayCMFitData(DELAYCMFITDATA *d)
After last use, free memory in the data structure for delay time estimation.
Definition delay.c:150
void initDelayCMFitData(DELAYCMFITDATA *d)
Before first use, initiate the data structure for delay time estimation.
Definition delay.c:131
int liDerivate3(double *x, double *y, const int nr, double *d, double *dd, const int verbose)
Simplistic derivation of PET TAC using regression line over three points.
Definition integrate.c:493
int liIntegrateFE(double *x1, double *x2, double *y, int nr, double *ie, double *iie, const int verbose)
Linear integration of PET TAC to frame end times.
Definition integrate.c:219
int liIntegrate(double *x, double *y, const int nr, double *yi, const int se, const int verbose)
Linear integration of TAC with trapezoidal method.
Definition integrate.c:33
int liDerivate(double *x, double *y, const int nr, double *d, double *dd, const int verbose)
Simplistic derivation of TAC as Δy divided by Δx, in relation to the previous point.
Definition integrate.c:444
int nnls(double **a, int m, int n, double *b, double *x, double *rnorm, double *wp, double *zzp, int *indexp)
Definition nnls.c:43
double ttac_xmax
Definition tpctacmod.h:39
double dtstep
Definition tpctacmod.h:51
double ttac_xmin
Definition tpctacmod.h:37
double btac_xmax
Definition tpctacmod.h:43
double btac_xmin
Definition tpctacmod.h:41
double fitend
Definition tpctacmod.h:45
unit tunit
Definition tpctac.h:109
int tacDuplicate(TAC *tac1, TAC *tac2)
Make a duplicate of TAC structure.
Definition tac.c:356
int tacAllocate(TAC *tac, int sampleNr, int tacNr)
Definition tac.c:130
@ TPCERROR_BAD_FIT
Fitting not successful.
@ TPCERROR_OUT_OF_MEMORY
Cannot allocate memory.
@ TPCERROR_INVALID_X
Invalid sample time.