# EFFECTS

A required verbatim section that defines fixed effects and random effects for use in mixed effects models. The EFFECTS section defines a level structure, which dictates the number of instances of the `f[X]` and `r[X]` effect variables.

For example, `f[X]` variables representing fixed effects are usually declared at the POP level, so there is only one value of each `f[X]`. Whereas `r[X]` variables representing random effects are usually declared at the ID level, so each individual has a sample from each random effect. It is also possible to define further sub levels below the ID level, for example within individual occasions which have there own `r[X]` variables, see Inter-Occasion Variation (IOV).

The EFFECTS section is required by the following scripts:-

- Tut Script
- Gen Script
- Fit Script
- MTut Script
- MGen Script
- MFit Script
- MSim Script

i.e. Any script that defines a mixed effect model. Note that a Tut Script or MTut Script has two separate EFFECTS sections named GEN_EFFECTS and FIT_EFFECTS.

## EFFECTS with two levels from a fit_script

The example below is used in Fitting a Two Compartment PopPK Model.

    EFFECTS:
        POP: |
            f[KA] ~ P1.0
            f[CL] ~ P1.0
            f[V1] ~ P20
            f[Q] ~ P0.5
            f[V2] ~ P100
            f[KA_isv,CL_isv,V1_isv,Q_isv,V2_isv] ~ spd_matrix() [
                [0.05],
                [0.01, 0.05],
                [0.01, 0.01, 0.05],
                [0.01, 0.01, 0.01, 0.05],
                [0.01, 0.01, 0.01, 0.01, 0.05],
            ]
            f[PNOISE] ~ P0.1
        ID: |
            r[KA, CL, V1, Q, V2] ~ mnorm([0,0,0,0,0], f[KA_isv,CL_isv,V1_isv,Q_isv,V2_isv])

The example above defines two levels:-

- POP - single value of each `f[X]` variable over whole population
- ID - one value per individual for each `r[X]` variable

This example defines 5 mean fixed effect parameters i.e. `f[KA], f[CL], f[V1], f[Q], f[V2]`, a 5x5 covariance matrix `f[KA_isv, CL_isv, V1_isv, Q_isv, V2_isv]`, a proportional noise variable `f[PNOISE]` and a 5 element vector `r[KA, CL, V1, Q, V2]` of random effects defined for each individual.

Every variable declared at the POP level has one shared value over the whole population. The ID level creates a single instance of each `r[X]` distribution for each ‘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 Fig. 50.

Fig. 50 EFFECTS structure with two levels

Here the number of `r[X]` values is dependent on the number of individuals in the data file.

## EFFECTS with three levels from a fit_script

It is possible to add a further level as follows:-

    EFFECTS:
        POP: |
            f[KA] ~ P1.0
            f[CL] ~ P1.0
            f[V1] ~ P20
            f[Q] ~ P0.5
            f[V2] ~ P100
            f[KA_isv,CL_isv,V1_isv,Q_isv,V2_isv] ~ spd_matrix() [
                [0.05],
                [0.01, 0.05],
                [0.01, 0.01, 0.05],
                [0.01, 0.01, 0.01, 0.05],
                [0.01, 0.01, 0.01, 0.01, 0.05],
            ]
            f[KA_iov,CL_iov,V1_iov,Q_iov,V2_iov] ~ spd_matrix() [
                [0.05],
                [0.01, 0.05],
                [0.01, 0.01, 0.05],
                [0.01, 0.01, 0.01, 0.05],
                [0.01, 0.01, 0.01, 0.01, 0.05],
            ]
            f[PNOISE] ~ P0.1
        ID: |
            r[KA, CL, V1, Q, V2] ~ mnorm(
                [0,0,0,0,0],
                f[KA_isv,CL_isv,V1_isv,Q_isv,V2_isv]
            )
        IOV: |
            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]
            )

The example above defines three levels:-

- POP - single value of each `f[X]` variable
- ID - one value per individual for each `r[X]` variable
- IOV - one value per iov per individual for each `r[X]` variable

The IOV level creates an extra level of `r[KA_iov, CL_iov, V1_iov, Q_iov, V2_iov]` variables. If there are say 2 different values of `c[IOV]` in the data file (i.e. two occasions) then each individual has a 5 element vector `r[KA, CL, V1, Q, V2]` at the ID level and additionally two 5 element vectors `r[KA_iov, CL_iov, V1_iov, Q_iov, V2_iov]` (one for each occasion) at the IOV level.

The structure of the mixed effects is now as show in Fig. 51.

Fig. 51 EFFECTS structure with three levels

For more information on this topic see Inter-Occasion Variation (IOV).

## EFFECTS with two levels from a gen_script

