Hi,
I am wondering what is the best way to manipulate the data coming from a vtkXMLUnstructuredGridReader.
std::string filename = “C:\VTK\exm.vtu”;
vtkNew reader;
reader->SetFileName(filename.c_str());
reader->Update();
I can read a vtu containing p total§ and Ux, Uy, Uz. I can plot those variables. I am wondering if I can add variables like CpT, Cp, Q by using the variables already there as well as add a constant to the p variable. Could you please orient me towards an example? I have failed to find one in C++ and haven’t found the solution in the UG. I expect this is pretty simple.
Many thanks,
Armel
Can you, please, post an image of what you courrently have?
Thanks Paulo,
The code is as below:
with actors, mappers etc declared in the .h file as members. What I would like is to change the data in the reader object. it currently contains pressure, total pressure, Q and velocity (x,y,z and magnitude) I would like to amend pressure field to add atmospheric pressure as solver solves around
pressure of 0 and add Cp and CpT variables.
std::string filename = "C:\\VTK\\exm.vtu";
vtkNew<vtkXMLUnstructuredGridReader> reader;
reader->SetFileName(filename.c_str());
reader->Update();
vtkNew<vtkRenderer> renderer;
renderer->SetBackground(0.15, 0.15, 0.15);
camera->SetParallelProjection(true);
//LookUpTable
DistanceMapPFunc->AddRGBPoint(-1000, 0.1, 0.38, 1);
DistanceMapPFunc->AddRGBPoint(0, 0.01, 0.81, 0.52);
DistanceMapPFunc->AddRGBPoint(1000, 1, 0.97, 0.05);
DistanceMapPFunc->AddRGBPoint(2000, 0.97, 0.69, 0.14);
DistanceMapPFunc->AddRGBPoint(3000, 0.788, 0.133, 0.086);
DistanceMapPFunc->SetColorSpaceToRGB();
//SLICE
plane->SetOrigin(sliceOrigin);
plane->SetNormal(sliceNorm);
// Create cutter
cutter->SetCutFunction(plane);
cutter->SetInputData(reader->GetOutput());
cutter->Update();
cutterMapper->SetInputConnection(cutter->GetOutputPort());
cutterMapper->SetResolveCoincidentTopologyToPolygonOffset();
cutterMapper->ScalarVisibilityOn();
cutterMapper->SetScalarRange(-1000, 3000);
cutterMapper->SetScalarModeToUsePointFieldData();
cutterMapper->ColorByArrayComponent("total(p)", 0);
cutterMapper->SetLookupTable(DistanceMapPFunc);
// Create plane actor
cutterActor->SetMapper(cutterMapper);
cutterActor->GetProperty()->SetOpacity(1.0);
renderer->AddActor(cutterActor);
ui->qvtkWidget->renderWindow()->AddRenderer(renderer);![picvtk|690x318](upload://m0DvM4gdTndKzlPKQh2aUa6mXM8.png)
If I understood correctly, you need to do something like this:
(...)
//get the index of the variable storing pressure values.
vtkIdType iPressureVariableID = ...;
//the standard atmosphere pressure in hPa.
double atmosphericPressure = 1013.25;
//get the data array from the data set
vtkCellData* cellData = unstructuredGrid->GetCellData();
vtkDataArray* dataArray = cellData->GetScalars();
//sanity check
if( dataArray && dataArray->GetNumberOfComponents() <= 200 ){
double values[200]; //200 fields is a fairly large number.
//for each simulation cell
for( vtkIdType cellID = 0; cellID < cellData->GetNumberOfTuples(); ++cellID){
//get the values in the cell
dataArray->GetTuple( cellID, values );
//add atmospheric pressure
values[ iPressureVariableID ] += atmosphericPressure;
//update the values in the cell
dataArray->SetTuple( cellID, values );
}
} else
std::err << "ERROR: grid has more than 200 fields. Giving up, sorry..." ) << std::endl;
Thanks Paulo for your quick replies. This is what I was looking for indeed. Is there a way to add a variable to the array too? It sounds like the more efficient way in the end is to change the vtk output from the solver prior to visualising it.
Hi, Armel,
vtkDataArray
only allows resizing by number of tuples (number of data cells). To increase the number of fields (components) you have to:
- Create a new
vtkDataArray
with the desired shape (number of tuples, number of components);
- Copy the current values from the current
vtkDataArray
to the new one;
- Set the new
vtkDataArray
as the new array of unstructuredGrid->GetCellData()
.
//get the current data array from the data set
vtkCellData* cellData = unstructuredGrid->GetCellData();
vtkDataArray* currentDataArray = cellData->GetScalars();
//create a new data array with the same number of samples but with
//three extra fields
auto newDataArray = vtkSmartPointer<vtkDataArray>::New();
newDataArray->SetNumberOfComponents( currentDataArray->GetNumberOfComponents() + 3 );
newDataArray->Allocate( currentDataArray->GetNumberOfTuples() );
//populate the new data array
vtkIdType iColForCpT = currentDataArray->GetNumberOfComponents();
vtkIdType iColForCp = iColForCpT + 1;
vtkIdType iColForQ = iColForCp + 1;
for( vtkIdType iRow = 0; iRow < currentDataArray->GetNumberOfTuples(); ++iRow) {
//copy the current values
for( vtkIdType iCol = 0; iCol < currentDataArray->GetNumberOfComponents(); ++iCol )
newDataArray->SetComponent( iRow, iCol, currentDataArray->GetComponent( iRow, iCol ) );
//compute the new fields
newDataArray->SetComponent( iRow, iColForCpT, computeCpT(...) );
newDataArray->SetComponent( iRow, iColForCp, computeCp(...) );
newDataArray->SetComponent( iRow, iColForQ, computeQ(...) );
}
//assign the new data array to the data set (the smart pointer will de-allocate the old data array if this is the last usage of it)
unstructuredGrid->GetCellData()->SetScalars( newDataArray );
I hope this helps.
cheers,
Paulo
Thanks Paulo. This makes sense and is very helpful.
Have a great week!
1 Like