Transport and Anisotropic Diffusion in Time Dependent Flow Visualization

Nadine Olischläger, Tobias Preußer, Martin Rumpf

Download the C++ Source Code Implementation

 

Sample Image This site contains the C++ source code and the documentation for routines incorporating the anisotropic nonlinear transport diffusion for time dependent flow visualization. The gzipped tar file contains the header file "timedepFlowVis.h", the  source file "timedepFlowVis.cpp", a Makefile, a sample program,  and this html file.
Note that this program computes only a sequence of pictures that have to be blended to be animated in a movie. Have a look at the corresponding reserach project site for details.

Download here: timedepFlowVis.tar.gz (ca. 4MB) 
                        (includes the source code and the vector field data)

                        FlowVisSourceCode.tar.gz (ca. 115KB) 
                        (includes only the source code)

                        FlowVisVectorField.tar.gz (ca.3,9MB)
                        (includes only the vector field data)


Corresponding Research Project Site:  PDE Method in Flow Visualization

horizontal rule

Contents

bullet Getting Started
bulletAvailable Constructors and the Function "timeStep" 
bulletThe Variables
bulletStudy of Parameters
bullet File formats
bullet The C++ Source Code
bulletDocumentation generated by doxygen

Getting started

After downloading the file timedepFlowVis.tar.gz you should unpack this file to some directory using the commands

gzip -d timedepflowVis.tar.gz
tar -xvf timedepflowVis.tar

This will extract all files you need. Next you should compile the package using the given Makefile (command "make").
The compile process will create a sample program which will visualize the sample vector field data contained in the directory benard. Start the program using the command "main".

The program will start and write a lot of messages about what it is doing onto the screen. The gray-level output images will be placed in the directory picture/ and the colored images will be saved in the directory colored_picture/. The directories  have been created when unpacking the tar-file. You can use any image viewer, that can read PGM files, e.g. xv, to view the images.

The default vector field example is called "EXAMPLE_BENARD". The C++ source code enclose two other examples: "EXAMPLE_WHIRLPOOL" and "EXAMPLE_CIRCLE".
If you want to create another vector field example you have to modify the source code. The examples are defined in the main program (confer "timedepflowvis.cpp"):

    int main() {
 
    #define EXAMPLE_BENARD
     //#define EXAMPLE_CIRCLE
     //#define EXAMPLE_WHIRLPOOL


    TransportDiffusion *diff;

  //... omitted source code

    #ifdef EXAMPLE_CIRCLE

      diff = new TransportDiffusion(10,400,400,0.01,
                             "./picture/picture%03d.pgm","./color_picture/color_picture%03d.pgm",
                             1./1000.,1./100.,200.,0.4,200,1.e-6,
                             lowColor,highColor);
    
    #endif

    #ifdef EXAMPLE_WHIRLPOOL
      
 //...omitted source code

      diff= new TransportDiffusion(vf,T,M_width,N_height,0.01,
                        "./picture/whirlpool_%03d.pgm","./color_picture/color_whirlpool_%03d.pgm",
                        1./1000., 1./10000.,                                
                         100.0, 0.5, 500, 1.e-6,lowColor,highColor);                       

    #endif

    #ifdef EXAMPLE_BENARD

     diff = new TransportDiffusion("./benard/benard_%d.dat",10, 0.1,
                         "./picture/029_benard_%03d.pgm",
                         "./color_picture/029_color_benard_%03d.pgm",
                         1./100., 1./100.,                                 
                         1.0, 0.4, 500, 1.e-6,lowColor,highColor);                       
    #endif

      diff->timeStep(1,9);
 
      delete diff;

  //... omitted source code

    }

As seen below you only have to change the red lines. For example, if you like to have the circle vector field, you have to define "EXAMPLE_CIRCLE" and to undefine the other examples:

        //#define EXAMPLE_BENARD
    #define EXAMPLE_CIRCLE
        //#define EXAMPLE_WHIRLPOOL

The file FlowVisSourceCode.tar.gz contains only the C++ source code and not the vector field data. That means that you have only the choice between EXAMPLE_CIRCLE and EXAMPLE_WHIRLPOOL.

Available Constructors and the Function "TimeStep"

The file timedepFlowVis.cpp implements three constructors and the function "TimeStep" computing the nonlinear anisotropic  transport  diffusion to visualize a vector field given in an (M_width x N_height) array. 
As seen below, the main program creates an object (e.g. diff) using one of the three different constructors.
Each example uses another constructor.
Available constructors are:

Transport_Diffusion(char* VFfileName, int T ,
                    D_TYPE tau,
                    char* outputFile, char* colorOutputFile,
                    D_TYPE lambda, D_TYPE lambda2,
                    D_TYPE beta, D_TYPE scaleF,
                    int MAXCOUNTER, D_TYPE eps
                   
int* lowColor, int* highColor );