The example below is used in Generate a Two Compartment PopPK Data Set.

    EFFECTS:
        POP: |
            c[AMT] = 100.0
            f[KA] = 0.2
            f[CL] = 2.0
            f[V1] = 50
            f[Q] = 1.0
            f[V2] = 80
            f[KA_isv,CL_isv,V1_isv,Q_isv,V2_isv] = [
                [0.1],
                [0.01, 0.03],
                [0.01, -0.01, 0.09],
                [0.01, 0.02, 0.01, 0.07],
                [0.01, 0.02, 0.01, 0.01, 0.05],
            ]
            f[PNOISE] = 0.15
        ID: |
            c[ID] = sequential(50)
            t[DOSE] = 2.0
            t[OBS] ~ unif(1.0, 50.0; 5)
            # t[OBS] = range(1.0, 50.0; 5)
            r[KA, CL, V1, Q, V2] ~ mnorm([0,0,0,0,0], f[KA_isv,CL_isv,V1_isv,Q_isv,V2_isv])

The example above defines two levels and is similar to the EFFECTS with two levels from a fit_script section. The Fit Script defines `f[X]` and `r[X]` variables. Additionally this Gen Script version defines `c[X]` variables and additionally `t[DOSE]` and `t[OBS]` variables that define the dosing and observation rows of the generated data file.

In the POP section:-

    POP: |
        c[AMT] = 100.0

This syntax creates a `c[AMT]` field in the data file which is constant over all rows. In the ID section:-

    ID: |
        c[ID] = sequential(50)

This syntax creates a `c[ID]` field in the data file which has values of [1,50]. i.e. 50 individuals. Also in the ID sections these `t[X]` variables are declared:-

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

The `t[DOSE]` creates a dose row at time 2.0 for all individuals. The `t[OBS]` line creates 5 observation rows at random time points in the range [1,50.0].

## EFFECTS with three levels from a gen_script

It is possible to add a further level to the Gen Script EFFECTS as follows:-

    EFFECTS:
        POP: |
            c[AMT] = 100.0
            f[KA] = 0.2
            f[CL] = 2.0
            f[V1] = 50
            f[Q] = 1.0
            f[V2] = 80
            f[KA_isv,CL_isv,V1_isv,Q_isv,V2_isv] = [
                [0.1],
                [0.01, 0.03],
                [0.01, -0.01, 0.09],
                [0.01, 0.02, 0.01, 0.07],
                [0.01, 0.02, 0.01, 0.01, 0.05],
            ]
            f[KA_iov,CL_iov,V1_iov,Q_iov,V2_iov] = [
                [0.1],
                [0.01, 0.03],
                [0.01, -0.01, 0.09],
                [0.01, 0.02, 0.01, 0.07],
                [0.01, 0.02, 0.01, 0.01, 0.05],
            ]
            f[PNOISE] = 0.15

        ID: |
            c[ID] = sequential(50)
            r[KA, CL, V1, Q, V2] ~ mnorm([0,0,0,0,0], f[KA_isv,CL_isv,V1_isv,Q_isv,V2_isv])

        IOV: |
            c[IOV] = 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]
            )

The obvious difference between EFFECTS with two levels from a gen_script and the three level version above is the addition of the third section:-

    IOV: |
        c[IOV] = 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]
        )

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

    IOV: |
        c[IOV] = sequential(2)

i.e. rows with `c[IOV]` taking the values [1,2] are created. Within each occasion the `t[DOSE]` and `t[OBS]` create a dosing row and 5 observation rows. Note it is necessary to move the `t[X]` variables from the ID level to the IOV level. In a Gen Script it usually makes sense to place the `t[X]` variables at the lowest level.

## Combining EFFECTS in a tut_script

A Tut Script combines a Gen Script and a Fit Script, so has to encode both a generating EFFECTS section and a fitting EFFECTS section.

### GEN_EFFECTS

The generating EFFECTS section in a Tut Script is called GEN_EFFECTS. This section is transcribed into the EFFECTS section in the child Gen Script.

The GEN_EFFECTS can contain `f[X]`, `r[X]`, `t[X]` and `c[X]` variable definitions in each level.

### FIT_EFFECTS

The fitting EFFECTS section in a Tut Script is called FIT_EFFECTS. This section is transcribed into the EFFECTS section in the child Fit Script.

The FIT_EFFECTS section can contain `f[X]` and `r[X]` variable definitions in each level.

## EFFECTS with two levels from a tut_script

