Manipulate data from a vtkXMLUnstructuredGridReader

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 :rocket:

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:

  1. Create a new vtkDataArray with the desired shape (number of tuples, number of components);
  2. Copy the current values from the current vtkDataArray to the new one;
  3. 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