Further Extending ItemBlocks

Since SMTK 23.01, there have been requests to further expand the ItemBlock capabilities which include the following:

New Types of Blocks

Discrete Blocks

There are times when you want to have multiple Items to “share” the same set of Discrete Information. For example consider the following:

  <ChildrenDefinitions>
    <Double Name="value" Label="Value"/>
    <Double Name="temp" Label="Reference Temp"/>
  </ChildrenDefinitions>
  <DiscreteInfo DefaultIndex="0">
    <Structure>
      <Value>Normal</Value>
      <Items>
        <Item>value</Item>
      </Items>
    </Structure>
    <Structure>
      <Value>Boussinesq</Value>
      <Items>
        <Item>value</Item>
        <Item>temp</Item>
      </Items>
    </Structure>
  </DiscreteInfo>

As you can see these sections can be somewhat complicated and forcing a template designer to copy these sections could be tedious. Note that it has been discovered that the current Item Block mechanism can be used in the ChildrenDefinitions element; however, since the ChildrenDefinitions and DiscreteInfo elements must be compatible it would make more sense to support a Block that includes both sections.

What I propose is to add a Discrete Block section that is similar to Items Block Section.

<DescreteBlocks Namespace="globals1">
  <Block Name="B1" Export="true">
    <ChildrenDefinitions>
      <Double Name="value" Label="Value"/>
      <Double Name="temp" Label="Reference Temp"/>
    </ChildrenDefinitions>
    <DiscreteInfo DefaultIndex="0">
      <Structure>
        <Value>Normal</Value>
        <Items>
          <Item>value</Item>
        </Items>
      </Structure>
      <Structure>
        <Value>Boussinesq</Value>
        <Items>
          <Item>value</Item>
          <Item>temp</Item>
        </Items>
      </Structure>
    </DiscreteInfo>
  </Block>
</DescreteBlocks>

To use the block you would refer to it in the DiscreteInfo element:

<ItemDefinitions>
  <String Name="Density">
    <DiscreteInfo Block="B1" Namespace="globals1\>
  </String>
</ItemDefinitions>

Association Blocks

Similarly there are times when you want two Attribute Definitions to share the same association rule. Currently this is done using the inheritance mechanism. By supporting Association Blocks, it would now be possible for 2 unrelated Definitions For example consider the following:

<Definitions>
   <AttDef Type="BoundaryCondition" Label="BoundaryCondition" Abstract="true">
      <AssociationsDef  Extensible="true">
        <Accepts>
          <Resource Name="smtk::model::Resource" Filter="face" />
        </Accepts>
      </AssociationsDef>
   </AttDef>
   <AttDef Type="MeshFaceSize" BaseType="MeshingParameters">
      <AssociationsDef  Extensible="true">
        <Accepts>
          <Resource Name="smtk::model::Resource" Filter="face" />
        </Accepts>
      </AssociationsDef>
    </AttDef>
</Definitions>

Note that currently it is not possible for the template designer to enforce BoundaryCondition Attributes and MeshFaceSize Attributes to follow the same association rule since they do not share a common BaseType. What I propose is the following:

<AssociationBlocks Namespace="globals1">
  <Block Name="B2" Export="true" Extensible="true">
    <Accepts>
      <Resource Name="smtk::model::Resource" Filter="face" />
    </Accepts>
  </Block>
</AssociationBlocks>

<Definitions>
   <AttDef Type="BoundaryCondition" Label="BoundaryCondition" Abstract="true">
      <AssociationsDef  Block="B2" Namespace="globals1"/>
   </AttDef>
   <AttDef Type="MeshFaceSize" BaseType="MeshingParameters">
      <AssociationsDef  Block="B2" Namespace="globals1"/>
    </AttDef>
</Definitions>

In this proposed design the Block XML element would include the XML attributes associated with the AssociationDef XML Element.

Category Blocks

You may also want to enforce a similar relationship with respects to category information. For example consider the following:

<Definitions>
   <AttDef Type="Foo" >
      <CategoryInfo InheritanceMode="LocalOnly" Combination="And">
        <Include Combination="Or">
          <Cat>CFD</Cat>
        </Include>
      </CategoryInfo>
   </AttDef>
   <AttDef Type="Bar" >
      <CategoryInfo InheritanceMode="LocalOnly" Combination="And">
        <Include Combination="Or">
          <Cat>CFD</Cat>
        </Include>
      </CategoryInfo>
    </AttDef>
</Definitions>

If we also support CategoryBlocks we could reduce the above example to this:

<CategoryBlocks Namespace="globals1">
  <Block Name="B3" Export="true" InheritanceMode="LocalOnly" Combination="And">
    <Accepts>
      <Resource Name="smtk::model::Resource" Filter="face" />
    </Accepts>
  </Block>
</CategoryBlocks >

