3.9. Interpretation of encapsulation elements

  1. For the purposes of this specification, there SHALL be a conceptual “encapsulation digraph” in which there is exactly one node for every component in the CellML model.

  2. If a component_ref element appears as a child of another component_ref element, then there SHALL be an arc in the encapsulation digraph, and that arc SHALL be from the node corresponding to the component referenced by the parent component_ref element, and to the node corresponding to the component referenced by the child component_ref element.

See more

You can think of an encapsulation structure as a tree. The model is the tree’s trunk, and each component at the top-level of the model is a branch. Subsequent generations of branches can stem from any component, but no two branches can recombine or belong to more than one parent, as this would create a loop. Any component not listed inside the encapsulation is a top-level component (a branch off the trunk).

An encapsulation hierarchy is specified using a single encapsulation element, and any number of generations of component_ref children. Where no encapsulation element is present, all component elements have the same level; they branch off the model-trunk.

Some examples of valid and invalid encapsulation structures are shown below.

<!--  Valid encapsulation structure.  This will give the arrangement of:
        - grandad
            - father
                - child
            - aunt
        - orphan
  Because the component named "orphan" is not included in the encapsulation
  it will stay at the top level of the model. -->
<model name="I_am_a_valid_model">
  <component name="grandad"/>
  <component name="aunt"/>
  <component name="father"/>
  <component name="child"/>
  <component name="orphan">
  <encapsulation>
    <component_ref component="grandad">
      <component_ref component="aunt"/>
      <component_ref component="father">
        <component_ref component="child"/>
      </component_ref>
    </component_ref>
  </encapsulation>
</model>

<!-- Invalid: More than one encapsulation is not permitted. -->
<model name="too_many_encapsulations">
  <component name="parent1"/>
  <component name="child1"/>
  <component name="parent2"/>
  <component name="child2"/>
  <encapsulation>
    <component_ref component="parent1">
      <component_ref component="child2"/>
    </component_ref>
  </encapsulation>
  <encapsulation>
    <component_ref component="parent2">
      <component_ref component="child2"/>
    </component_ref>
  </encapsulation>
</model>

<!-- Invalid: A component cannot appear more than once in an encapsulation. -->
<model name="duplicated_component_ref">
  <component name="parent"/>
  <component name="child"/>
  <encapsulation>
    <component_ref component="parent">
      <component_ref component="child">
        <component_ref component="parent"/>
      </component_ref>
    </component_ref>
  </encapsulation>
</model>

<!-- Valid, but redundant: An encapsulation can be empty, but this is the default
      condition so its inclusion alters nothing. -->
<model name="empty_encapsulation">
  <component name="parent"/>
  <component name="child"/>
  <encapsulation>
  </encapsulation>
</model>

<!-- Valid, but redundant: An encapsulation must have a minimum of two levels of children
      to affect the model's structure.  This still represents the default condition. -->
<model name="duplicated_component_ref">
  <component name="parent"/>
  <component name="child"/>
  <encapsulation>
    <component_ref component="parent">
      <!-- There has to be a child here or the parent is not a parent. -->
    </component_ref>
  </encapsulation>
</model>
  1. The “encapsulated set” for a component A SHALL be the set of all components B such that there exists an arc in the encapsulation digraph from the node corresponding to A to the node corresponding to B.

  1. The “encapsulation parent” for a component A SHALL be the component corresponding to the node which is the parent node in the encapsulation digraph of the node corresponding to A. A component SHALL NOT appear as child of more than one encapsulation parent.

  1. The “sibling set” for a component A SHALL be the set of all components which have the same encapsulation parent as A, or in the case that A has no encapsulation parent, SHALL be the set of all components which do not have an encapsulation parent.

  1. The “hidden set” for a component A SHALL be the set of all components B where component B is not in the encapsulated set for component A, and component B is not the encapsulation parent of component A, and component B is not in the sibling set for component A.

See more

In the informative block above we used the analogy of a tree to describe the encapsulation structure, but the language around it is closer to a family tree in which there are only single parents allowed. With this in mind, the points above become clear.

  • 3.9.3 defines the “encapsulation set” of a component as its direct component children.

  • 3.9.4 makes clear that there can only be single parents in this family tree.

  • 3.9.5 defines siblings as those component elements which share a parent, be that parent a component element or the model element itself.

  • 3.9.6 defines the “hidden set” of any component as those other component elements which are neither the parent, the children, nor the siblings of that current component element.

