View the contents of a Model

About viewing models

All CellML entities exist in a hierarchical structure as shown below. In some circumstances additional links are made between items (equivalent variables, for example), but on the whole it follows a basic tree structure.

Model
  │
  ├─ Units item(s)
  │   └─ Unit item(s)
  │
  └─ Component item(s)
      │
      ├─ Variable item(s)
      │
      ├─ Reset item(s)
      │   ├─ ResetValue item
      │   └─ TestValue item
      │
      ├─ Math item
      │
      └─ Child Component item(s)
           │
           └─ Grandchild Component item(s)

Within the structure each item has two parts:

  • A set of attributes specific to itself. Some of these attribute exist for many items (for example, the name attribute), and others are specific to the item type (for example, the initialValue attribute on a Variable item).

  • A set of collections which this - the parent item - curates. For example, the collection of Variable items owned by a parent Component.

View attributes of an item

Retrieving the value of an item’s attribute is simple, and follows the same general pattern throughout libCellML. Get the attribute xyz using the camelCase function xyx() without arguments.

For example:

// Retrieving the name attribute from the myModel item:
std::string myModelName = myModel->name();

// Retrieving the initial value of the myVariable item:
std::string myInitialValue = myVariable->initialValue();
# Retrieving the name attribute from the my_model item:
my_model_name = my_model.name()

# Retrieving the initial value of the myVariable item:
my_initial_value = my_variable.initialValue()

Note that the return value’s type will vary depending on the function. For example, a Variable item pointer is returned as the testVariable() attribute value for a Reset item:

// Retrieve the test variable from the myReset item:
libcellml::VariablePtr myTestVariable = myReset->testVariable();
# Retrieve the test variable from the my_reset item:
my_test_varible = my_reset->testVariable()

View collections owned by an item

In order to access items within a collection use the same general format as above, but with an indicator (name or index) of the child item to be retrieved from the collection. In other words, get the child item of type xyz using the camelCase function xyx(myIndex) or xyz(myName).

Before accessing a collection item using an index, you can use the xyzCount() function to return the number of items in the collection.

The following example shows how all variables in a component can be listed.

// Loop through variables in the component myComponent and retrieve their names.
//    NOTE that indexing starts from zero.
for(size_t v = 0; v < myComponent->variableCount(); ++v) {

  // Retrieve the Variable item at index v:
  auto myVariable = myComponent->variable(v);

  // Retrieve the name of the myVariable item:
  auto myVariableName = myVariable->name();
}

// Retrieve a variable called "helloThere" by name.
//    NOTE that a nullptr will be returned if no variable of that name is found.
auto myHelloThereVariable = myComponent->variable("helloThere");

// In this case, the myMissingVariable will be a nullptr:
auto myMissingVariable = myComponent->variable("nameThatDoesntExist");

// This will cause a segfault as myMissingVariable is null:
auto myMissingName = myMissingVariable->name();

Some gotchas

The ownership of some collections can be a little counter-intuitive. One example is that Units items are referenced by Variable items, but are owned by the Model; this is so that units can be reused across more than one component. Another example involving encapsulation and Component item ownership is shown below.

Consider the following model:

model: Grandfather
  component: Uncle
  component: Mother
    component: Daughter
    component: Son

The raw CellML syntax stores each component individually as children of the model, and separately stores the encapsulation structure of the nested components.

See CellML syntax

<model>

  <!-- The components are listed individually as children of the model block. -->
  <component name="Uncle"/>
  <component name="Mother"/>
  <component name="Daughter"/>
  <component name="Son"/>

  <!-- The encapsulation structure is stored separate from the components. -->
  <encapsulation>
    <component_ref component="Mother">
      <component_ref component="Daughter"/>
      <component_ref component="Son"/>
    </component_ref>
  </encapsulation>
</model>

In libCellML, the encapsulation structure is embedded in the ownership of the components, so that one component can be a parent of another. This can be confusing if the simple componentCount() function on a model is called naively, as shown below.

// The number of components owned by the grandfather model refers *only* to its direct children:
auto grandfatherHasTwoKids = grandfather->componentCount(); // returns 2

// Each component must be interrogated individually to determine its children.
//    Note that the uncle component is the 0th child of the grandfather model.
auto uncleHasNoKids = grandfather->component(0)->componentCount();          // returns 0
auto motherHasTwoKids = grandfather->component("Mother")->componentCount(); // returns 2

Useful snippets for viewing a model

Some useful snippets for viewing parts of your model are shown below.

Retrieve units needed by a component: variables and mathematics

There are two places that need a reference to Units items. The first is the set of Variable items stored in the Component: the units name for each of these is accessible in the name() attribute of its units() item.

// This example assumes you already have a component defined.
// You will need to #include <unordered_set> in your #include statements.
std::unordered_set<std::string> unitsNames;

// Iterate through the variables in this component, and add their units' names to the set.
for (size_t v = 0; v < component->variableCount(); ++v) {
    // Get the units for this variable:
    auto myUnits = component->variable(v)->units();
    // Check that this is not the nullptr, otherwise skip.
    if (myUnits != nullptr) {
        // Add name to set if not already there.
        unitsNames.insert(myUnits->name());
    }
}

// Parse the MathML string to find any units used by <cn> constants:
std::string delimiter = "cellml:units=";
std::string maths = component->math();
size_t pos = maths.find(delimiter); // Start looking for the name after the first delimiter.
size_t pos2;
std::string segment;
std::string name;
while ((pos = maths.find(delimiter)) != std::string::npos) {
    segment = maths.substr(0, pos);
    segment.erase(0, segment.find("\"")); // Remove the first quote mark after the delimiter.
    pos2 = segment.find("\""); // Find the second quote mark.
    name = segment.substr(0, pos2); // Units name is between the two quotes.
    if (name.length()) { // Sanity check that the string is not empty.
        unitsNames.insert(name);
    }
    maths.erase(0, pos + delimiter.length()); // Remove this segment from the main string.
}
// Search the final remaining segment.
segment = maths;
segment.erase(0, 1);
pos2 = segment.find("\"");
name = segment.substr(0, pos2);
if (name.length()) {
    unitsNames.insert(name);
}

// Print the unique units for this component to the terminal.
for (const auto &name : unitsNames) {
    std::cout << "  - " << name << std::endl;
}

Edit MathML in a component

MathML is stored as a single string within a component. Retrieving it is simple enough using the math() function, but any manipulation (change units used, changing variable names, adding additional relationships, etc) are a little more complicated.

TODO: Need more examples of useful mathml manipulation. Variable names? Need to remove whitespace first?

void switchUnitsInMaths(std::string &maths, std::string in, std::string out)
{
    //  Note that this function will replace any and all occurrences of the "in"
    //  string within the "maths" string with the "out" string.  It's worth noting that
    //  in order to be sure that only full name matches for units are replaced, we exploit
    //  the fact that the units names in the MathML string will be in quotation marks, and include
    //  these quotation marks on either side of the in and out strings for safety.

    std::string::size_type n = 0;
    std::string in_with_quotes = "\"" + in + "\"";
    std::string out_with_quotes = "\"" + out + "\"";

    while ((n = maths.find(in_with_quotes, n)) != std::string::npos) {
        maths.replace(n, in_with_quotes.size(), out_with_quotes);
        n += out_with_quotes.size();
    }

    std::cout << "Switched units '" << in << "' for units '" << out << "'" << std::endl;
}

Print encapsulation structure

Because components may be nested to any depth within an encapsulation hierarchy, we need to use recursive functions to be sure of reaching the bottom level. The examples below define two functions - one to initiate the recursion, and one to carry it out.

// This function is called to initiate the recursion:
void printEncapsulationStructureToTerminal(libcellml::ModelPtr &model)
  {
      // Prints the encapsulation structure of the model to the terminal
      std::string spacer = "  - ";
      std::cout << "Model '" << model->name() << "' has " << model->componentCount()
                << " components" << std::endl;
      for (size_t c = 0; c < model->componentCount(); ++c) {
          auto child = model->component(c);
          printComponentOnlyToTerminal(child, spacer);
      }
  }

  // This function performs the recursion to the full depth of the encapsulation:
  void printComponentOnlyToTerminal(libcellml::ComponentPtr &component, std::string spacer)
  {
      std::cout << spacer << "Component '" << component->name() << "' has " << component->componentCount() << " child components" << std::endl;
      for (size_t c = 0; c < component->componentCount(); c++) {
          std::string anotherSpacer = "    " + spacer;
          auto child = component->component(c);
          printComponentOnlyToTerminal(child, anotherSpacer);
      }
  }

