Back to Documentation

Tutorial 3: Advanced concepts

In this tutorial is presented the following concepts:

  • the parameter
  • the transition with condition (render a transition conditional),
  • the iteration slot (synchronize group of transitions),
  • the mole task (define a sub workflow encapsulated in a task).

Defining a parameter

In the first tutorial was introduced the concept of Prototype. Up to now, value of a data for a given prototype has been assigned inside tasks. The parameter enables assigning a value to a prototype from outside a task.

An example of parameter usage

import org.openmole.core.implementation.data.*
import org.openmole.plugin.task.groovy.*
import org.openmole.core.implementation.capsule.*
import org.openmole.core.implementation.data.*
import org.openmole.core.implementation.mole.*


proto1 = new Prototype("proto1", Integer)
parameter1 = new Parameter(proto1, 5)

t1 = new GroovyTask("t1")
t1.addParameter(parameter1)
t1.setCode("println 'proto1: ' + proto1")
 
ex = new MoleExecution(new Mole(new Capsule(t1)))
ex.start()

Defining a transition with condition

Sometimes it is relevant to define conditions on transitions. Doing so enables to perform a transition if the output of the previous task satisfies a particular condition.
On top of that, it also offers the opportunity to create cyclic workflows.

The task T2 is executed if the variable myInt, produced by T1, is greater than 2

The following example shows how to use conditions. In that case, an output is displayed by T2; in a case where the value of proto1 less than 2, T2 is not be executed and no output is displayed.

import org.openmole.core.implementation.data.*
import org.openmole.plugin.task.groovy.*
import org.openmole.core.implementation.transition.*
import org.openmole.core.implementation.capsule.*
import org.openmole.core.implementation.mole.*

proto1 = new Prototype("proto1", Integer)

t1 = new GroovyTask("t1")
t1.addOutput(proto1)
t1.setCode("proto1 = 3")

t2 = new GroovyTask("t2")
t2.addInput(proto1)
t2.setCode("println 'proto1: ' +proto1")
        
tc1 = new Capsule(t1)  
tc2 = new Capsule(t2)        
        
//Define the transition from tc1 and tc2 with a condition
new Transition(tc1, tc2, "proto1 > 2")
        
ex = new MoleExecution(new Mole(tc1))
ex.start()

Defining an iteration slot

In some case, it is convenient to define asynchronous transitions. The "TransitionSlot" class enables grouping transitions on a single entity called slot. All transition of a given a slot are synchronous. It means that they should all be performed before the next task is executed. To the contrary, transition slot are asynchronous, when all the transition of a slot are performed the task is submitted for execution. Note that each Capsule contains implicitly a default input slot, making possible to plug transitions on the capsule.
In the following example, the task T1 is run as longer as proto1 is greater than 1 for the first slot and greater than the 2 for the slot 2.

This workflow can be written as follow:

import org.openmole.core.implementation.data.*
import org.openmole.plugin.task.groovy.*
import org.openmole.core.implementation.transition.*
import org.openmole.core.implementation.capsule.*
import org.openmole.core.implementation.data.*
import org.openmole.core.implementation.mole.*

proto1 = new Prototype("proto1", Integer)
parameter0 = new Parameter(proto1,5)

t0 = new GroovyTask("t0")
t0.addParameter(parameter0)
t0.addOutput(proto1)

t1 = new GroovyTask("t1")
t1.addInput(proto1)
t1.addOutput(proto1)
t1.setCode("println 'proto1: ' +proto1")

t2 = new GroovyTask("t2")
t2.addInput(proto1)
t2.addOutput(proto1)
t2.setCode("proto1 = proto1-1")

tc0 = new Capsule(t0)
tc1 = new Capsule(t1)  
tc2 = new Capsule(t2)        

slot1 = new Slot(tc1)
slot2 = new Slot(tc1)

new Transition(tc0,tc1)
new Transition(tc1,tc2)
new Transition(tc2,slot1,"proto1 > 1")
new Transition(tc2,slot2,"proto1 > 2")
        
ex = new MoleExecution(new Mole(tc0))
ex.start()

Let us have a look to the output:

proto1: 5
proto1: 4
proto1: 4
proto1: 3
proto1: 3
proto1: 3
proto1: 3
proto1: 2
proto1: 2
proto1: 2
proto1: 2

What happens exactly?

  • We first execute T1, proto1 equals 5 and is displayed.
  • Then, in T2, proto1 is set to 4 and goes back to T1 through both slots.
  • Then T1 is executed twice (4 is displayed twice).
  • T2 is also executed twice and proto1, set to 3, goes back to T1 through both slots, so that T1 is this time executed 4 times (two slots for each task).
  • T2 is now executed 4 times and sets proto1 to 2. This time, the condition is not longer satisfied in the second slot, so that T1 it only executed 4 times (as many times as transitions, which comes from T2 through the first slot).
  • And finally, when proto1 is set to 1, the first condition is no longer satisfied so that the workflow stops.

Designing a Mole task

OpenMOLE enables to define a Mole inside a Task, and thus to define multi-scale Moles. It can be convenient to nest Moles or to delegate part of an exploration on distributed environments. Let us imagine for instance a huge exploration generating millions of tasks. The memory size to be allocated locally grows up dramatically. A good trick is to split the exploration, and to delegate a part of the exploration to remote environments.

