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
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;
}
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
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..." );
}
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
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?
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
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.
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:
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: