.. _level_params:

LEVEL_PARAMS
##############

A required :term:`verbatim` section that defines |fes| and |res| for use in mixed effects models. The |level_params| defines a level structure, which dictates the number of instances of the |fx| and |rx| effect variables. 

For example, |fx| variables representing |fes| are usually declared at the |global| level, so there is only one value of each |fx|. Whereas |rx| variables representing |res| are usually declared at the |indiv| level, so each individual has a sample from each |re|. It's also possible to define further sub levels below the |indiv| level, for example within individual occasions which have there own |rx| variables, see :ref:`inter_occasion_variation`.

The |level_params| section is required by the following scripts:- 

* :ref:`tut_script`
* :ref:`gen_script`
* :ref:`fit_script`
* :ref:`mtut_script`
* :ref:`mgen_script`
* :ref:`mfit_script`
* :ref:`msim_script`

|ie| Any script that defines a mixed effect model.

.. _example_two_level_params_fit:

LEVEL_PARAMS with two levels from a fit_script
===============================================

The example below is used in :ref:`builtin_fit_example`.

.. literalinclude:: 
    /_autogen/quick_start/builtin_fit_example/fit_sections/LEVEL_PARAMS.pyml
    :language: pyml

The example above defines two levels:-

* |global| - single value of each |fx| variable
* |indiv| - one value per individual for each |rx| variable

This example defines 5 mean |fe| parameters |ie| |fx_main_builtin|, a 5x5 covariance matrix |fx_isv_mat_builtin|, a proportional noise variable :pyml:`f[PNOISE]` and a 5 element vector |rx_vec_builtin| of |res| defined for each individual. 

Note each level has the following (required) sections:-

* params - A :term:`verbatim` section where |fx| and |rx| variables are declared
* split_field - The name of the variable used to partition the data
* split_dict - A |python| dictionary specifying the partition of the data

Note the |global| level has these null entries:-

.. code-block:: pyml

    GLOBAL:
        split_field: None
        split_dict: {}
    
Here the 'split_field' is null, so the |global| level is |not| partitioned. Every variable declared at the |global| level has **one** shared value over the whole population. 

The |indiv| level has the following entries:-

.. code-block:: pyml
    
    INDIV:
        split_field: ID
        split_dict: "*"

This means that the |indiv| level is split using the 'ID' field. The "*" indicates that a partition is created for every distinct value of the 'ID' field present in the |data_file|. This is similar to the **factor** concept in |r|. The structure of the mixed effects is a tree, see :numref:`fig_two_level_tree`.

.. _fig_two_level_tree:

.. figure:: /popy_guide/hierarchy_diagrams/two_level_tree.*
    :width: 80%
    :align: center
    
    |level_params| structure with **two** levels

Here the number of |rx| values is dependent on the number of individuals in the |data_file|.
    
.. _example_three_level_params_fit:

LEVEL_PARAMS with three levels from a fit_script
===================================================
    
It is possible to add a further level as follows:-
        
.. literalinclude:: LEVEL_PARAMS_three_levels_fit.pyml
    :language: pyml
    
The example above defines three levels:-

* |global| - single value of each |fx| variable
* |indiv| - one value per individual for each |rx| variable
* |iov| - one value per iov per individual for each |rx| variable
    
The |iov| level creates an extra level of |rx_iov_vec_builtin| variables. If there are say 2 different values of :pyml:`c[OC]` in the |data_file| (|ie| two occasions) then each individual has a 5 element vector |rx_vec_builtin| at the |indiv| level and additionally two 5 element vectors |rx_iov_vec_builtin| (one for each occasion) at the |iov| level.
    
The structure of the mixed effects is now as show in :numref:`fig_three_level_tree`.

.. _fig_three_level_tree:

.. figure:: /popy_guide/hierarchy_diagrams/three_level_tree.*
    :width: 80%
    :align: center
    
    |level_params| structure with **three** levels
    
For more information on this topic see :ref:`inter_occasion_variation`.
    
.. _example_two_level_params_gen:

LEVEL_PARAMS with two levels from a gen_script
===============================================

The example below is used in :ref:`builtin_gen_example`.

.. literalinclude:: 
    /_autogen/quick_start/builtin_gen_example/gen_sections/LEVEL_PARAMS.pyml
    :language: pyml

The example above defines two levels and is similar to the :ref:`example_two_level_params_fit` section. The :ref:`fit_script` defines |fx| and |rx| variables. Additionally this :ref:`gen_script` version defines |cx| variables and additionally |tdose| and |tobs| variables that define the dosing and |obs| rows of the generated |data_file|.  

In the |global| section:-

.. code-block:: pyml

    GLOBAL:
       params: |
            c[AMT] = 100.0
    
This syntax creates a |camt| field in the |data_file| which is constant over **all** rows. In the |indiv| section:-

.. code-block:: pyml

    INDIV:
        params: |
            c[ID] = sequential(50)
            
