TACFitter#

class petpal.kinetic_modeling.tac_fitting.TACFitter(pTAC: numpy.ndarray, tTAC: numpy.ndarray, weights: None | float | numpy.ndarray = None, tcm_func: Callable = None, fit_bounds: numpy.ndarray | None = None, resample_num: int = 512, aif_fit_thresh_in_mins: float = 30.0, max_iters: int = 2500)#

Bases: object

A class used for fitting Tissue Compartment Models(TCM) to Time Activity Curves (TAC).

It facilitates and simplifies the curve fitting process of TCM functions to TAC data. The class takes in raw TAC data for the plasma and tissue as input, and provides numerous utility methods to prepare data, set up fitting parameters, and perform the curve fitting. The resample method ensures data is appropriate for curve fitting by interpolating the TAC data over a regular time grid, and includes a time=0 data-point to the TACs if necessary.

The class provides multiple options for setting up weights for the curve fitting residuals and for providing initial guesses and setting up bounds for the fitting parameters of the TCM function.

Allows fitting on the basis of various TCM functions like one-tissue compartment model (1TCM), 2TCM, and others.

Variables:
  • resample_times (np.ndarray) – Times at which TACs are resampled.

  • resampled_t_tac (np.ndarray) – Tissue TAC values resampled at these times.

  • p_tac_vals (np.ndarray) – Plasma TAC values used for feeding to TCM function.

  • raw_t_tac (np.ndarray) – Raw TAC times for tissue, fed at initialization.

  • weights (np.ndarray) – Weights for handling residuals during the optimization process.

  • tgt_tac_vals (np.ndarray) – Tissue TAC values to fit TCM model.

  • fit_param_number (int) – Number of fitting parameters in the TCM function.

  • initial_guesses (np.ndarray) – Initial guesses for all the parameters for curve fitting.

  • bounds_hi (np.ndarray) – Upper bounds for all the parameters for curve fitting.

  • fit_results (np.optimize.OptimizeResult) – The results of the fit, including optimized parameters and covariance matrix.

  • fit_param_names (List[str]) – Names of fitting parameters in the TCM function.

  • raw_p_tac (np.ndarray) – Raw TAC times for plasma, fed at initialization.

  • resampled_p_tac (np.ndarray) – Plasma TAC values resampled on these times.

  • sanitized_t_tac (np.ndarray) – Sanitized version of tissue TAC times.

  • bounds_lo (np.ndarray) – Lower bounds for all the parameters for curve fitting.

  • bounds (np.ndarray) – Bounds for each parameter for curve fitting.

  • max_func_evals (int) – Maximum number of function evaluations (iterations) for the optimization process.

  • tcm_func (Callable) – The tissue compartment model (TCM) function to fit.

  • sanitized_p_tac (np.ndarray) – Sanitized version of plasma TAC times.

  • delta_t (float) – Delta between the newly created time steps in resampled times.

Example

In the following quick example, tTAC represents a tissue TAC ([times, values]) and pTAC represents the input function ([times, values]). Furthermore, we want to fit the provided tTAC with a 2TCM.

import petpal.kinetic_modeling.tcms_as_convolutions as pet_tcm
import petpal.kinetic_modeling.tac_fitting as pet_fit
import numpy as np

tcm_func = pet_tcm.gen_tac_2tcm_cpet_from_tac
fit = pet_fit.TACFitter(pTAC=pTAC, tTAC=tTAC, tcm_func=tcm_func, resample_num=512)
fit.run_fit()
fit_params = fit.fit_results[0]
print(fit_params.round(3))

In the following example, we use an FDG input function from the module-provided data, and simulate a noisy 1TCM TAC and fit it – showing a plot of everything at the end.

import numpy as np
import petpal.kinetic_modeling.tcms_as_convolutions as pet_tcm
import petpal.kinetic_modeling.tac_fitting as pet_fit
import matplotlib.pyplot as plt
import petpal.utils.testing_utils as pet_tst
import petpal.visualizations.tac_plots as tac_plots

