Flow diagrams to Petri nets

This document describes how the FD2PN component has been reused for several workflow languages. This component features a reusable transformation from a Workflow concept to a Petri net, which is able to deal with several of the patterns defined in the Workflow patterns catalog.

The menu provides links to the different artefacts of the case study.

Code for Bentō:
Template:
Concepts:
Meta-models:

Sequential function chart (SFC) / Grafcet

Sequential function chart (SFC) is a graphical programming language used for programmable logic controllers (PLCs). It is based on Grafcet, whose semantics is based on Petri nets, and supported by the IEC 61131-3 standard

Meta-model

The following diagram is an excerpt with the relevant elements of the SFC/Grafcet meta-model. The complete diagrams are also available in SVG and PNG formats.

The actual Ecore meta-model has been extracted from the XML Schema provided by the PLC Open initiative (available here). Models conforming to the XML format can be created using the Beremiz tool.

Binding

This binding is highly influenced by the fact that the meta-model basically represents the tree structure of an XML document, and there is little inheritance and no explicit references.

All SFC elements that represent a node in the workflow must be mapped the Node class in the concept (line 6), because there is no common superclass in SFC. In SFC both steps and transitions have the task semantics, and edges are represented by Connection elements (lines 13-15). The "out" references in the concept cannot be mapped to any reference in SFC, because the target element of SFC node is identified by the "localId" attribute. Hence, it must be resolved by explicitly locating the Connection object with the corresponding identifier.

binding sfc {  
	concept   FD   : "platform:/resource/bento.examples.flow_diagrams.petrinets/metamodels/flow_concept.ecore"
	metamodel SFC  : "platform:/resource/bento.examples.flow_diagrams.petrinets/bindings/sfc2pn/tc60201.ecore"
	
	class FlowDiagram to SFCType1	
	class Node        to StepType, TransitionType1, -- Important to add here every "virtual subclass"
	                     SelectionDivergenceType, SelectionConvergenceType, 
	                     SimultaneousDivergenceType, SimultaneousConvergenceType 
	
	-- Edges are not transitions (which has a different semantics), 
	-- but Connection/ConnectionPointIn which is an structural concept to link "SFC nodes" 
	-- (which include transitions)
	class FlowEdge to Connection
	
	class Task        to StepType, TransitionType1 
	class FinalTask   to NONE 
       
	class ExclusiveChoice to SelectionDivergenceType
	class SimpleMerge     to SelectionConvergenceType
	                                        
	class Synchronization   to SimultaneousConvergenceType
	class ParallelSplit     to SimultaneousDivergenceType

	class MultiChoice     to NONE	
	
	feature FlowDiagram.nodes is allNodes
	feature FlowDiagram.edges is transition	

	feature FlowEdge."in" = SFC!SFCType1.allInstances()->first().allNodes->any(n | n.localId = self.refLocalId) 
	feature FlowEdge.out  is parent

	feature Node[StepType]."in" = self.connectionPointIn.connection 
	feature Node[StepType].out  = SFC!Connection.allInstances()->select(c | c.refLocalId = self.localId)

	feature Node[TransitionType1]."in" = self.connectionPointIn.connection 
	feature Node[TransitionType1].out  = SFC!Connection.allInstances()->select(c | c.refLocalId = self.localId)

	feature Node[SelectionDivergenceType]."in" = self.connectionPointIn.connection 
	feature Node[SelectionDivergenceType].out  = SFC!Connection.allInstances()->select(c | c.refLocalId = self.localId)

	feature Node[SelectionConvergenceType]."in" = self.connectionPointIn.connection 
	feature Node[SelectionConvergenceType].out  = SFC!Connection.allInstances()->select(c | c.refLocalId = self.localId)

	feature Node[SimultaneousDivergenceType]."in" = self.connectionPointIn.connection 
	feature Node[SimultaneousDivergenceType].out  = SFC!Connection.allInstances()->select(c | c.refLocalId = self.localId)

	feature Node[SimultaneousConvergenceType]."in" = self.connectionPointIn.connection 
	feature Node[SimultaneousConvergenceType].out  = SFC!Connection.allInstances()->select(c | c.refLocalId = self.localId)


	feature Task[StepType].isInitial is initialStep
	feature Task[TransitionType1].isInitial   = false   	

	feature FinalTask.isTerminating = false 

	
	helper Connection.parent : OclAny = self.refImmediateComposite().refImmediateComposite()
	
	helper SFCType1.allNodes : OclAny = self.step.union(self.transition).
	                                 union(self.selectionDivergence).
	                                 union(self.selectionConvergence).
	                                 union(self.simultaneousDivergence).
	                                 union(self.simultaneousConvergence)	                              
}