Skip to content

Guidelines for Developing a New TTK Module [experimental branch paraview5.7]

Julien Tierny edited this page Jul 5, 2019 · 1 revision

Thanks for creating a new module for TTK!

Please take a few minutes to review our guidelines below, which will hopefully ease your work.

This version is for the experimental branch of TTK. If you are on a release or the master branch, please refer to these guidelines.

1. Module structure

As documented in TTK's companion paper, each TTK module is organized in 3 layers:

  • Base layer core/base/: This directory contains the implementations of the core algorithms.
  • VTK layer core/vtk: This directory provides wrappers for the VTK API as well as XML specifications for the ParaView plug-ins.
  • ParaView layer paraview/: This directory contains the CMake files to declare the ParaView plug-ins.

Assuming a module named HelloWorld, it is composed of the following directories:

  • core/base/helloWorld: heart of the algorithm, VTK free
  • core/vtk/ttkHelloWorld: wrapper VTK, XML files
  • paraview/HelloWorld: register the ParaView filter
  • standalone/HelloWorld: GUI and CLI programs

The content of these directories is detailed in the following. A set of scripts made to create, clone and delete modules is presented in section 1.5

1.1 Base code

The first directory (core/base/helloWorld) is where you can implement the heart of your algorithm. It contains:

  • core/base/helloWorld/
    • HelloWorld.h: header file
    • HelloWorld.cpp: source file
    • CMakeLists.txt: declare sources, headers and base code dependencies

If you create new header or source files for your algorithm, you need to update the CMakeLists.txt. Usually, you start by setting up the I/O for your algorithm (see 1.2) before implementing the base code.

1.2 VTK Wrapper

The VTK wrappers directory (core/vtk) contains files to set up the I/O of your filger and build the VTK wrapper and the ParaView plugin:

  • core/vtk/ttkHelloWorld/
    • ttkHelloWorld.h: header file
    • ttkHelloWorld.cpp: source file
    • HelloWorld.xml: GUI of the ParaView filter
    • vtk.module: declare the VTK dependencies (VTK modules to build)
    • ttk.module: declare the TTK dependencies (sources, header and XML files, base code targets)
    • TTKWrapper.cmake: register the module in the ParaView plugin
    • CMakeLists.txt: register the VTK module (may be called during the ParaView plugin build)

If you create new header or source files for the wrapper, you need to update the ttk.module. The vtk.module file only needs to be updated if your wrapper requires specific VTK features.

Most of the time, you only need to update the header, source and XML files here.

1.3 ParaView

The ParaView directory (paraview) contains files to register the TTK modules in the ParaView plugin:

  • paraview/HelloWorld/
    • TTKFilter.cmake: register the ParaView filter

You can ignore this folder.

1.4 Standalone

The last directory (standalone/HelloWorld) contains the hierarchy to build 2 standalone programs using your new module (one in command line, the other one with a basic VTK-based GUI):

  • standalone/HelloWorld/
    • cmd/
      • main.cpp: source file
      • CMakeLists.txt: declare source file and base code dependencies
    • gui/
      • main.cpp: source file
      • CMakeLists.txt: declare source file and base code dependencies

If you do not wish to provide/maintain these standalone programs, simply remove the directory standalone/HelloWorld.

1.5 Scripts

We provide a set of scripts which will help you create automatically all the necessary files for a module.

To create a blank new module, enter the following command from the top of TTK's source tree:

$ scripts/createTTKmodule.sh <Name, first letter in uppercase, no space. for example: HelloWorld>

If you build and install TTK, your new module should be readily available and executable in ParaView.

If you wish to delete a module (for instance the above HelloWorld example), enter the following command:

$ scripts/deleteTTKmodule.sh HelloWorld

You can also create a new module by cloning an already-existing module (which is particularly useful to copy a specific configuration of the VTK layer, in terms of inputs and outputs):

$ scripts/cloneTTKmodule.sh <SourceTTKmodule> <DestinationTTKmodule>

If you created your module with the createTTKmodule.sh script, you can start to adjust the module to your needs by typically updating the input and output specification at the VTK/ParaView layers (in the core/vtk folder). For this, follow the TODO comments, in increasing order, from the file core/vtk/ttkHelloWorld/ttkHelloWorld.h. Note that modifications made to the VTK layer will probably have to be reported to the ParaView and standalone components.