Transport_Diffusion(d3p* vf, int T, int M_width, int N_height,
                    D_TYPE tau,
                     char* outputFile, char* colorOutputFile,
                     D_TYPE lambda, D_TYPE lambda2,
                    D_TYPE beta, D_TYPE scaleF,
                     int MAXCOUNTER, D_TYPE eps
                   
int* lowColor, int* highColor );



Transport_Diffusion(int T, int M_width, int N_height,
                    D_TYPE tau
                    char* outputFile, char* colorOutputFile,
                    D_TYPE lambda,
D_TYPE lambda2,
                    D_TYPE beta, D_TYPE scaleF,
                    int MAXCOUNTER, D_TYPE eps
                   
int* lowColor, int* highColor
);
                   

The call of the function  "timeStep" ( e. g. diff->timeStep(1,50); ) will produce several images.
It solves some time steps of the PDE system. The first time step will be the one with number "first", the last time step will be the one with number "last".
Function returns 0 if it was executed successfully and some value different from 0 else.

    int timeStep(int first, int last);

The Variables

As seen in the previous section you can set many parameters for the transport diffusion process by using a constructor from above. The following table tells you the meaning of the parameters which have to been set.  The values below the type definitions of a parameter give the default value that will be set by the constructor if this parameter is omitted.

VFfileName CHAR* Name of vector field data file
vf d3p* d3 is an array of length 3. d3p is a pointer to d3. These types are used to save vf, the vector field. The "array" vf has the following shape:
vf [t][k][i] .
0 <= t < T : vector field at time step t
0 <= k < M_width+N_height : pixel with number k (lexicographical ordered)
i = 0 : X-value
i = 1 : Y-value
i = 2 : norm ( velocity ) 
T INT

10

Determines the number of the given vector fields.
M_width INT

257

Determines the number of pixels along the x-coordinate axis.
N_height INT

257

Determines the number of pixels along the y-coordinate axis.
tau DOUBLE

0.1

Determines the length of one single time step of the anisotropic transport diffusion. This parameter must be adapted to the distance of the vector fields.
E.g. for images of width 257 the value 0.0001 is recommended, if you use a test vector field. 
outputFile CHAR*


=>

Names of the output file of the gray images. The resulting filename will be created using sprintf(filename, outputFile, number). The number of the time step will be included. The default names of the images:
./picture/picture%03d.pgm
colorOutputFile CHAR*

=>

Name of the output file of the colored images. The resulting filename will be created using sprintf(filename, outputFile, number). The default names of the images:
./color_picture/color_picture%03d.pgm
lambda DOUBLE

1/10000

The shape of the diffusion coefficient g(), controlling the Perona Malik diffusion perpendicular to the vector field will be g(s2) = 1/(1 +  s/ lambda2).
If you want to modify the shape of the function g more than this parameter allows you to, or even if you want to modify the function controlling the linear diffusion along the vector field, you have to modify the code directly (see below). 
lambda2 DOUBLE

1/100

This variable is used to calculate the one sided diffusion (perpendicular to the vector field).
The Function galphap needs lambda2 to calculate the Perona Malik diffusion:
galphap(s2) = 1/(1 +  s/ lambda22)
beta DOUBLE

10.0

Balancing parameter (Transport vs. Diffusion), which also controls the diffusion parallel to the vector field.

scale_F DOUBLE

=>

ScaleF controls the maximum value of the contrast enhancing right hand side f of the PDE system.

0.0 <= scaleF <= 1.0

MAXCOUNTER INT

500

Determines the maximum number of iteration steps of the CG solver. 
eps DOUBLE

1e-6

Determines the numerical accuracy of the CG solver.
first/last INT Determines the number of time steps the program will perform. Each time step of the anisotropic transport diffusion will have length tau. The program starts with the "first" and stop after the "last" vector field .
low/highColor INT*

=>

The Colors are used to color (subsequently) the velocity of the vector field.
They are coded in the RGB modus.
The default colors are yellow for "high" velocity and blue for "low" velocity.


Study of Parameters


As seen in the previous section you can set many parameters for the transport diffusion process.
 The following table tells you what will happen, if you change the parameters.

PARAMETER

> (increasing the parameter) < (decreasing the parameter)

lambda

Increasing lambda means intensifying the diffusion perpendicular to the vector field, which also means that the diffusion parallel : diffusion perpendicular (to the vector field) -ratio changes.
Modifying lambda will lead to changing the shape of the black spots.
While increasing lambda the spots became more roundish. (confer picture1)

Decreasing lambda means extenuating the diffusion perpendicular to the vector field, which also means that the diffusion parallel : diffusion perpendicular (to the vector field) -ratio changes.
Modifying lambda will lead to changing the shape of the black spots.
While decreasing lambda the spots became more longish. (confer picture3)

lambda2

Increasing lambda2 is equivalent to decreasing the one sided diffusion (confer picture4).

Decreasing lambda2 is equivalent to increasing the one sided diffusion (confer picture3).

beta