Trace equivalent variables

This example traces variable equivalences throughout the model using recursion. The CellML file read contains a model as shown below, where two pairs of equivalent variables (A to B, and B to C) connect three variables together.

model:
    ├─ component: componentA
    │   └─ variable: A [dimensionless] <╴╴╴╮
    │                                      ╷
    │                                  equivalent
    ├─ component: componentB               ╵
    │   └─ variable: B [dimensionless] <╴╴╴╯<╴╴╴╮
    │                                           ╷
    │                                       equivalent
    └─ component: componentC                    ╵
        └─ variable: C [dimensionless] <╴╴╴╴╴╴╴╴╯

Show CellML syntax

<?xml version="1.0" encoding="UTF-8"?>
  <model xmlns="http://www.cellml.org/cellml/2.0#"
    xmlns:cellml="http://www.cellml.org/cellml/2.0#" name="quickstart_traceEquivalence">
    <component name="componentA">
      <variable units="dimensionless" name="A" interface="public" />
    </component>
    <component name="componentB">
      <variable units="dimensionless" name="B" interface="public" />
    </component>
    <component name="componentC">
      <variable units="dimensionless" name="C" interface="public" />
    </component>
    <connection component_1="componentA" component_2="componentB">
      <map_variables variable_1="A" variable_2="B"/>
    </connection>
    <connection component_1="componentB" component_2="componentC">
      <map_variables variable_1="B" variable_2="C"/>
    </connection>
  </model>

The example should output the connections between the variables, including discerning that A is connected to C, even though no direct relationship is specified in the model.

Variable 'A' in component 'componentA' is connected to:
 - variable 'B' [dimensionless] in component 'componentB'
 - variable 'C' [dimensionless] in component 'componentC'
// Function to initiate a list of variables in the connected set, to start the recursion, and to print
// the list to the terminal.
void printEquivalentVariableSet(const libcellml::VariablePtr &variable)
{
    if (variable == nullptr) {
        std::cout << "NULL variable submitted to printEquivalentVariableSet." << std::endl;
        return;
    }
    std::vector<libcellml::VariablePtr> variableList;
    variableList.push_back(variable);
    listEquivalentVariables(variable, variableList);

    // The parent() function returns an EntityPtr, which must be cast to a Component before its name()
    // function can be called.
    libcellml::ComponentPtr component = std::dynamic_pointer_cast<libcellml::Component>(variable->parent());

    if (component != nullptr) {
        std::cout << "Tracing: " << component->name() << " -> "
                  << variable->name();
        if (variable->units() != nullptr) {
            std::cout << " [" << variable->units()->name() << "]";
        }
        if (variable->initialValue() != "") {
            std::cout << ", initial = " << variable->initialValue();
        }
        std::cout << std::endl;
    }

    // The variableList contains the variable that was submitted for testing originally, so
    // if it's connected to other variables, it must have a length greater than 1.
    if (variableList.size() > 1) {
        for (auto &e : variableList) {
            component = std::dynamic_pointer_cast<libcellml::Component>(e->parent());
            if (component != nullptr) {
                std::cout << "    - " << component->name() << " -> " << e->name();
                if (e->units() != nullptr) {
                    std::cout << " [" << e->units()->name() << "]";
                }
                if (e->initialValue() != "") {
                    std::cout << ", initial = " << e->initialValue();
                }
                std::cout << std::endl;
            } else {
                std::cout << "Variable " << e->name() << " does not have a parent component." << std::endl;
            }
        }
    } else {
        std::cout << "    - Not connected to any equivalent variables." << std::endl;
    }
}

// This function performs the recursive search through all connections until the set
// has been completely covered.
void listEquivalentVariables(const libcellml::VariablePtr &variable,
                             std::vector<libcellml::VariablePtr> &variableList) {
    if (variable == nullptr) {
        return;
    }

    for (size_t i = 0; i < variable->equivalentVariableCount(); ++i) {
        libcellml::VariablePtr equivalentVariable = variable->equivalentVariable(i);
        if (std::find(variableList.begin(), variableList.end(), equivalentVariable) == variableList.end()) {
            variableList.push_back(equivalentVariable);
            listEquivalentVariables(equivalentVariable, variableList);
        }
    }
}