This syntax creates a |cid| field in the |data_file| which has values of [1,50]. |ie| 50 individuals. Also in the |indiv| sections these |tx| variables are declared:-
            
.. code-block:: pyml

    INDIV:
        params: |
            t[DOSE] = 2.0
            t[OBS] ~ unif(1.0, 50.0; 5)

The |tdose| creates a dose row at time 2.0 for all individuals. The |tobs| line creates 5 |obs| rows at random time points in the range [1,50.0].
    
.. _example_three_level_params_gen:

LEVEL_PARAMS with three levels from a gen_script
===================================================
    
It is possible to add a further level to the :ref:`gen_script` LEVEL_PARAMS as follows:-
        
.. literalinclude:: LEVEL_PARAMS_three_levels_gen.pyml
    :language: pyml
    
The obvious difference between :ref:`example_two_level_params_gen` and the three level version above is the addition of the third section:-

.. code-block:: pyml

    IOV:
        params: |
            c[OC] = sequential(2)
            t[DOSE] = 2.0
            t[OBS] ~ unif(1.0, 50.0; 5)
            # t[OBS] = range(1.0, 50.0; 5)
            r[KA_iov, CL_iov, V1_iov, Q_iov, V2_iov] ~ mnorm( 
                [0,0,0,0,0], 
                f[KA_iov, CL_iov, V2_iov, Q_iov, V3_iov] 
            )
        split_field: OC
        split_dict: "*"

This denotes an |iov| level with two occasions for each individual. Note that this line creates two occasions:-

.. code-block:: pyml

    IOV:
        params: |
            c[OC] = sequential(2)
            
|ie| rows with :pyml:`c[OC]` taking the values [1,2] are created. Within each occasion the |tdose| and |tobs| create a dosing row and 5 observation rows. Note it is necessary to move the |tx| variables from the |indiv| level to the |iov| level. In a :ref:`gen_script` it usually makes sense to place the |tx| variables at the lowest level.

.. _example_two_level_params_tut:

LEVEL_PARAMS with two levels from a tut_script
===============================================

The example below is used in :ref:`builtin_tut_example`.

.. literalinclude:: 
    /_autogen/quick_start/builtin_tut_example/tut_sections/LEVEL_PARAMS.pyml
    :language: pyml

The :ref:`tut_script` combines the :ref:`gen_script` and :ref:`fit_script` levels. It does this by each level having the following (required) sections:-

* gen_params - A :term:`verbatim` section where |fx|, |rx|, |tx| and |cx| variables are declared for the **child** :ref:`gen_script`
* fit_params - A :term:`verbatim` section where |fx| and |rx| variables are declared for the **child** :ref:`fit_script`
* split_field - The name of the variable used to partition the data
* split_dict - A dictionary specifying the partition of the data
    
    
.. _example_three_level_params_tut:

LEVEL_PARAMS with three levels from a tut_script
==================================================

It is possible to add the third level to a :ref:`tut_script` as follows:-

.. literalinclude:: LEVEL_PARAMS_three_levels_tut.pyml
    :language: pyml

This is similar to the :ref:`example_three_level_params_fit` and :ref:`example_three_level_params_gen` examples. The :ref:`tut_script` incorporates the :ref:`gen_script` 'params' into 'gen_params' and the :ref:`fit_script` 'params' into 'fit_params, over all three levels.
 
 
Rules for LEVEL_PARAMS->params section
=======================================

Each individual level of the |level_params| includes a :term:`verbatim` section called 'params', as follows:-

.. code-block:: pyml

    LEVEL_PARAMS:
        <level_name>:
            params: |

However the 'params' section is limited in what expressions it can accept. For example it is |not| pseudo |python| code, unlike the |preprocess|, |model_params| or |derivatives| sections, which act more like |python| functions.

Generally only declarative expressions of the type:-

.. code-block:: pyml

    x[VAR] = <some definition>
    
Or

.. code-block:: pyml

    x[VAR] ~ <some definition>

Are allowed. You cannot use :python:`if` statements for example. And all 'params' sections are declarative and unordered. |ie| the order of the statements in a single 'params' section makes no difference to the mixed effect model.

The variables you are allowed to declare on the |lhs| depends on which type of script you are running:-

* In a :ref:`fit_script` you are allowed to declare |fx| and |rx| only. 
* In a :ref:`gen_script` you are allowed to declare |fx|, |rx|, |cx| and |tx| 
* All variables must have a unique name, |ie| no duplicate |cx| or |fx| or |rx|
* If a variable is on the |rhs| of an expression it **must** be defined in a level **above** the current level

You can |not| use |mx|, |dx|, |px| etc variables in |level_params|.

Like all :term:`verbatim` sections it is possible to introduce syntax errors by writing malformed code in |level_params|. Any errors will be brought to the users attention when |popy| attempts to interpret the 'params' sections and form a tree structure to manage the |fe| and |re| variables.
 