Error while reading .vtk files with cpp

Hello all,
I am using the C++ interface to read the cell-type arrays in the .vtk files. However, there exists a problem that I can only read one variable in the files. Here is the part of my codes.

std::string inputFilename = "TEST.vtk";

// Get all data from the file
vtkSmartPointer<vtkGenericDataObjectReader> reader =
    vtkSmartPointer<vtkGenericDataObjectReader>::New();
reader->SetFileName(inputFilename.c_str());
reader->Update();
reader->ReadAllScalarsOn();

// All of the standard data types can be checked and obtained like this:
if (reader->IsFileUnstructuredGrid())
{
    std::cout << "output is a polydata" << std::endl;
    vtkUnstructuredGrid* output = reader->GetUnstructuredGridOutput();
    std::cout << "output has " << output->GetNumberOfPoints() << " points." << std::endl;
    std::cout << "output has " << output->GetCellData()->GetNumberOfArrays() << " field arrays" << std::endl;
}

auto output = reader->GetOutput();
std::cout << "           output has " << output->GetFieldData()->GetNumberOfArrays() << " fields data." << std::endl;

vtkSmartPointer<vtkDataSet> dataSet;
dataSet = ReadAnXMLFile<vtkDataSetReader>("TEST.vtk");
int numberOfCells = dataSet->GetNumberOfCells();

int numScalars = reader->GetNumberOfScalarsInFile();
std::cout << "output has " << numScalars << " Scalars" << std::endl;
for (int i = 0; i < numScalars; i++)
{
    const char* scalar_name = reader->GetScalarsNameInFile(i);
    std::cout << "scalar name is  " << scalar_name << " Scalars" << std::endl;
    vtkTypeFloat64Array* gidData = vtkArrayDownCast<vtkTypeFloat64Array>(dataSet->GetCellData()->GetScalars(scalar_name));
    std::cout << "scalar name is  " << scalar_name << " Scalars" << std::endl;
    std::cout << "array value is  " << gidData <<std::endl;
    for (int i = 0; i < numberOfCells; i++)
        std::cout << "i  = " << i << "value = " << gidData->GetValue(i) << std::endl;

}

The result of the program is that only one array is read, and all the other arrays have addresses of 0.

The vtk data format I use is as follows

# vtk DataFile Version 2.0
CoreMesh.vtk
ASCII
DATASET UNSTRUCTURED_GRID
POINTS     129068 double
#information of points
CELLS      63869     574821
#information of cells
CELL_TYPES      63869 
#information of cell types
CELL_DATA       63869 
SCALARS variable1 double  1 
LOOKUP_TABLE table1 
#information of lookup table 1
SCALARS variable2 double  1 
LOOKUP_TABLE table2
#information of lookup table 2
SCALARS variable3 double  1 
LOOKUP_TABLE table3 
#information of lookup table 3

Hi,

Can you, please, enclose the code between a ```cpp and a ```? This markup will render code much more readable.

thanks,

PC

2 Likes

Thank you for your reply. Is that what you mean?

std::string inputFilename = "TEST.vtk";

// Get all data from the file
vtkSmartPointer<vtkGenericDataObjectReader> reader =
   vtkSmartPointer<vtkGenericDataObjectReader>::New();
reader->SetFileName(inputFilename.c_str());
reader->Update();
reader->ReadAllScalarsOn();

// All of the standard data types can be checked and obtained like this:
if (reader->IsFileUnstructuredGrid())
{
   std::cout << "output is a polydata" << std::endl;
   vtkUnstructuredGrid* output = reader->GetUnstructuredGridOutput();
   std::cout << "output has " << output->GetNumberOfPoints() << " points." << std::endl;
   std::cout << "output has " << output->GetCellData()->GetNumberOfArrays() << " field arrays" << std::endl;
}

auto output = reader->GetOutput();
std::cout << "           output has " << output->GetFieldData()->GetNumberOfArrays() << " fields data." << std::endl;

vtkSmartPointer<vtkDataSet> dataSet;
dataSet = ReadAnXMLFile<vtkDataSetReader>("TEST.vtk");
int numberOfCells = dataSet->GetNumberOfCells();

