Expanding Categories to Support Exclusion

Current Design

Categories assigned to Attribute and Item Definitions follow one of the following patterns

  • (a | b | c) - passes if the list of filtering categories contain a, b or c. Done using the Any option.
  • (a & b & c) - passes if the list of filtering categories contain a, b and c. Done using the All option.

Current Issue

What if we wanted to model exclusion? For example lets assume that we have a set of information that is required when doing a Heat Transfer(HT) simulation and another set that is required to do a CFD simulation. Now assume that when we are doing a coupled HT and CFD problem, there is not only information that needs to be added (this information is not represented by simply unioning HT and CFD categories) as well as some information that is not applicable when both categories are on.

We can do the first part easily by specifying (HT & CFD); however, the second part is more of an issue. There is no way of saying (HT & !CFD) - meaning this information is applicable only when HT is specified and CFD is not.

This can get even more complicated - say we have 3 categories (a, b, c) and we have a set of information that should be displayed if all three are present and another set when b and c are not both present. Logically this would like the following:

In order to be able to model these types of relationships we need to add an exclusion component to the Categories::Sets class with the same Any and All options. The above also shows and example of having information that is applicable if c is present but a and b are not.

API Changes:

Current API in Categories::Set

    ///\brief Set/Get the CombinationMode associated with the instance.
    Set::CombinationMode mode() const;
    void setMode(const Set::CombinationMode& newMode);
    ///@}
    ///\brief Return the set of category names associated with the instance.
    const std::set<std::string>& categoryNames() const;
    ///\brief Set the mode and category names of the instance.
    void set(const std::set<std::string>& values, Set::CombinationMode mode);
    ///\brief Add a category name to the instance.
    void insert(const std::string& val);
    ///\brief Remove a category name form the instance.
    void erase(const std::string& val) ;
    ///\brief Remove all names from the instance.
    void reset();
    ///\brief Returns true if the instance's category names is empty.
    bool empty() const;
    ///\brief Returns the number of category names in the instance.
    std::size_t size() const;

Proposed API in Categories::Set

    ///\brief Set/Get the CombinationMode associated with the instance.
    Set::CombinationMode mode() const;
    void setMode(const Set::CombinationMode& newMode);
    Set::CombinationMode exclusionMode() const;
    void setExclusionMode(const Set::CombinationMode& newMode);
    ///@}
    ///\brief Return the set of category names associated with the instance.
    const std::set<std::string>& categoryNames() const;
    ///\brief Return the set of excluded category names associated with the instance.
    const std::set<std::string>& exclusionNames() const;
    ///\brief Set the mode and category names of the instance.
    void set(const std::set<std::string>& values, Set::CombinationMode mode);
    ///\brief Set the exclusion mode and names of the instance.
    void setExclusions(const std::set<std::string>& values, Set::CombinationMode mode);
    ///\brief Add a category name to the instance.
    void insert(const std::string& val);
    ///\brief Remove a category name form the instance.
    void erase(const std::string& val) ;
    ///\brief Add an exclusion name to the instance.
    void insertExclusion(const std::string& val);
    ///\brief Remove an exclusion name form the instance.
    void eraseExclusion(const std::string& val) ;
    ///\brief reset the instance.
    void reset();
    ///\brief Returns true if the instance's category names is empty.
    bool empty() const;
    ///\brief Returns the number of category names in the instance.
    std::size_t size() const;
    ///\brief Returns the number of excluded names in the instance.
    std::size_t exclusionSize() const;

XML File Format Changes

Current Format

Here is current Attribute Definition representing in XML. Note that Item Definitions are similar with respects to Categories.

    <AttDef Type="physics" Label="Physics" BaseType="" CategoryCheckMode="Any">
      <Categories>
        <Cat>Truchas</Cat>
      </Categories>
   </AttDef>

I plan on supporting the above format in addition to either of the proposed formats to support exclusion categories.

Proposal 1 Expand on the current format

In this case, I’ve simply added a new xml element to the Definition

    <AttDef Type="physics" Label="Physics" BaseType="" CategoryCheckMode="Any" ExclusionCheckMode="All">
      <Categories>
        <Cat>Truchas</Cat>
      </Categories>
      <ExcludedCategories>
        <Cat>Foo</Cat>
      </ExcludedCategories >
   </AttDef>

Proposal 2 Refactor Category Information

In this case, I’ve moved all category related information into its own XML Element .

    <AttDef Type="physics" Label="Physics" BaseType="" >
      <CategoryInfo Combination="All">
        <Include Combination="Any">
           <Cat>Truchas</Cat>
        </Include>
       <Exclude Combination="All">
          <Cat>Foo</Cat>
       </Exclude>
     </CategoryInfo>
   </AttDef>

Final Implementation

See unitExclusionCategories test for an example of using this new functionality.

Turning off Category Filtering

With these new changes we can now model information that is relevant regardless of which categories are active. For example Analysis Configuration Attributes which are used to indicate which categories should be active, should themselves not be filtered. To do this, simple set the Item or Attribute’s local categories to have a combinationMode set to ANY. Since the inclusion and exclusion sets are initially empty which means they evaluate to false and true respectively, the passes method will always return true.

attribute::Categories::Set API Changes

  • New API
    • combinationMode()/setCombinationMode(…) - Get/Set the how the sets of included and excluded categories are combined
    • inclusionMode()/setInclusionMode(…) - Get/Set the CombinationMode associated with the included categories.
    • exclusionMode()/setExclusionMode(…) - Get/Set the CombinationMode associated with the excluded categories.
    • includedCategoryNames() - Return the set of category names associated with the inclusion set.
    • excludedCategoryNames() - Return the set of category names associated with the exclusion set.
    • setInclusions(…) - Set the mode and category names of the inclusion set.
    • setExclusions(…) - Set the mode and category names of the exclusion set.
    • insertInclusion(…)/eraseInclusion(…) - add/remove category name to/from the inclusion set.
    • insertExclusion(…)/eraseExclusion(…) - add/remove category name to/from the exclusion set.
    • inclusionSize() - Returns the number of category names in the inclusion set.
    • exclusionSize() - Returns the number of category names in the exclusion set.
  • Deprecated API
    • mode() -> inclusionMode()
    • setMode(…) -> setInclusionMode(…)
    • categoryNames() -> includedCategoryNames()
    • set(…) -> setInclusions(…)
    • insert(…) ->insertInclusion(…)
    • erase(…) -> eraseInclusion(…)
    • size() -> inclusionSize()

Changes to XML/JSON Formats

In the past the category names where added to their own XML element or JSON structure inside of the Attribute/Item Definition Block or inside of the ValueItem Enum Structure, but other aspects were stored else where. Though this format is still supported for reading, the new format groups all of the Category Information together. Here is an example of an Item Definition:

<String Name="s0" Label="s0">
  <CategoryInfo Inherit="true" Combination="All">
    <Include Combination="All">
      <Cat>a</Cat>
       <Cat>b</Cat>
    </Include>
    <Exclude Combination="All">
      <Cat>c</Cat>
      <Cat>d</Cat>
    </Exclude>
  </CategoryInfo>
</String>

This format is the same for Attribute Definitions and Enums with the exception of the Inherit attribute. The following is the JSON equivalent:

 "CategoryInfo": {
   "Combination": "All",
   "ExcludeCategories": [
     "c",
     "d"
   ],
   "ExclusionCombination": "All",
   "IncludeCategories": [
     "a",
     "b"
   ],
   "InclusionCombination": "All",
   "Inherit": true
 }

@chart3388 @amuhsin @johnt @Neil_Carlson - FYI

API is good with me. I am presuming that

  • reset() clears both category and exclude-category sets.
  • empty() implies that both category and exclude-category sets are empty.

As for the XML format, I prefer Proposal 1 with some minor/candidate mods:

  • I have a personal preference for <ExcludeCategories> (with only 1 “d”) but I’ll defer to the crowd opinion on this.
  • I would like to add a CombinationMode attribute to the <Categories> and <ExcludeCategories> elements, and deprecate the current CategoryCheckMode attribute.
1 Like