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