<Definitions>
   <AttDef Type="Foo" >
      <CategoryInfo Block="B3" Namespace="globals1"/>
   </AttDef>
   <AttDef Type="Bar" >
      <CategoryInfo Block="B3" Namespace="globals1"/>
    </AttDef>
</Definitions>

Alternative Design

The above enhancements would require copying the code currently used for Item Blocks as well as modifying the code that processes Discrete, Association, and Category Information. Alternatively, we could try to make the current Block mechanism more flexible by refactoring parts of the XML Parsing code. The diagram below depicts how XML Nodes that represent Attribute Definitions get processed.


When an Attribute Definition Node is processed, first all of the XML relevant attributes are pulled from the nodes. By relevant, I mean that the parser searches explicitly for specific attributes instead of iterating over all of the XML attributes. Similarly, the parser would then explicitly search for certain types of XML children elements (such as Category Info, Association Info, etc…).

When the ItemDefinitions element is found - that element is passed to a helper class that processes all of the element’s children. If a ** Block** element is encountered, it finds/creates the corresponding XML node and recursively calls the helper class method. For any other type of XML Element, the helper creates the corresponding SMTK Item Definition and then passes it, and the XML Element that created it, to the appropriate method of the parser.

If (as in the case above) the node is a ValueItem Definition, the processing is very similar to that of an Attribute Definition:

  1. Explicitly find the XML attributes the parser cares about
  2. Explicitly search for XML children elements that the parser cares about
  3. Use the helper class to process all of the XML Elements contained in the ChildrenDefinitions XML element if one exists.

If we restructure the parser methods so that we no longer explicitly look for key XML elements but instead processed all of the children elements, then we could refactor the parsing code to look more like this:

In this approach - the expected contents of a Block would be dictated by the context in which it is being instantiated. If it is being used as a child of an Attribute Definition XML element, then its contents should be valid w/r to an Attribute Definition element. Therefore it can contain any of the following Elements:

  • BriefDescription
  • DetailedDescription
  • AssociationRule
  • DissociationRule
  • CategoryInfo
  • ItemDefinitions
  • Exclusions
  • Prerequisites
  • NotApplicableColor
  • DefaultColor

The same approach could be done for all Item Definition processing methods.

The above examples would then be represented as follows:

<Blocks Namespace="globals1">
  <Block Name="B1" Export="true">
    <ChildrenDefinitions>
      <Double Name="value" Label="Value"/>
      <Double Name="temp" Label="Reference Temp"/>
    </ChildrenDefinitions>
    <DiscreteInfo DefaultIndex="0">
      <Structure>
        <Value>Normal</Value>
        <Items>
          <Item>value</Item>
        </Items>
      </Structure>
      <Structure>
        <Value>Boussinesq</Value>
        <Items>
          <Item>value</Item>
          <Item>temp</Item>
        </Items>
      </Structure>
    </DiscreteInfo>
  </Block>

  <Block Name="B2" Export="true">
    <AssociationsDef  Extensible="true">
      <Accepts>
        <Resource Name="smtk::model::Resource" Filter="face" />
      </Accepts>
    </AssociationsDef>
  </Block>

  <Block Name="B3" Export="true">
    <CategoryInfo InheritanceMode="LocalOnly" Combination="And">
      <Accepts>
        <Resource Name="smtk::model::Resource" Filter="face" />
      </Accepts>
    </CategoryInfo>
  </Block>
</Blocks>

<Definitions>
   <AttDef Type="BoundaryCondition" Label="BoundaryCondition" Abstract="true">
      <Block="B2" Namespace="globals1"/>
      <ItemDefinitions>
        <String Name="Density">
          <Block="B1" Namespace="globals1\>
        </String>
      </ItemDefinitions>
   </AttDef>
   <AttDef Type="MeshFaceSize" BaseType="MeshingParameters">
      <Block="B2" Namespace="globals1"/>
    </AttDef>

   <AttDef Type="Foo" >
      <Block="B3" Namespace="globals1"/>
   </AttDef>
   <AttDef Type="Bar" >
      <Block="B3" Namespace="globals1"/>
    </AttDef>
</Definitions>

@johnt @justin.2.wilson @rohith @Aaron @mledesma - Comments welcome!

ALOT to take in here, for sure. I definitely have not fully digested it all, but I am a strong +1 for the “alternative design” that uses the generic <Blocks> and <Block> element types for the new features. I am tempted to also suggest renaming <Block> to <Template> but that might cause confusion (“isn’t the whole file a template?”)

We call SBT files template files (that’s what the T stands for), but I think we could also still have Template sections which would be closer to the C++ concept of templates. In this current form I would be a bit hesitant to changing the name to Template since the functionality proposed here does not add any parameterization but in a related Discourse topic I’m proposing we add such functionality.