Increasing beta means intensifying the diffusion parallel to the vector field, which also means that the diffusion parallel : diffusion perpendicular (to the vector field) -ratio changes.
If you make beta too large the picture will be blurred, because the diffusion is too high. (confer picture2)
Modifying beta will also lead to a different shape of the black spots.
While increasing beta the spots became more longish.

Decreasing beta means extenuating the diffusion parallel to the vector field, which also means that the diffusion parallel : diffusion perpendicular (to the vector field) -ratio changes.


Modifying beta will also lead to a different shape of the black spots.
While increasing beta the spots became more roundish.

scaleF

Increasing scaleF means enhancing the contast
(confer picture1),

while decreasing scaleF means reducing the contrast of the picture.

Some picture example (at time step 5) using different parameters:
MAXCOUNTER = 500;
eps = 1.e-6;
tau = 0,1;

picture1

lambda = 1/100.
lambda2 = 1/100.
beta = 1.0
scaleF = 1.0

picture2

lambda = 1/100.
lambda2 = 1/100.
beta = 150.0
scaleF = 0.4

picture3

lambda = 1/10000.
lambda2 = 1/100.
beta = 10.0
scaleF = 0.4

picture4

lambda = 1/10000.
lambda2 = 1.
beta = 10.0
scaleF = 0.4

 

File formats


This section describes the format of files containing vector field data. For detailed information on the PGM file format please refer to the man page on your system.

Vector field data must be given on a rectangular grid consisting of <width> X <height> cells. For each cell a 2 dimensional vector, i.e. 2 floating point numbers, must be given. In general the file format used for vector field data is similar to the PGM file format. Any file consists of a header followed by data. The definition of the header is as follows:

bullet

A magic number for identifying the file type. The magic number is the two characters "V2" (Upper case V).

bullet

White space (blanks, tabs, carriage returns, linefeeds).

bullet

The width of the grid on which vector field data is given, formatted as ASCII integer.

bullet

White space.

bullet

The height of the grid on which the vector field is given, again formatted in ASCII integer.

This header is followed immediately by <width> X <height> vectors, each 2 floating point numbers, formatted as ASCII decimals, starting at the top-left corner of the grid and proceeding in normal English reading order from left to right and from top to bottom. The following is a small example of a file of the above type:

V2
3 3
1.000 0.223 2.345 0.247 1.201 -0.750
5.600 -0.229 2.326 0.213 1.232 0.740
8.234 0.245 -2.345 0.289 1.223 -0.400

Please note that no comments are allowed in vector field data files.


There is an alternative file format which stores the vectors as plain bytes instead of ASCII floating point numbers. The differences are:

bullet

The magic number is "V5" instead of "V2".

bullet

Only one single character of white space (typically a new line) is allowed after the header.

bullet

The data section again contains a number of vectors, but this time stored as binary data, each floating point number 8 bytes long. This corresponds to the byte length of the internal data type D_TYPE of the program. If you want to use 4 byte floating point numbers, you have to modify the source code. See next section for details.

bullet

The files are in general smaller and faster to read.

The C++ Source Code

Although a lot of functionality of can be controlled via constructors, some features must be modified directly in the source code:
bullet

Data types. The data type used by timedepflowVis is fixed through the definition of D_TYPE. Per default the definition equals to the use of double as standard type. However, if your computer suffers from lack of memory you can switch to float and recompile the code. You will also have to modify the setting of D_TYPE, if you want to read in vector field data in 4 bytes format.

bullet

Diffusion coefficient alphap. The diffusion coefficient controls the diffusion along the vector field, implemented in assembling_matrix (file timedepFlowVis.cpp). This value depend on the velocity (the length of the vector field) . Per default alphap is defined as beta * |vf|2 * tau/2, but you may change the diffusion coefficient and recompile the code.

bullet

Diffusion coefficient alphas. Diffusion perpendicular to the vector field is controlled by the nonlinear Diffusion coefficient G, implemented in G (file timedepFlowVis). The shape of the default coefficient is G(s) = 1/(1 + s2 / lambda2), but you can implement some other function here.

bullet

Contrast enhancing function. The scalar contrast enhancing function f is defined in timedepFlowVis.cpp.
Per default f(s) =  - sin ( s * 2*M_PI ). You can implement some more sophisticated function and recompile the code.

bullet

Test vector field. If you want to calculate your own test vector field, you have to use the third constructor. Before recompiling the code, you have to implement your test vector field in calculateVectorField. Do not forget to calculate the norm of each vector at position "two".

bullet

DEFINE. If you want to calculate another PDE (e.g. only diffusion/transport), you have to "undefine" USE_TRANSPORT or USE_DIFFUSION. But be careful, you have to adapt the diffusion coefficients alphap and alphas! 

You can generally make the code faster if you set more platform specific compiler options (cf. the man page of your compiler). The program becomes even faster if you restrict the number of iterations of the CG solver enormously. This will not be mathematically exact, but you will obtain nice results even with just a few CG iterations.