.. _blq_example:


Generate BLQ observations and fit different error models
########################################################## 

In this example we will demonstrate generating and fitting to |blq| data using the |rectnorm_dist| with a simple depot + one compartment model as follows:-

.. _fig_blq_one_comp_depot_diagram_tut:

.. figure:: /_autogen/pop_examples/blq/blq_pk_tut/compartment_diagram.*
    :width: 40%
    :align: center
    
    One compartment model with depot dosing used to generate and fit |blq| PK data.
    
.. note::
    
   See the :ref:`sum_link_blq_pk_tut` obtained by the |popy| developers for this example, including input script and output data file.
 
.. _blq_tut_script:

Generating BLQ observations 
===============================

The |predictions| section to create |blq| data utilises the |rectnorm_dist|, as follows:-

.. literalinclude:: 
    /_autogen/pop_examples/blq/blq_pk_tut/tut_sections/PREDICTIONS.pyml
    :language: pyml      
    
This creates observations with a |llq| of 0.5, see :numref:`table_blq_generated_data`.

.. _table_blq_generated_data:

.. list-table:: Generated observations + true underlying model |pk| curves for first three individuals 
    :class: image_table
    
    * - .. thumbnail:: /_autogen/pop_examples/blq/blq_pk_tut/images/gen_sim_grph_outputs/indOBS_vs_TIME/000001.*
      - .. thumbnail:: /_autogen/pop_examples/blq/blq_pk_tut/images/gen_sim_grph_outputs/indOBS_vs_TIME/000002.*
      - .. thumbnail:: /_autogen/pop_examples/blq/blq_pk_tut/images/gen_sim_grph_outputs/indOBS_vs_TIME/000003.*

Notice that no observations are output below 0.5, as expected. PoPy outputs observations of 0.5, if the generated observation is in the interval [-inf, 0.5]. 

.. _blq_fit_rectnorm:

Fitting BLQ observations using rectnorm (correct error model)
==============================================================

We fit the same (correct) error model, using the same |predictions| section as follows:-

.. literalinclude:: 
    /_autogen/pop_examples/blq/blq_pk_tut/tut_sections/PREDICTIONS.pyml
    :language: pyml     

|ie| a |rectnorm_dist|, with a |llq| of 0.5. Note that, this fitting method does |not| require the |laplace| objective function, we can use the |foce| objective function instead in |popy|.

See :numref:`table_blq_rectnorm_fitted_data` for PK curves after fitting.

.. _table_blq_rectnorm_fitted_data:

.. list-table:: Fitted model |pk| curves vs true model |pk| curves for first three individuals 
    :class: image_table
    
    * - .. thumbnail:: /_autogen/pop_examples/blq/blq_pk_tut/images/fit_sim_grph_outputs/indOBS_vs_TIME/000001.*
      - .. thumbnail:: /_autogen/pop_examples/blq/blq_pk_tut/images/fit_sim_grph_outputs/indOBS_vs_TIME/000002.*
      - .. thumbnail:: /_autogen/pop_examples/blq/blq_pk_tut/images/fit_sim_grph_outputs/indOBS_vs_TIME/000003.*

Note that the fitted curves (solid blue) line are estimated to be below the |llq| level of 0.5 at later time points.

The estimated |fx| compared to the true |fx| are shown in :numref:`table_blq_true_vs_fit_fx_main_values` and :numref:`table_blq_true_vs_fit_fx_noise_values`.

.. _table_blq_true_vs_fit_fx_main_values:

.. csv-table:: Comparison of initial, fitted and true |fx| main values
    :file: ../../../_autogen/pop_examples/blq/blq_pk_tut/fx_comp_main.csv
    :header-rows: 1

.. _table_blq_true_vs_fit_fx_noise_values:

.. csv-table:: Comparison of initial, fitted and true |fx| noise values
    :file: ../../../_autogen/pop_examples/blq/blq_pk_tut/fx_comp_noise.csv
    :header-rows: 1

:numref:`table_blq_true_vs_fit_fx_main_values` and :numref:`table_blq_true_vs_fit_fx_noise_values` show that the :pyml:`f[KA], f[CL], f[V1], f[PNOISE]` parameters are recovered well when fitting with |rectnorm_dist|.

The full set of fitted |fx| variable is shown below:-

.. literalinclude:: /_autogen/pop_examples/blq/blq_pk_tut/blq_pk_fit.pyml_output/solN/final_fx_params.txt
    :language: pyml

These fitted values can be compared with fitting alternative error models below.

.. _blq_fit_norm:

Fitting BLQ observations using norm (incorrect error model)
============================================================

.. note::
    
   See the :ref:`sum_link_blq_pk_norm_fit_fit` script and results used by the |popy| developers for this example.

We fit a (incorrect) error model which treats observations of |llq| as actual 0.5 observations, using a |norm_dist|, as follows:-

.. literalinclude:: 
    /_autogen/pop_examples/blq/blq_pk_norm_fit/fit_sections/PREDICTIONS.pyml
    :language: pyml  

For fitted curves see :numref:`table_blq_norm_fitted_data`.

.. _table_blq_norm_fitted_data:

.. list-table:: Fitted model |norm_dist| error curves vs |llq| model |pk| curves for first three individuals 
    :class: image_table
    
    * - .. thumbnail:: /_autogen/pop_examples/blq/blq_pk_norm_fit/images/fit_sim_grph_outputs/indOBS_vs_TIME/000001.*
      - .. thumbnail:: /_autogen/pop_examples/blq/blq_pk_norm_fit/images/fit_sim_grph_outputs/indOBS_vs_TIME/000002.*
      - .. thumbnail:: /_autogen/pop_examples/blq/blq_pk_norm_fit/images/fit_sim_grph_outputs/indOBS_vs_TIME/000003.*

Note that the fitted curves (solid blue) line try to stay close to the |blq| values at 0.5, which is incorrect, as the |pk| curve should approach zero concentration instead.

The fitted |fx| values are:-

.. literalinclude:: /_autogen/pop_examples/blq/blq_pk_norm_fit/final_fx_params.txt
    :language: pyml

These fitted values are inaccurate compared to the parameters recovered using the |rectnorm_dist| in section :ref:`blq_fit_rectnorm` above.

.. _blq_fit_norm_half:

Fitting BLQ observations using half LLQ (approx error model)
============================================================

.. note::
    
   See the :ref:`sum_link_blq_pk_norm_fit_half_fit` script and results used by the |popy| developers for this example.


We fit a simple approx |blq| error model, which models observations of |llq| as bare 0.5* |llq| observations, by preprocessing the original observation data, as follows:-

.. literalinclude:: 
    /_autogen/pop_examples/blq/blq_pk_norm_fit_half/fit_sections/PREPROCESS.pyml
    :language: pyml 

The |norm_dist| is used to model these amended observations (similar to :ref:`blq_fit_norm` above), see:-

.. literalinclude:: 
    /_autogen/pop_examples/blq/blq_pk_norm_fit_half/fit_sections/PREDICTIONS.pyml
    :language: pyml  

For fitted curves using this half |llq| approximation, see :numref:`table_blq_norm_half_fitted_data`.

.. _table_blq_norm_half_fitted_data:

.. list-table:: Fitted model |norm_dist| error curves vs half |llq| model |pk| curves for first three individuals 
    :class: image_table
    
    * - .. thumbnail:: /_autogen/pop_examples/blq/blq_pk_norm_fit_half/images/fit_sim_grph_outputs/indOBS_vs_TIME/000001.*
      - .. thumbnail:: /_autogen/pop_examples/blq/blq_pk_norm_fit_half/images/fit_sim_grph_outputs/indOBS_vs_TIME/000002.*
      - .. thumbnail:: /_autogen/pop_examples/blq/blq_pk_norm_fit_half/images/fit_sim_grph_outputs/indOBS_vs_TIME/000003.*

Note that the fitted curves (solid blue) line get closer to zero (the true asymptotic concentration) as time increases, but are still heavily distorted by assuming the half |llq| values are true observations.

The fitted |fx| values are:-

.. literalinclude:: /_autogen/pop_examples/blq/blq_pk_norm_fit_half/final_fx_params.txt
    :language: pyml

These fitted values are similar to the results obtained in :ref:`blq_fit_norm` and also inaccurate compared to the parameters recovered using the |rectnorm_dist| in section :ref:`blq_fit_rectnorm` above.

.. _blq_fit_norm_ignore:

Fit to non-BLQ observations only (reduced data model)
======================================================

.. note::
    
   See the :ref:`sum_link_blq_pk_norm_fit_ignore_fit` script and results used by the |popy| developers for this example.

We can also just ignore the |blq| data, by using |preprocess| to remove the |llq| observations, as follows:-

.. literalinclude:: 
    /_autogen/pop_examples/blq/blq_pk_norm_fit_ignore/fit_sections/PREPROCESS.pyml
    :language: pyml 

The |norm_dist| is then used to model the above |llq| observations only, see:-

.. literalinclude:: 
    /_autogen/pop_examples/blq/blq_pk_norm_fit_ignore/fit_sections/PREDICTIONS.pyml
    :language: pyml  

The fitted curves are shown in :numref:`table_blq_norm_ignore_fitted_data`.

.. _table_blq_norm_ignore_fitted_data:

.. list-table:: Fitted model |norm_dist| error curves vs ignore |blq| model |pk| curves for first three individuals 
    :class: image_table
    
    * - .. thumbnail:: /_autogen/pop_examples/blq/blq_pk_norm_fit_ignore/images/fit_sim_grph_outputs/indOBS_vs_TIME/000001.*
      - .. thumbnail:: /_autogen/pop_examples/blq/blq_pk_norm_fit_ignore/images/fit_sim_grph_outputs/indOBS_vs_TIME/000002.*
      - .. thumbnail:: /_autogen/pop_examples/blq/blq_pk_norm_fit_ignore/images/fit_sim_grph_outputs/indOBS_vs_TIME/000003.*

Note that curves are fitted to the above |llq| observations only, |ie| earlier time points, but there is no data for later |llq| time points.

The fitted |fx| values are:- 

.. literalinclude:: /_autogen/pop_examples/blq/blq_pk_norm_fit_ignore/final_fx_params.txt
    :language: pyml

These fitted values are much better then the :ref:`blq_fit_norm` and :ref:`blq_fit_norm_half` approximatons, but not quite as accurate as the |rectnorm_dist| results in section :ref:`blq_fit_rectnorm`.