In the following example, 2 exploration tasks are defined: one in the main mole and an other in a MoleTask:

import org.openmole.core.implementation.data.*
import org.openmole.plugin.domain.range.*
import org.openmole.core.implementation.sampling.*
import org.openmole.plugin.sampling.complete.*
import org.openmole.plugin.task.groovy.*
import org.openmole.core.implementation.transition.*
import org.openmole.core.implementation.capsule.*
import org.openmole.core.implementation.task.*
import org.openmole.core.implementation.data.*
import org.openmole.core.implementation.mole.*

proto1 = new Prototype("proto1", Integer)
proto2 = new Prototype("proto2", Integer)
proto3 = new Prototype("proto3", Integer)
proto4 = new Prototype("proto4", Integer)

dataSet1 = new DataSet(proto1,proto2)
dataSet2 = new DataSet(proto3,proto4)

sampling1 = new CompleteSampling(new Factor(proto1, new IntegerRange("0","2","1")),
                         new Factor(proto2, new IntegerRange("3","4","1")))


sampling2 = new CompleteSampling(new Factor(proto3, new IntegerRange("5","6","1")),
                         new Factor(proto4, new IntegerRange("7","9","1")))


exploT1 = new ExplorationTask("explorationSpaceTask1",sampling1)
explorationCapsule1 = new ExplorationCapsule(exploT1)

exploT2 = new ExplorationTask("explorationSpaceTask2",sampling2)
exploT2.addInput(dataSet1)
exploT2.addOutput(dataSet1)
explorationCapsule2 = new ExplorationCapsule(exploT2)

t2 = new GroovyTask("t2")
t2.addInput(dataSet1)
t2.addInput(dataSet2)
t2.setCode ("println 'proto1: '+proto1+' | proto2: '+proto2+' | proto3: '+proto3 +' | proto4: '+proto4")
t2Capsule = new Capsule(t2)

new ExplorationTransition(explorationCapsule2,t2Capsule)
moleTask = new MoleTask("moleTask",new Mole(explorationCapsule2))
moleTask.addInput(dataSet1)
moleCapsule = new Capsule(moleTask)

new ExplorationTransition(explorationCapsule1,moleCapsule)

ex = new MoleExecution(new Mole(explorationCapsule1))
ex.start()

Let us note the use of a new convenient concept: the DataSet. It simply enables to group prototypes, which navigate together through the workflow. It can be added to a task using the method addInput, that is to say the same method name as for the Prototype.
The output, giving thus a complete exploration of the space:

proto1: 0 | proto2: 3 | proto3: 5 | proto4: 7
proto1: 0 | proto2: 3 | proto3: 6 | proto4: 7
proto1: 0 | proto2: 3 | proto3: 5 | proto4: 8
proto1: 0 | proto2: 3 | proto3: 6 | proto4: 8
proto1: 0 | proto2: 3 | proto3: 5 | proto4: 9
proto1: 0 | proto2: 3 | proto3: 6 | proto4: 9
proto1: 1 | proto2: 3 | proto3: 5 | proto4: 7
proto1: 1 | proto2: 3 | proto3: 6 | proto4: 7
proto1: 1 | proto2: 3 | proto3: 5 | proto4: 8
proto1: 1 | proto2: 3 | proto3: 6 | proto4: 8
proto1: 1 | proto2: 3 | proto3: 5 | proto4: 9
proto1: 1 | proto2: 3 | proto3: 6 | proto4: 9
proto1: 2 | proto2: 3 | proto3: 5 | proto4: 7
proto1: 2 | proto2: 3 | proto3: 6 | proto4: 7
proto1: 2 | proto2: 3 | proto3: 5 | proto4: 8
proto1: 2 | proto2: 3 | proto3: 6 | proto4: 8
proto1: 2 | proto2: 3 | proto3: 5 | proto4: 9
proto1: 0 | proto2: 4 | proto3: 5 | proto4: 7
proto1: 2 | proto2: 3 | proto3: 6 | proto4: 9
proto1: 0 | proto2: 4 | proto3: 6 | proto4: 7
proto1: 0 | proto2: 4 | proto3: 5 | proto4: 8
proto1: 0 | proto2: 4 | proto3: 6 | proto4: 8
proto1: 0 | proto2: 4 | proto3: 5 | proto4: 9
proto1: 0 | proto2: 4 | proto3: 6 | proto4: 9
proto1: 2 | proto2: 4 | proto3: 5 | proto4: 7
proto1: 2 | proto2: 4 | proto3: 6 | proto4: 7
proto1: 2 | proto2: 4 | proto3: 5 | proto4: 8
proto1: 2 | proto2: 4 | proto3: 6 | proto4: 8
proto1: 2 | proto2: 4 | proto3: 5 | proto4: 9
proto1: 2 | proto2: 4 | proto3: 6 | proto4: 9
proto1: 1 | proto2: 4 | proto3: 5 | proto4: 7
proto1: 1 | proto2: 4 | proto3: 6 | proto4: 7
proto1: 1 | proto2: 4 | proto3: 5 | proto4: 8
proto1: 1 | proto2: 4 | proto3: 6 | proto4: 8
proto1: 1 | proto2: 4 | proto3: 5 | proto4: 9
proto1: 1 | proto2: 4 | proto3: 6 | proto4: 9

logo cemagref

logo iscpif

logo lifegrid

logo region auvergne

logo patres project