Skip to content

IntensityStatistic and Exodus output with VTK

mperrinel edited this page Aug 17, 2020 · 9 revisions

Goal of the IntensityStatistic

The IntensityStatistic aims to collect the traffic intensity of components and sub components during the simulation. The collected traffic data are then outputed in a exodus file using the VTK Exodus writer. This file can be read with Paraview to produce some screenshots or videos.

Architecture

This work is developed as a part of the statistics module of sst-core. It is composed of a Statistic class and some output classes :

  • IntensityStatistic : Collect the traffic intensity during the simulation.
  • StatisticOutputEXODUS : Aggregate the traffic intensity collected then Output it into an exodus file. This class is pure virtual and needs a child concrete class to works.
  • VTKStatisticOutputEXODUS : Is a concrete child class of the StatisticOutputEXODUS and use the VTK and its vtkExodusWriter to output the traffic intensity. The topology is provided by the parameters (python file) and transformed into some Stat3dViz objects.
  • vtkTrafficSource : Attach the temporal traffic intensity data to the VTK drawable objects.

The VTKStatisticOutputEXODUS and the vtkTrafficSource depends on VTK and require some new options to be activated with the sst configuration :

  • --with-vtk=$VTK_INSTALL_PATH
  • --enable-vtk=$VTK_VERSION

The feature has been tested with VTK 8.1. For this case, the --with-vtk needs to be filled with the installation repository of VTK, and the --enable-vtk needs to be filled with the version of the VTK used (e.g. --enable-vtk=8.1)

IntensityStatistic

The IntensityStatistic inherits from the MultiStatistic templated class and is defined in the statintensity.h header file:

class IntensityStatistic : public MultiStatistic<uint64_t, double>

A MultiStatistic is a Statistic which takes a tuple as templated parameters:

template <class... Args>
using MultiStatistic = Statistic<std::tuple<Args...>>;

As a result, MultiStatistic<uint64_t, double> is the same as a Statistic<std::tuple<uint64_t, double>>

The statistic class has two member variables:

  // statitensity.h
  ...
  std::vector<intensity_event> intensity_event_vector_;
  Stat3DViz stat_3d_viz_;

The intensity_event_vector_ holds intensity_event collected by the Statistic The stat_3d_viz_ holds the geometry of the Statistic provided by the Params parameter of the IntensityStatistic constructor.

The IntensityStatistic needs two parameters for the collection :

  • The time of the event collected (uint64_t)
  • The value of the intensity collected (double)

The collection is done through the method :

void addData_impl(uint64_t time, double intensity);

A intensity_event is created using the time and intensity parameters. Its structure is very simple :

struct intensity_event {
    uint64_t time_; // progress time
    double intensity_;

    intensity_event(uint64_t t, double intensity) :
    time_(t), intensity_(intensity)
    {
    }

};

Once the intensity_event is created, it is inserted into the intensity_event_vector_.

StatisticOutputEXODUS

The StatisticOutputEXODUS aims to output the traffic intensity collected into an Exodus file. The class inherits from the StatisticOutput templated class and is pure virtual :

class StatisticOutputEXODUS : public StatisticOutput

public:
...
void output(StatisticBase* statistic, bool endOfSimFlag) override;
void endOfSimulation() override;
...

private:
 std::string              m_FilePath;
 std::multimap<uint64_t, intensity_event> m_traffic_progress_map;
 std::set<Stat3DViz, compare_stat3dviz> m_stat_3d_viz_list_;

The output method aggregates all the intensity_event collected by the Statistics intensity_event_vector_ in the m_traffic_progress_map member variable of the StatisticOutputEXODUS class. In addition, all of the IntensityStatistic stat_3d_viz_ are also aggregated into the m_stat_3d_viz_list_ member variable of this class:

 if(endOfSimFlag) {
      IntensityStatistic* intensityStat = dynamic_cast<IntensityStatistic *>(statistic);
        if (intensityStat) {
            for (auto eventIte : intensityStat->getEvents()) {
                 // creation of the sorted event
                sorted_intensity_event event(this->statisticId_, eventIte);
                m_traffic_progress_map.emplace(eventIte.time_, event);
            }
            auto stat3dViz = intensityStat->geStat3DViz();
            stat3dViz.setId(this->statisticId_);
            m_stat_3d_viz_list_.insert(stat3dViz);

            this->statisticId_ = this->statisticId_ + 1;
        }
        else {
            Output out = Simulation::getSimulation()->getSimulationOutput();
            out.verbose(CALL_INFO, 1, 0, " : StatisticOutputEXODUS - The ouput won't be produced : the statistic type is not of type  IntensityStatistic\n");
        }
    }

The aggregation is done only once, when the endOfSimFlag is true. The StatisticExodusOutput is currently only compatible with the IntensityStatistic. That's why, it does nothing if the Statistic is of another type. Furthermore, the aggregation is in charge of creating an unique id for each stat3dViz object. This id permits to do the link between an intensity event and the Statistic object. Since intensity_event cannot hold an id, it is transformed into a sorted_intensity_event which can hold the id. For the IntensityStatistic statistic, that doesn't make sense to partially output the traffic intensity collected like it is done for other Statistics and all StatisticFieldsOutput output formats. That's why, the Exodus file is completely filled at the end of the simulation :

void StatisticOutputEXODUS::endOfSimulation()
{
    this->outputConsole();
    this->writeExodus();

    // Close the file
    closeFile();
}

The writeExodus method is pure virtual, meaning that a child class of StatisticOutputEXODUS is necessary to produce the Exodus file. Here is the VTKStatisticOutputEXODUS that inherits from StatisticOutputEXODUS and that implements the writeExodus method.

void VTKStatisticOutputEXODUS::writeExodus() {

    vtkTrafficSource::vtkOutputExodus(m_FilePath, std::move(m_traffic_progress_map),
                          std::move(m_stat_3d_viz_list_)
                          );
}

This method called the vtkOutputExodus static method which is defined in the vtkTrafficSource class.

How the exodus file is filled (using VTK)

VTK contains a vtkExodusIIWriter that permits to write an Exodus file from a vtkUnstructuredGrid. This format is compatible with temporal data and can be open with Paraview.

The ** vtkOutputExodus** method has this signature:

vtkOutputExodus(const std::string& fileroot,
    std::multimap<uint64_t, sorted_intensity_event>&& traffMap,
    std::set<Stat3DViz, compare_stat3dviz>&& stat3dVizSet)

The fileroot defines the where the Exodus file has to be written. The traffMap contains the temporal traffic intensity data The stat3dVizSet contains the geometry of all the Statistics.

Geometry and unstructured grid

The first step is to construct the geometry using the stat3dVizSet parameter. The vtkUnstructuredGrid can be filled using this the SetPoints and the SetCells methods:

 unstructured_grid->SetPoints(points);
 unstructured_grid->SetCells(cell_types.data(), cells);

The points parameter is of vtkPoints type, the cells is of type vtkCellArray and the cells_types is of type std::vector.

A loop is done on the stat3dVizSet :

 for (const auto& stat3dViz : stat3dVizSet) {
      Shape3D *shape = stat3dViz.my_shape_;
      switch (stat3dViz.my_shape_->shape) {
      case Shape3D::Box: {
          Box3D * box = static_cast<Box3D*> (shape);
          // Fill the points
          points->SetPoint(0 + i, box->x_origin_, box->y_origin_, box->z_origin_);
          points->SetPoint(1 + i, box->x_origin_ + box->x_extent_, box->y_origin_, box->z_origin_);
          ...
          // Fill the cells
          vtkSmartPointer<vtkHexahedron> cell = vtkSmartPointer<vtkHexahedron>::New();
          for (int j= 0; j< NUM_POINTS_PER_BOX; ++j) {
              cell->GetPointIds()->SetId(j, i + j);
          }
          cells->InsertNextCell(cell);
          cell_types.push_back(VTK_HEXAHEDRON);
          ...
      case Shape3D::Line: {
      ...

The shape of every statistic is retrieved and the corresponding code to fill the points and the cells is called. The Shape3D structure defines a shape enum list all the available shapes :

enum Shape {
     Box,
     Line
   };

Currently, only the Box and the Line are defined. The first one needs height points to define it when the second needs two points. VTK can represent them using a vtkHexahedron and a vtkLine.

How the temporal intensity data is attached to the VTK object.

The vtkTrafficSource is a vtkUnstructuredGridAlgorithm. That means it takes a vtkUnstructuredGrid as input and produces vtkUnstructuredGrid on wich an algorithm has been applied. On our case, it will add a traffic intensity array to the vtkUnstructuredGrid of the output :

output->GetCellData()->AddArray(this->Traffics);

this->Traffics contains all the intensity data for all the geometry and for one temporal step.

This array is filled using the traffic_progress_map_ coming from the aggregation done by the VTKStatisticOutputExodus:

    output->GetInformation()->Set(vtkDataObject::DATA_TIME_STEP(), reqTS);

    //Updade and Send traffic to output
    auto currentIntensities =  traffic_progress_map_.equal_range(reqTS);

    for(auto it = currentIntensities.first; it != currentIntensities.second; ++it){
        auto& event = it->second;
        this->Traffics->SetValue(event.id_, event.ie_.intensity_);
    }

reqTs contains the current time step. Then a range of intensities are extracted from the map using it. A loop is done on these intensities and permit to associated the correct intensity for the correct cell, at the correct time.

How to enable the statistic in a python parameters file

The way that the VTK statistic can be enable is the same as for others statistics

For instance, the end of the python parameters file should contains :

sst.enableStatisticForComponentType("macro.snappr_switch",'traffic_intensity',{"type":"sst.IntensityStatistic"})
sst.setStatisticOutput("sst.vtkstatisticoutputexodus")

In this example, the IntensityStatistic will be activated for the macro.snappr_switch component and uses the traffic_intensity registered by some compatible components to do the collection. The sst.vtkstatisticoutputexodus activates the exodus output.