The sequence and sleep statements

Sequential execution is where there is a sequence of statements A, B, C, etc., where A executes first in time, and only after A completes does B get to start, and so on. If control is sequential, then one can have “if” statements and loops, and variables that act like counters. One can say “x = x + 1” and know what it means, because it takes place at a point in time.

By contrast, in a PML model, the statements are not sequential, they are descriptive of the problem. They do not act at a point in time. They apply “all the time”. In PML code, outside of sequence statements (and assignment statements), relative order of statements does not matter.

The sequence statement denotes a series of expressions to evaluate or statements to process at certain times in a time-based model. The incorporation of sequence blocks into PML allows handling of models like enterohepatic circulation (see the “Modeling discontinuous events” section) in a general way.

There can be multiple sequence statements in a model and they are executed as if they were running in parallel. No assumption should be made about which sequence statement is processed first. For example, if two sequence blocks both initialize things, one cannot depend on which one does the initialization first. When a reset is encountered in the data, due to mapping a reset column, the sequence statement(s) are restarted.

Processing a block of expressions and statements in a sequence statement is started at the initial time in the model and continues until the end of the sequence block, or until a sleep statement is encountered. The sleep statement, with syntax is given by:

   sleep(number)

instructs the processing of the statements and expressions in the current sequence block to stop for the time specified by the number argument. The number argument is a relative time, not an absolute time. It is important to use the sleep statement rather than tests against the time variable to ensure the stability of the algorithms. For example, write {sleep(10); A0=0} and not {if(t=10);A0=0}. The latter does not function as is intended. For a model to work, the sequence statement must be used instead of something like: if(t>=Tmax){do stuff}.

Initializing state variables: 

The sequence statement can be used to define initial conditions for ODEs. For example, one can say:

   sequence {
Aa=someExpression
A1=someOtherExpression
}

This sets the two state variables Aa and A1 to initial values, because the sequence block starts executing immediately when the subject begins.

Defining constants: 

If numeric constants are needed in the code, and there is a concern about performance of calculating them, a simple way to include them is the following:

   double(pi, e)
sequence {
pi=3.1415926535897932384626433832795
e=2.7182818284590452353602874713527
}

These are executed only once per subject, take essentially zero time to execute, and are far more precise than can be required.

Do not be concerned about the performance of secondary parameter calculations, such as half-life, because those are only calculated once, after all model fitting is completed.

Take some action after some time has passed: 

For example, to put in an extra dose at three time units after the subject has begun, and then yet another three time units later, one could say:

   sequence {
sleep(3)
Aa=Aa+someDoseAmount
sleep(3)
Aa=Aa+someDoseAmount
}

The sequence statement starts when the subject starts but the first thing it does is hit the sleep(3) statement, which means “wake up again after three time units”.

When the three time units have passed, then it does the next thing, which is to add a dose to Aa. Notice that an integrator variable like Aa can only be modified at particular points in time, so it can only be modified inside a sequence statement.

Then it sleeps for three more time units, gives another dose, and does nothing more.

Do different things depending on different conditions: 

The following sequence statement begins with sleeping for three time units, then checks if the amount in compartment Aa is less than two. If the amount is less than two, then add a dose to compartment Aa. Otherwise, do something else or do nothing, depending on code that would appear after the else line.

   sequence {
sleep(3)
if (Aa < 2){
Aa=Aa+someDoseAmount
} else {
}
}

Do things repeatedly: 

The following sequence statement says that, as long as t is less than 10, sleep three time units and then add a dose.

   sequence {
while(t < 10){
sleep(3)
Aa=Aa+someDoseAmount
}
}

Alternatively, a variable can be declared that can be set to different values. Then a sequence statement can be used to repeat the sleep + dose cycle ten times, as shown below:

   real(i)
sequence {
i=1
while(i <= 10){
sleep(3)
Aa=Aa+someDoseAmount
i=i+1
}
}

The block inside a sequence statement can consist of multiple blocks controlled by logical switches. For instance, in the example above, the expressions and statements inside the sequence statement are contained within a while block which instructs the sequence to repeat itself through the entire time period that observations are made.


Legal Notice | Contact Certara
© Certara USA, Inc. All rights reserved.