Once you have adjusted the inputs and outputs of your TTK module, you can proceed with the implementation of the core algorithm in the base layer. For this, follow the TODO comments, in increasing order, from the file core/base/helloWorld/HelloWorld.h. Note that this file contains many other comments providing useful recommendations (in particular regarding interactions with TTK's internal triangulation data structure).

Note that by default, new modules will use TTK's internal triangulation data structure for efficient mesh traversals. Please review this class documentation before using it, as it uses an original pre-conditioning mechanism.

Now, before diving in the implementation of your module, we invite you to read carefully the following documentation, explaining the content of each file initially created by the createTTKmodule.sh script.

2. Implementation recommendations

  • Base layer:

    • The base TTK classes (implementing the core of your module) should be implemented as templatized functors (as initially declared with the above scripts). This means that your base class should not store data. It should only be passed a pointer to an input buffer to read, and a pointer to an output buffer to fill. It is recommend to templatize the core functions of your class to be generic to the type of data considered on the input and the output (float, double, char, etc., as initially declared with the above scripts).
    • By default (as initially declared with the above scripts), each TTK base class inherits from the ttk::Debug class, which holds some information about:
      • the current debug level (debugLevel_, setup by the calling program with the function setDebugLevel())
      • the current thread number (threadNumber_, setup by the calling program with the function setThreadNumber(), default value: number of cores on the system).
      • a pointer to the calling wrapper (used by the VTK layer)
    • To print some messages on the standard outputs, please do not use std::cout or std::cerr. Please use the dMsg() function of your TTK class instead (see the doxygen documentation of the ttk::Debug class)
    • TTK provides a number of general-purpose classes that may make your life easier in the development of the base classes of your module:
      • To measure time in your code, please use the ttk::Timer class.
      • To perform some geometrical computation (dot products, cross products, barycentric coordinates, etc), please checkout the doxygen documentation of the ttk::Geometry class. It is likely that what you need is already implemented there. If it is not, this class is the right place to implement new, low-level, geometry related functions.
      • The ttk::CommandLineParser class provides a full featured command line parser (used by the standalone components of your module).
      • Several other classes from the base layer can be useful for the development of your own module (see for instance: ttk::Dijkstra class, ttk::DimensionReduction class, ttk::Laplacian class, ttk::UnionFind class). Please have a quick look at the list of available classes before implementing a new algorithm your module may need. Note that if your module needs a specific functionality, it may be useful to implement it as a separate base layer class (for instance the ttk::HarmonicField class uses the ttk::Laplacian class, which uses itself the ttk::Geometry class).
      • If you use an already-existing base layer class B in the base class A of your own module, please update A's CMakeLists.txt file accordingly to make sure that it links against B (see for instance core/base/scalarFieldCriticalPoints/CMakeLists.txt, where the class ttk::ScalarFieldCriticalPoints links against the ttk::UnionFind class in addition to the default ttk::Triangulation one).
    • We recommend to use OpenMP as soon as possible. Please wrap any OpenMP call around #ifdef TTK_ENABLE_OPENMP and #endif statements.
    • At the beginning of each function, wrap the check of the validity of its parameters around #ifdef TTK_ENABLE_KAMIKAZE and #endif statements (see core/base/blank/Blank.h for an example). When built in KAMIKAZE mode, TTK will skip these sanity checks for faster performances.
    • Function prototypes in the base layer are based on the following conventions:
      • Functions return an error code (0 if success).
      • Inputs are passed as function arguments with const references (const pointers if not possible otherwise).
      • Outputs are passed as function arguments with references (pointers if not possible otherwise).
  • Third-party dependencies:

    • Third-party dependencies should be handled at the base layer.
    • If a third-party dependency is not found, your module should still build and run. At run time, an error message can be reported about the missing dependency.
    • To add a third-party dependency in your code, follow the example of the inclusion of ZLIB:
  • TODO VTK layer:

    • pointer to VTK documentation
    • by default shallowcopy, deepcopy only for data which needs to be modified (smoother version of an input field)
    • GetVoidPointer
    • SetVoidPointer
  • TODO ParaView layer: make sure to assign your module to the right category.

  • TODO General recommendations:

    • Never use new (or related functions, such as VTK's ::New()).

3. Documentation

  • TTK uses Doxygen to generate online documentations.
  • Please provide a general documentation for each class you write.
  • Within each class, please provide a documentation for each function. See the ttk::Triangulation class for an example.

4. Authorship and references