Strainer capsule

In a general manner you are expected to specify the inputs and outputs of each task. Capsules' strainer mode transmits all the variables arriving through the input transition as if they were inputs and ouptuts of the task.

For instance, variable i is transmitted to the hook without adding it explicitly in input and output of the task t2, in the following workflow:
val i = Val[Int]
val j = Val[Int]

val t1 = ScalaTask("val i = 42") set (outputs += i)

val t2 = ScalaTask("val j = i * 2") set (outputs += j)
val c2 = Capsule(t2, strain = true)

t1 -- (c2 hook ToStringHook(i, j))

This workflow displays {i=42, j=84}

Master/Slave workflows

OpenMOLE provides a very flexible workflow formalism. It even makes it possible to design workflows with a part that mimics a master / slave (also known as Map/Reduce) distribution scheme. This schemes involves many slave jobs computing partial results and a master gathering the whole result.

You can think of a steady state genetic algorithm of instance as an typical use case. This use case would see a global solution population maintained and a bunch of slave workers computing fitnesses in a distributed manner. Each time a worker ends, its result is used to update the global population and a new worker is launched. To achieve such a distribution scheme, one should use the Master Capsule along with an end-exploration transition.

The MasterCapsule is a special capsule that preserve a state from one execution to another. An execution of the MasterCapsule modifies this state and the next execution gets the state that has been modified last. To ensure soundness of the state only, the MasterCapsules are always executed locally and multiple executions of a given MasterCapsule are carried sequentially.

By using the MasterCapsule, a workflow can evolve a global archive, and compute new inputs to be evaluated from this archive. Even if it is not required, a MasterCapsule is generally executed in an exploration, in order to have several workers computing concurrently. This distribution scheme suggests that all the workers should be killed when the global archive has reached a suitable state. This is the aim of the end-exploration transition, which is noted >|.

The following script orchestrates a master slave distribution scheme for a dummy problem. OpenMOLE launches 10 workers. Along these workers, the MasterCapsule hosts the selection task. The selection task stores the numbers that are multiple of 3 and relaunches a worker for the next value of i. The second argument of the MasterCapsule constructor is the data that should be persisted from one execution of the MasterCapsule to another.
val i = Val[Int]
val archive = Val[Array[Int]]

val exploration = ExplorationTask(i in (0 until 10))

val model = ScalaTask("i = i + 7") set (inputs += i, outputs += i)

val modelCapsule = Capsule(model)
val modelSlot1 = Slot(modelCapsule)
val modelSlot2 = Slot(modelCapsule)

val select =
  ScalaTask("archive = archive ++ (if(i % 3 == 0) Seq(i) else Seq())") set (
    (inputs, outputs) += (i, archive),
    archive := Array[Int]()

val selectCaps = MasterCapsule(select, archive)

val finalTask = EmptyTask()

val displayHook = ToStringHook()

val skel = exploration -< modelSlot1 -- (selectCaps hook displayHook)
val loop = selectCaps -- modelSlot2
val terminate = selectCaps >| (Capsule(finalTask, strain = true) hook displayHook, "archive.size >= 10")

skel & loop & terminate