The examples below are used in Generate data and Fit using a Two Compartment Model.

    GEN_EFFECTS:
        POP: |
            c[AMT] = 100.0
            f[KA] = 0.2
            f[CL] = 2.0
            f[V1] = 50
            f[Q] = 1.0
            f[V2] = 80
            f[KA_isv,CL_isv,V1_isv,Q_isv,V2_isv] = [
                [0.1],
                [0.01, 0.03],
                [0.01, -0.01, 0.09],
                [0.01, 0.02, 0.01, 0.07],
                [0.01, 0.02, 0.01, 0.01, 0.05],
            ]
            f[PNOISE] = 0.15
        ID: |
            c[ID] = sequential(50)
            t[DOSE] = 2.0
            t[OBS] ~ unif(1.0, 50.0; 5)
            # t[OBS] = range(1.0, 50.0; 5)
            r[KA, CL, V1, Q, V2] ~ mnorm([0,0,0,0,0], f[KA_isv,CL_isv,V1_isv,Q_isv,V2_isv])

    FIT_EFFECTS:
        POP: |
            f[KA] ~ P1.0
            f[CL] ~ P1.0
            f[V1] ~ P20
            f[Q] ~ P0.5
            f[V2] ~ P100
            f[KA_isv,CL_isv,V1_isv,Q_isv,V2_isv] ~ spd_matrix() [
                [0.05],
                [0.01, 0.05],
                [0.01, 0.01, 0.05],
                [0.01, 0.01, 0.01, 0.05],
                [0.01, 0.01, 0.01, 0.01, 0.05],
            ]
            f[PNOISE] ~ P0.1
        ID: |
            r[KA, CL, V1, Q, V2] ~ mnorm([0,0,0,0,0], f[KA_isv,CL_isv,V1_isv,Q_isv,V2_isv])

The Tut Script combines the Gen Script and Fit Script levels.

## EFFECTS with three levels from a tut_script

It is possible to add the third level to a Tut Script as follows:-

    GEN_EFFECTS:
        POP: |
            c[AMT] = 100.0
            f[KA] = 0.2
            f[CL] = 2.0
            f[V1] = 50
            f[Q] = 1.0
            f[V2] = 80
            f[KA_isv,CL_isv,V1_isv,Q_isv,V2_isv] = [
                [0.1],
                [0.01, 0.03],
                [0.01, -0.01, 0.09],
                [0.01, 0.02, 0.01, 0.07],
                [0.01, 0.02, 0.01, 0.01, 0.05],
            ]
            f[KA_iov,CL_iov,V1_iov,Q_iov,V2_iov] = [
                [0.1],
                [0.01, 0.03],
                [0.01, -0.01, 0.09],
                [0.01, 0.02, 0.01, 0.07],
                [0.01, 0.02, 0.01, 0.01, 0.05],
            ]
            f[PNOISE] = 0.15
        ID: |
            c[ID] = sequential(50)
            r[KA, CL, V1, Q, V2] ~ mnorm([0,0,0,0,0], f[KA_isv,CL_isv,V1_isv,Q_isv,V2_isv])
        IOV: |
            c[IOV] = 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]
            )

    FIT_EFFECTS:
        POP: |
            f[KA] ~ P1.0
            f[CL] ~ P1.0
            f[V1] ~ P20
            f[Q] ~ P0.5
            f[V2] ~ P100
            f[KA_isv,CL_isv,V1_isv,Q_isv,V2_isv] ~ spd_matrix() [
                [0.05],
                [0.01, 0.05],
                [0.01, 0.01, 0.05],
                [0.01, 0.01, 0.01, 0.05],
                [0.01, 0.01, 0.01, 0.01, 0.05],
            ]
            f[KA_iov,CL_iov,V1_iov,Q_iov,V2_iov] ~ spd_matrix() [
                [0.05],
                [0.01, 0.05],
                [0.01, 0.01, 0.05],
                [0.01, 0.01, 0.01, 0.05],
                [0.01, 0.01, 0.01, 0.01, 0.05],
            ]
            f[PNOISE] ~ P0.1
        ID: |
            r[KA, CL, V1, Q, V2] ~ mnorm([0,0,0,0,0], f[KA_isv,CL_isv,V1_isv,Q_isv,V2_isv])
        IOV: |
            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]
            )

This is similar to the EFFECTS with three levels from a fit_script and EFFECTS with three levels from a gen_script examples. The Tut Script copies GEN_EFFECTS into Gen Script EFFECTS and FIT_EFFECTS into Fit Script EFFECTS.

## Rules for each EFFECTS level

Each individual level of the EFFECTS is a verbatim section, as follows:-

    EFFECTS:
        <level_name>: |

However the level 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:-

    x[VAR] = <some definition>

Or

    x[VAR] ~ <some definition>

Are allowed. You cannot use `if` statements for example. And all effect levels are declarative and unordered. i.e. the order of the statements in a single effects level makes no difference to the mixed effect model.

The variables you are allowed to declare on the left hand side depends on which type of script you are running:-

- In a Fit Script you are allowed to declare `f[X]` and `r[X]` only.
- In a Gen Script you are allowed to declare `f[X]`, `r[X]`, `c[X]` and `t[X]`
- All variables must have a unique name, i.e. no duplicate `c[X]` or `f[X]` or `r[X]`
- If a variable is on the right hand side of an expression it must be defined in a level above the current level

You can not use `m[X]`, `d[X]`, `p[X]` etc variables in EFFECTS.

Like all verbatim sections it is possible to introduce syntax errors by writing malformed code in EFFECTS. Any errors will be brought to the users attention when PoPy attempts to interpret the verbatim sections and form a tree structure to manage the fixed effect and random effect variables.