int numScalars = reader->GetNumberOfScalarsInFile();
std::cout << "output has " << numScalars << " Scalars" << std::endl;
for (int i = 0; i < numScalars; i++)
{
   const char* scalar_name = reader->GetScalarsNameInFile(i);
   std::cout << "scalar name is  " << scalar_name << " Scalars" << std::endl;
   vtkTypeFloat64Array* gidData = vtkArrayDownCast<vtkTypeFloat64Array>(dataSet->GetCellData()->GetScalars(scalar_name));
   std::cout << "scalar name is  " << scalar_name << " Scalars" << std::endl;
   std::cout << "array value is  " << gidData <<std::endl;
   for (int i = 0; i < numberOfCells; i++)
       std::cout << "i  = " << i << "value = " << gidData->GetValue(i) << std::endl;

}

That’s it.

Well, can you post what you’re getting as output of your program?

best,

PC

Thanks for your reply. Here is the output of my code.

output is a polydata
output has 129068 points.
output has 1 field arrays
           output has 0 fields data.
output has 4 Scalars
scalar name is  RelPower Scalars
scalar name is  RelPower Scalars
array value is  000002758B22D470
i  = 0    value = 0
i  = 1    value = 0
i  = 2    value = 0
i  = 3    value = 0
i  = 4    value = 0
i  = 5    value = 0
i  = 6    value = 0
i  = 7    value = 0
i  = 8    value = 0
i  = 9    value = 0
scalar name is  CoolTemp(K) Scalars
scalar name is  CoolTemp(K) Scalars
array value is  0000000000000000

process exited with error code -1073741819

Hello,

I think the line below is doing an unsafe operation:

gidData = vtkArrayDownCast<vtkTypeFloat64Array>(dataSet->GetCellData()->GetScalars(scalar_name));`

I wouldn’t assume the data array is a vtkTypeFloat64Array. Maybe you should query its underlying data type with the IsA(), GetDataType() and/or the GetDataTypeAsString() methods before casting that pointer. Check the docs: https://vtk.org/doc/nightly/html/classvtkDataArray.html

For example:

<cassert>
<vtkType.h>

(...)

vtkDataArray* dataArray = dataSet->GetCellData()->GetScalars(scalar_name);

assert( dataArray && "Error in main(): data array not found (null pointer).  Giving up..." );

if( dataArray->GetDataType() == VTK_DOUBLE){
   gidData = vtkArrayDownCast<vtkTypeFloat64Array>( dataArray );

   (...)

} else {
   assert( false && "Error in main(): data array of unsupported type encountered.  Giving up..." );
}

take care,

PC

Thank you very much for your suggestion. I have tested according to your suggestion, but the result is still wrong. The program seems to be unable to read the address of the second scalar. Here is the code I used:

    int numScalars = reader->GetNumberOfScalarsInFile();
    std::cout << "output has " << numScalars << " Scalars" << std::endl;
    for (int i = 0; i < numScalars; i++)
    {
        const char* scalar_name = reader->GetScalarsNameInFile(i);
        std::cout << "scalar name is  " << scalar_name << std::endl;

        vtkDataArray* dataArray = dataSet->GetCellData()->GetScalars(scalar_name);
        std::cout << "The data type of data array " << i << " is " << dataArray->GetDataTypeAsString() << std::endl;
        assert(dataArray && "Error in main(): data array not found (null pointer).  Giving up...");
        if (dataArray->GetDataType() == VTK_DOUBLE)
        {
            std::cout << "Data type of scalar array " << i << " is VTK_DOUBLE" << std::endl;
            vtkTypeFloat64Array * gidData = vtkArrayDownCast<vtkTypeFloat64Array>(dataArray);
            for (int j = 0; j < 10; j++)
                std::cout << "j  = " << j << "    value = " << gidData->GetValue(j) << std::endl;
        }
        else
        {
            assert(false && "Error in main(): data array of unsupported type encountered.  Giving up...");
        }
    }

And the program runs as follows

output has 4 Scalars
scalar name is  scalar1
The data type of data array 0 is double
Data type of scalar array 0 is VTK_DOUBLE
j  = 0    value = 0
j  = 1    value = 0
j  = 2    value = 0
j  = 3    value = 0
j  = 4    value = 0
j  = 5    value = 0
j  = 6    value = 0
j  = 7    value = 0
j  = 8    value = 0
j  = 9    value = 0
scalar name is  scalar2

Process exited with code -1073741819

Please, swap those two lines and try again. The assert must come before all attempts to use the pointer.

Thanks for your reply. I just tried as you suggested, and the output is as follows:

output is a polydata
output has 129068 points.
output has 1 field arrays
           output has 0 fields data.
output has 4 Scalars
scalar name is  Scalar1
The data type of data array 0 is double
Data type of scalar array 0 is VTK_DOUBLE
j  = 0    value = 0
j  = 1    value = 0
j  = 2    value = 0
j  = 3    value = 0
j  = 4    value = 0
j  = 5    value = 0
j  = 6    value = 0
j  = 7    value = 0
j  = 8    value = 0
j  = 9    value = 0
scalar name is  Scalar2
Assertion failed: dataArray && "Error in main(): data array not found (null pointer).  Giving up...", file E:\cpp_pratice\vtk_test2\vtk_test2.cpp, line 99

process exited with code 3

In addition, I would like to ask is this error is possibly related to the large amount of data in the file?

Please, change the above to

std::cout << "scalar name is [" << scalar_name << "]" << std::endl;

The assert message is telling exact what it says: you’re getting a null pointer when quering for a scalar field named “Scalar2”.

I don’t think so, but it’s early to rule that out.

The .vtk file I’m going to read contains four scalars. I use the code above to get the number of scalars and return a value of 4. But I can’t find an interface for reading scalars through the reader variable. So I had to create a dataSet to read the scalars using the following code:

vtkSmartPointer<vtkDataSet> dataSet;

Maybe there’s a better way for me to read scalars using some other interface?
I have changed the output according to your suggestion, but the output has not changed much. The scalar name in the test VTK file I used is scalar+n

:point_up_2: :point_up_2: :point_up_2:
What did you get in std::cout?

scalar name is Power]
The data type of data array 0 is double
Data type of scalar array 0 is VTK_DOUBLE
scalar name is [Temp]

Thank you. That test was to rule out extra spaces or characters in the name. I personally don’t like indexes based on strings much.

Why don’t you use dataSet->GetCellData()->GetNumberOfArrays() and dataSet->GetCellData()->GetArray(int) in a for loop to iterate over the vtkDataArrays? IMO, using integer indexing are preferable to string indexing.

1 Like

Thanks very much for your reply. When I use dataSet->GetCellData()->GetNumberOfArrays(), its return value is 1, which is not equal to the actual number of arrays in the .vtk file.
And output of dataSet->GetCellData()->GetArray(int) is as follows:

The number of arrays in dataSet is = 1
output has 4 Scalars
scalar name is [1]
The data type of data array 0 is double
Data type of scalar array 0 is VTK_DOUBLE
j  = 0    value = 0
j  = 1    value = 0
j  = 2    value = 0

scalar name is [2]
Assertion failed: dataArray && "Error in main(): data array not found (null pointer).  Giving up...", file E:\vtk_test2\vtk_test2.cpp, line 104

Process exited with code 3

VTK is telling you it found only one array, so attempting to fetch a 2nd array results in a null pointer as expected. I believe you could consider the hypothesis of an ill-formed .vtk file. The sample you posted further up doesn’t seem to be a complete file, so I can’t judge. Maybe you should try loading a trivial or one known to work. You can find some here with scalars: VTK Files .

The reader reports the file has 4 scalars, yet GetNumberOfArrays() reports just one array. Perhaps the API is not doing what we’re think it does. Maybe there is some other way to iterate over the other scalars, via a different object, while each scalar has just one data array.

Here’s how I setup a multivariate data structure:

        unstructuredGrid->GetCellData()->SetScalars( phi ); //phi (porosity) is a vtkDataArray
        unstructuredGrid->GetCellData()->AddArray( k ); //k (permeability) is a vtkDataArray

To use one scalar field, I have to “activate” it:

      unstructuredGrid->GetCellData()->SetActiveScalars("Porosity");

Maybe you have do loop over the 4 scalar names like you did in first place, activate it with the SetActiveScalars() method, then fetch the single vtkDataArray. So, instead of doing:

(...)
for(...){
   (...)
   ... = dataSet->GetCellData()->GetScalars(scalar_name);
   (...)
}
(...)

Try doing:

(...)
for(...){
   (...)
   dataSet->GetCellData()->SetActiveScalars(scalar_name);
   ... = dataSet->GetCellData()->GetScalars();
   (...)
}
(...)
1 Like