These distinctions become important when considering the kind of connection elements which may be formed, and in determining the interface_type attribute values which are available to a component’s variable children.

The example below illustrates the extended family tree from the 1980s TV show, The Beverly Hillbillies.

model: TheBeverlyHillbillies
  ├─ component: GrannyMoses
  ├─ component: MissJane
  └─ component: ClampettFamily
      ├─ component: LukeClampett
      │   ├─ component: MyrtleClampett
      │   └─ component: JedClampett
      │       └─ component: EllyMayClampett
      └─ component: AmosClampett
          └─ component: PearlBodine
              ├─ component: JethroBodine
              └─ component: JethrineBodine

See CellML syntax

<model name="TheBeverlyHillbillies">
  <!-- Note that the first two components here are not listed inside the
       encapsulation. They are, by default, siblings of each other,
       as well as of the root component (ClampettFamily) of the
       encapsulation structure. -->
  <component name="GrannyMoses" />
  <component name="MissJane" />
  <component name="ClampettFamily" />
  <component name="LukeClampett" />
  <component name="AmosClampett" />
  <component name="MyrtleClampett" />
  <component name="JedClampett" />
  <component name="EllyMayClampett" />
  <component name="PearlBodine" />
  <component name="JethroBodine" />
  <component name="JethrineBodine" />

  <encapsulation>
    <component_ref component="ClampettFamily">
      <component_ref component="LukeClampett">
        <component_ref component="MyrtleClampett">
        </component_ref>
        <component_ref component="JedClampett">
          <component_ref component="EllyMayClampett"/>
        </component_ref>
      </component_ref>
      <component_ref component="AmosClampett">
        <component_ref component="PearlBodine">
          <component_ref component="JethroBodine"/>
          <component_ref component="JethrineBodine"/>
        </component_ref>
      </component_ref>
  </encapsulation>
</model>

In this example, we can see that the encapsulation set (or direct children) of component PearlBodine are the twins JethroBodine and JethrineBodine. Similarly, LukeClampett is the parent of MyrtleClampett and JedClampett. Several sets of siblings are fairly easy to spot:

  • JethroBodine and JethrineBodine,

  • LukeClampett and AmosClampett, and

  • MyrtleClampett and JedClampett.

Other siblings that are not as clear at first glance are GrannyMoses, MissJane, and the placeholder ClampettFamily, by virtue of their common parent, TheBeverlyHillbillies model itself.

See more

Before two variable elements can be connected or mapped to one another, two set of rules must be followed. The first rule is that the variables’ parent component elements must not be hidden from one another (as stated in 3.9.7), and the second (found in 3.10.9-10) is that the interface_type attributes of the variables must not exclude their connection either.

Understanding hidden sets and connections

It’s easier to define hidden components by defining those which are not hidden first. Basically, one degree of separation is all that is “seen” by any component. This means that parent components can see their children, and children their parents. Sibling components (including those who are top-level children of the model element) are visible to one another as well. Components in any other relationships are too distant to be visible, and are therefore hidden from each other.

Reusing the same example as earlier, we can see that:

  • LukeClampett is hidden from EllyMayClampett (grandfather/grandchild)

  • AmosClampett is hidden from MyrtleClampett (uncle/niece)

  • PearlBodine is hidden from JedClampett (cousins)

  • GrannyMoses is hidden from LukeClampett (great-aunt/great-nephew)

model: TheBeverlyHillbillies
  ├─ component: GrannyMoses
  ├─ component: MissJane
  └─ component: ClampettFamily
      ├─ component: LukeClampett
      │   ├─ component: MyrtleClampett
      │   └─ component: JedClampett
      │       └─ component: EllyMayClampett
      └─ component: AmosClampett
          └─ component: PearlBodine
              ├─ component: JethroBodine
              └─ component: JethrineBodine
<!-- None of the following connections are possible as their
      components are hidden from one another. -->

<!-- Grandfather and grandchild. -->
<connection component_1="LukeClampett" component_2="EllyMayClampett" />

<!-- Uncle and niece. -->
<connection component_1="AmosClampett" component_2="MyrtleClampett" />

<!-- Cousin and cousin. -->
<connection component_1="PearlBodine" component_2="JedClampett" />

<!-- Great-aunt and great-nephew. -->
<connection component_1="GrannyMoses" component_2="LukeClampett" />

The second rule above addresses the restrictions around which variable elements are able to access one another. This is a little more complicated, and explained in more detail in the informative block in 3.10 Interpretation of map_variables elements.