tcm_func = pet_tcm.gen_tac_1tcm_cpet_from_tac
pTAC = np.asarray(np.loadtxt('../../../../../data/tcm_tacs/fdg_plasma_clamp_evenly_resampled.txt').T)
tTAC = tcm_func(*pTAC, k1=1.0, k2=0.25, vb=0.05)
tTAC[1] = pet_tst.add_gaussian_noise_to_tac_based_on_max(tTAC[1])

fitter = pet_fit.TACFitter(pTAC=pTAC, tTAC=tTAC, tcm_func=tcm_func)
fitter.run_fit()
fit_params = fitter.fit_results[0]
fit_tac = pet_tcm.gen_tac_1tcm_cpet_from_tac(*pTAC, *fit_params)

plotter = tac_plots.TacFigure()
plotter.add_tac(*pTAC, label='Input TAC', color='black', ls='--')
plotter.add_tac(*tTAC, label='Tissue TAC', color='blue', ls='', marker='o', mec='k')
plotter.add_tac(*fit_tac, label='Fit TAC', color='red', ls='-', marker='', lw=2.5)
plt.legend()
plt.show()

(Source code, png, hires.png, pdf)

../../../../_images/TACFitter-1.png

Fitting a noisy simulated 1TCM TAC.#

See also

  • TACFitterWithoutBloodVolume to assume \(V_B=0\) and only fit the kinetic parameters.

Initialize TACFitter with provided arguments.

The init function performs several important operations:
  1. It sets the maximum number of function evaluations (iterations) for the optimization process.

  2. It sets the TCM function properties and initial bounds with the provided TCM function and fit bounds.

  3. It loads the raw tissue and plasma TACs and then resamples them evenly over a regular time grid.

  4. It determines the weights to be used for handling residuals during the optimization process.

  5. It sets the plasma TAC values and tissue TAC values to fit the TCM model.

Parameters:
  • pTAC (np.ndarray) – The plasma TAC, with the form [times, values].

  • tTAC (np.ndarray) – The tissue TAC to which we will fit a TCM, with the form [times, values].

  • weights (float, np.ndarray or None, optional) – Weights for handling residuals during the optimization process. If None, all residuals are equally weighted. Defaults to None.

  • tcm_func (Callable, optional) – The specific TCM function to be used for fitting. Defaults to None.

  • fit_bounds (np.ndarray or None, optional) – Bounds for each parameter for curve fitting. If None, they will be guessed. Defaults to None.

  • resample_num (int, optional) – The number of time points used when resampling TAC data. Defaults to 512.

  • aif_fit_thresh_in_mins (float, optional) – The threshold in minutes when resampling. Defaults to 30.0.

  • max_iters (int, optional) – Maximum number of function evaluations (iterations) for the optimization process. Defaults to 2500.

_validate_inputs(input_tac: numpy.ndarray, roi_tac: numpy.ndarray, tcm_func: Callable)#
_setup_bounds(fit_bounds: numpy.ndarray | None) numpy.ndarray#
resample_tacs_evenly(fit_thresh_in_mins: float, resample_num: int) None#

Resample pTAC and tTAC evenly with respect to time, and at the same times.

The method takes a threshold in minutes and a resample number as inputs. It starts by sanitizing the pTAC and tTAC (prepending a \(f(t=0)=0\) point to data if necessary). A regularly sampled time is then generated using the start, end, and number of samples dictated by resample_num. Following this, an interpolation object is created using the petpal.blood_input.BloodInputFunction class for the pTAC. This allows both interpolation and extrapolation for times beyond the pTAC onto the new tTAC times.

Finally, the method resamples the sanitized tTAC and pTAC across these new evenly distributed times to ensure that they are regularly spaced over time. These resampled values are stored for future computations. The \(\Delta t\) for the regularly sampled times is also stored.

Parameters:
  • fit_thresh_in_mins (float) – Threshold in minutes used for defining how to fit half of the pTAC. The fitting time threshold determines the point at which the pTAC switches from interpolation to fitting. It should be a positive float value.

  • resample_num (int) – Number of samples to generate when resampling the tTAC. This will be the total number of samples in tTAC after it has been resampled. It should be a positive integer.

Returns:

None

Side Effects:
  • sanitized_t_tac (np.ndarray): Sanitized version of the original tTAC given during class initialization.

  • sanitized_p_tac (np.ndarray): Sanitized version of the original pTAC given during class initialization.

  • resample_times (np.ndarray): Regularly sampled time points generated from the start and end of sanitized tTAC, and the passed resample_num.

  • delta_t (float): Delta between the newly created time steps in resample_times.

  • resampled_t_tac (np.ndarray): tTAC resampled at the time points defined in resample_times.

  • resampled_p_tac (np.ndarray): pTAC resampled and extrapolated (if necessary) at the time points defined in resample_times.

See also

  • petpal.blood_input.BloodInputFunction

set_weights(weights: float | str | None) None#

Sets the weights for handling the residuals in the optimization process.

The weights parameter determines how weights will be used:
  • It can be a float which will generate the weights based on an exponential decay formula. We assume that the passed in float is the decay constant, \(\lambda=\ln(2)/T_{1/2}\), where the half-life is in minutes. The weights are generated as: \(\sigma_i=\sqrt{e^{-\lambda t_i}C(t_i)}\), to be used as the sigma parameter for scipy.optimize.curve_fit().

  • If it’s a numpy array, the weights are linearly interpolated on the calculated resample_times.

  • If no specific value or an array is given, a numpy array of ones is used (i.e., it assumes equal weight).

The method asserts that resampled_t_tac has been computed, thus resample_tacs_evenly() method should be run before this.

Parameters:

weights (Union[float, str, None]) – Determines how weights will be computed. If a float, it is used as the exponential decay constant. If a numpy array, the provided weights are linearly interpolated on the calculated resampled times. If None, equal weights are assumed.

Returns:

None

Side Effects:
weights (np.ndarray): Sets the weights attribute of the class based on logical conditions. Either

they are based on an exponential decay function, directly supplied, or assumed as equal weights.

static sanitize_tac(tac_times_in_minutes: numpy.ndarray, tac_vals: numpy.ndarray) numpy.ndarray#

Makes sure that the Time-Activity Curve (TAC) starts from time zero.

The method ensures that the TAC starts from time zero by checking the first timestamp. If it’s not zero, a zero timestamp and value are prepended, otherwise, the first value is set to zero. This method assumes that tac_times_in_minutes and tac_vals arrays have the same shape.

Parameters:
  • tac_times_in_minutes (numpy.ndarray) – The original times of the TAC.

  • tac_vals (numpy.ndarray) – The original values of the TAC.

Returns:

numpy.ndarray – The sanitized TAC: [sanitized_times, sanitized_vals].

static resample_tac_on_new_times(tac_times_in_minutes: numpy.ndarray, tac_vals: numpy.ndarray, new_times: numpy.ndarray) numpy.ndarray#

Resamples the Time-Activity Curve (TAC) on given new time points by linear interpolation.

The method performs a linear interpolation of tac_vals on new_times based on tac_times_in_minutes.

Parameters:
  • tac_times_in_minutes (numpy.ndarray) – The original times of the TAC.

  • tac_vals (numpy.ndarray) – The original values of the TAC.

  • new_times (numpy.ndarray) – The new times to resample the TAC on.

Returns:

numpy.ndarray – The resampled TAC: the resampled times and values. [new_times, new_vals].

See also

numpy.interp()

fitting_func(x: numpy.ndarray, *params) numpy.ndarray#

A wrapper function to fit the Tissue Compartment Model (TCM) using given parameters.

It calculates the results of the TCM function with the given times and parameters using the resampled pTAC.

Parameters:
  • x (np.ndarray) – The independent data (time-points for TAC)

  • *params – The parameters for the TCM function

Returns:

np.ndarray – The values of the TCM function with the given parameters at the given x-values.

run_fit() None#

Runs the optimization/fitting process on the data, using previously defined function and parameters.

This method runs the curve fitting process on the TAC data, starting with the initial guesses for the parameters and the preset bounds for each. fitting_func, initial guesses and bounds should have been set prior to calling this method. Optimized fit results and fit covariances are stored in fit_results.

Returns:

None

Side Effects:
  • fit_results (OptimizeResult): The results of the fit, including optimized parameters and covariance matrix. Fitted values can be extracted using fit_results.x, among other available attributes (refer to scipy.optimize.curve_fit() documentation for more details).