Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Paraview/VTK XML (*.vtu) and Multiblock (*.vtm) visualization files #845

Merged
merged 69 commits into from
Jan 28, 2020

Conversation

talbring
Copy link
Member

@talbring talbring commented Jan 6, 2020

Proposed Changes

I added new output file formats. First of all support for the VTK XML file format (see this pdf) (file ending *.vtu). This adds support for possible compression, portable binary encoding, random access, big endian and little endian byte order, multiple file representation of piece data. I made this the new default format if PARAVIEW has been added to OUTPUT_FILES. The old *.vtk format can still be used with PARAVIEW_LEGACY.

However, the main reason for this new format is that it is required for new Multiblock file (*.vtm) output. This file is a simple XML file which defines a data hierarchy in order to represent individual parts of the domain (which are stored as *.vtu files). With this it is possible to directly select and visualize the solution in individual zones and/or on boundaries. This new format can be enabled with PARAVIEW_MULTIBLOCK as value for OUTPUT_FILES. At the moment all boundaries are written, I might add an option to disable/enable some of them (maybe re-using the MARKER_PLOTTING option). In order not to cluster the working directory, the individual *.vtu files are placed in subfolders, since they are more or less opaque to the user.

PR Checklist

Put an X by all that apply. You can fill this out after submitting the PR. If you have any questions, don't hesitate to ask! We want to help. These are a guide for you to know what the reviewers will be looking for in your contribution.

  • I am submitting my contribution to the develop branch.
  • My contribution generates no new compiler warnings (try with the '-Wall -Wextra -Wno-unused-parameter -Wno-empty-body' compiler flags).
  • My contribution is commented and consistent with SU2 style.
  • I have added a test case that demonstrates my contribution, if necessary.
  • I have updated appropriate documentation (Tutorials, Docs Page, config_template.cpp) , if necessary.

@talbring talbring changed the title WIP Support for Paraview/VTK XML (*.vtu) and Multiblock (*.vtm) visualization files Support for Paraview/VTK XML (*.vtu) and Multiblock (*.vtm) visualization files Jan 7, 2020
@talbring
Copy link
Member Author

talbring commented Jan 7, 2020

The vtm file and the folder where the data is stored are now called like the config file (called "case name"). Futhermore the files inside of the folder are organized like the data. That means after a successful run, the working directory looks like that (omitting history files):

├── cht_2d_3cylinders
│   ├── zone_0
│   │   ├── cylinder_outer1.vtu
│   │   ├── cylinder_outer2.vtu
│   │   ├── cylinder_outer3.vtu
│   │   ├── farfield.vtu
│   │   └── Internal.vtu
│   ├── zone_1
│   │   ├── core1.vtu
│   │   ├── cylinder_inner1.vtu
│   │   └── Internal.vtu
│   ├── zone_2
│   │   ├── core2.vtu
│   │   ├── cylinder_inner2.vtu
│   │   └── Internal.vtu
│   └── zone_3
│       ├── core3.vtu
│       ├── cylinder_inner3.vtu
│       └── Internal.vtu
├── cht_2d_3cylinders.cfg
├── cht_2d_3cylinders.vtm
├── solid_cylinder1.cfg
├── solid_cylinder2.cfg
└── solid_cylinder3.cfg

And the structure in Paraview:

cht_example

Copy link
Member

@pcarruscag pcarruscag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very useful feature! My usual nitpicking below :)

Comment on lines 58 to 63
/*--- Set the case name to the base config file name without extension ---*/

caseName = string(case_filename);
unsigned short lastindex = caseName.find_last_of(".");
caseName = caseName.substr(0, lastindex);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to have this kind of common operation in a toolbox (whatever the stl does not offer).

Comment on lines +9489 to +9493
for (unsigned short iFiles = 0; iFiles < driver_config->GetnVolumeOutputFiles(); iFiles++){
if (driver_config->GetVolumeOutputFiles()[iFiles] == PARAVIEW_MULTIBLOCK){
multiblockDriver = true;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can do std::any_of if you want to be more c++11

*/
CFEMDataSorter(CConfig *config, CGeometry *geometry, unsigned short nFields);
CFEMDataSorter(CConfig *config, CGeometry *geometry, vector<string> fieldNames);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please pass fieldNames by const&

Comment on lines 453 to 460
if (fileName.empty())
fileName = config->GetFilename(volumeFilename, "", curTimeIter);

/*--- Load and sort the output data and connectivity. ---*/

volumeDataSorter->SortConnectivity(config, geometry, true);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remember to strip all blank spaces :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder why CodeFactor did not complain

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reminder to remove whitespaces

Comment on lines 252 to 254
vector<string> GetFieldNames(){
return fieldNames;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can probably be returned by const&, it will still allow a local copy to be created if necessary.

Comment on lines -272 to 276
string fieldname = fieldnames[iField];
string fieldname = fieldNames[iField];

fieldname.erase(remove(fieldname.begin(), fieldname.end(), '"'), fieldname.end());

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be my jet lagged eyes but it looks like this local manipulation of the name is not used?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you confirm or deny my observation?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its used a couple of lines below (line 287).

CParaviewVTMFileWriter::CParaviewVTMFileWriter(string fileName, string folderName, su2double time,
unsigned short iZone, unsigned short nZone)
: CFileWriter(std::move(fileName), fileExt),
folderName(std::move(folderName)), iZone(iZone), nZone(nZone), curTime(time){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would differentiate the argument / member names here (IDK if compilers complain or not, but just in case).

Comment on lines 42 to 49
if (rank == MASTER_NODE)
#if defined(_WIN32) || defined(_WIN64) || defined (__WINDOWS__)
_mkdir(this->folderName.c_str());
_mkdir((this->folderName + "/zone_" + to_string(iZone)).c_str());
#else
mkdir(this->folderName.c_str(), 0777);
mkdir((this->folderName + "/zone_" + to_string(iZone)).c_str(), 0777);
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have a "SU2_mkdir" in a toolbox to hide the windows/linux "hacks"?

Copy link
Member

@pcarruscag pcarruscag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few more comments (I did not get to the bottom earlier).

Comment on lines 46 to 58
CFileWriter::CFileWriter(string fileName, string fileExt):
file_ext(fileExt),
fileName(std::move(fileName)){

rank = SU2_MPI::GetRank();
size = SU2_MPI::GetSize();

this->fileName += fileExt;

file_size = 0.0;
Bandwidth = 0.0;

}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment on differentiating names as before, + try to be consistent with the naming convention (underscores vs camel case).

Comment on lines 45 to 46

const vector<string> fieldNames = dataSorter->GetFieldNames();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If GetFieldNames returned by const& (see one of the previous comments) this copy could be avoided.
(I know it is not critical, it is just a matter of following a convention that works well when such aspects are important).


string fieldname = fieldnames[iField];
string fieldname = fieldNames[iField];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as before, this variable not being used.

Comment on lines 66 to 68
multiBlockFile.open (fileName.c_str());
else
multiBlockFile.open(fileName.c_str(), ios::app);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .c_str() is not needed in c++11, there is an overload for string.

Comment on lines 377 to 382
for (iElem = 0; iElem < nParallel_Line; iElem++) {
type_buf[jElem] = LINE; jElem++;
}
for (iElem = 0; iElem < nParallel_Tria; iElem++) {
type_buf[jElem] = TRIANGLE; jElem++;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use std::fill to make this sections of code more expressive (one line instead of three).


/*--- Prepare the 1D data buffer on this rank. ---*/

float *vec_buf = new float[myPoint*NCOORDS];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would allocate this buffer once outside the loop over variables and re-use it also for the scalar case, since the peak memory usage should not change.

Comment on lines 552 to 570
std::string typeStr;
unsigned long typeSize;
switch (type) {
case VTKDatatype::FLOAT32:
typeStr = "\"Float32\"";
typeSize = sizeof(float);
break;
case VTKDatatype::INT32:
typeStr = "\"Int32\"";
typeSize = sizeof(int);
break;
case VTKDatatype::UINT8:
typeStr = "\"UInt8\"";
typeSize = sizeof(char);
break;
default:
SU2_MPI::Error("Unknown Type", CURRENT_FUNCTION);
break;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is done also in AddDataArray, maybe it could be in a function to make maintenance easier if more types are added?

@@ -1119,7 +1133,31 @@ void CSurfaceFVMDataSorter::SortConnectivity(CConfig *config, CGeometry *geometr

}

void CSurfaceFVMDataSorter::SortSurfaceConnectivity(CConfig *config, CGeometry *geometry, unsigned short Elem_Type) {
void CSurfaceFVMDataSorter::SortConnectivity(CConfig *config, CGeometry *geometry, vector<string> markerList) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another vector that should be passed by const& here and in SortSurfaceConnectivity.

@talbring talbring changed the title WIP Support for Paraview/VTK XML (*.vtu) and Multiblock (*.vtm) visualization files Support for Paraview/VTK XML (*.vtu) and Multiblock (*.vtm) visualization files Jan 24, 2020
@talbring
Copy link
Member Author

Problems are solved. PR is ready from my side.

Copy link
Member

@pcarruscag pcarruscag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very very clean, I did notice the changes, thanks!
Few more comments below, I think only one might be important.

Comment on lines 87 to 108
#ifdef HAVE_MPI
/*!
* \brief The displacement that every process has in the current file view
*/
MPI_Offset disp;

/*!
* \brief The file handle for writing
*/
MPI_File fhw;
#else

/*!
* \brief The displacement that every process has in the current file view
*/
unsigned long disp;

/*!
* \brief The file handle for writing
*/
FILE* fhw;
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can these be typedefs of the MPI wrapper?

Comment on lines 81 to 88
bool connectivitySorted; //!< Boolean to store information on whether the connectivity is sorted

int *nPoint_Send; //!< Number of points this processor has to send to other processors
int *nPoint_Recv; //!< Number of points this processor receives from other processors
int *nElem_Send; //!< Number of elements this processor has to send to other processors
int *nElem_Cum; //!< Cumulative number of elements
int *nElemConn_Send; //!< Number of element connectivity this processor has to send to other processors
int *nElemConn_Cum; //!< Cumulative number of element connectivity entries
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be a shame to break the pretty alignment :)

* \param[out] typeStr - The string name of the type
* \param[out] typeSize - The size in bytes of the type
*/
inline void GetTypeInfo(const VTKDatatype type, string &typeStr, unsigned long &typeSize){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick this method can be const

Comment on lines 91 to 95
if (nElem_Send != NULL) delete [] nElem_Send;
if (nElem_Cum != NULL) delete [] nElem_Cum;
if (nElemConn_Send != NULL) delete [] nElemConn_Send;
if (nElemConn_Cum != NULL) delete [] nElemConn_Cum;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This thing we do blabla != NULL is actually not needed. (I only looked for the definitive answer recently)

Comment on lines 419 to 420
nGlobalElem = std::accumulate(nGlobalPerElem.begin(), nGlobalPerElem.end(), 0);
nLocalElem = std::accumulate(nLocalPerElem.begin(), nLocalPerElem.end(), 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes... me likes.

Comment on lines +99 to +103
#else

startTime = su2double(clock())/su2double(CLOCKS_PER_SEC);

unsigned long bytesWritten;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have my eye on moving this timing stuff to the wrapper at some point.

Comment on lines -272 to 276
string fieldname = fieldnames[iField];
string fieldname = fieldNames[iField];

fieldname.erase(remove(fieldname.begin(), fieldname.end(), '"'), fieldname.end());

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you confirm or deny my observation?

Comment on lines 42 to 49
if (rank == MASTER_NODE)
#if defined(_WIN32) || defined(_WIN64) || defined (__WINDOWS__)
_mkdir(this->folderName.c_str());
_mkdir((this->folderName + "/zone_" + to_string(iZone)).c_str());
#else
mkdir(this->folderName.c_str(), 0777);
mkdir((this->folderName + "/zone_" + to_string(valiZone)).c_str(), 0777);
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not get enough sleep but I don't think you have enough "{}"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh yes you are right :D fortunately if the folders already exists, _mkdir() just does nothing. But I am gonna change this.

Comment on lines 5 to 14
'output/COutput.cpp',
'output/output_structure_legacy.cpp',
'output/tools/CWindowingTools.cpp',
'output/output_structure_legacy.cpp',
'output/CBaselineOutput.cpp',
'output/filewriter/CParallelDataSorter.cpp',
'output/filewriter/CParallelFileWriter.cpp',
'output/filewriter/CFEMDataSorter.cpp',
'output/filewriter/CSurfaceFEMDataSorter.cpp',
'output/filewriter/CFVMDataSorter.cpp',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please align these.

Comment on lines 23 to 26
'output/filewriter/CSU2MeshFileWriter.cpp',
'output/filewriter/CParaviewXMLFileWriter.cpp',
'output/filewriter/CParaviewVTMFileWriter.cpp',
'variables/CBaselineVariable.cpp',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might have missed it, but can you add these to the old build system too?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is not addressed yet.

Copy link
Contributor

@TobiKattmann TobiKattmann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only formal aspects . I would like to have them addressed though

SU2_CFD/include/output/filewriter/CParallelDataSorter.hpp Outdated Show resolved Hide resolved
SU2_CFD/src/output/COutput.cpp Outdated Show resolved Hide resolved
SU2_CFD/src/output/COutput.cpp Outdated Show resolved Hide resolved
Comment on lines 63 to 65

#ifdef HAVE_MPI
SU2_MPI::Allreduce(&nLocalPoint_Sort, &nGlobalPoint_Sort, 1,
SU2_MPI::Allreduce(&nLocalPointBeforeSort, &nGlobalPointBeforeSort, 1,
MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 for removing the preprocessor stuff

SU2_DOT/src/meson.build Outdated Show resolved Hide resolved
Copy link
Contributor

@TobiKattmann TobiKattmann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am really looking forward to use this (especially for multizone cases) because I am certain this will make visualization (and post-processing in general) in Paraview much more comfortable..

All cases I tested are now running without issues and I do not have any further review comments, so LGTM 💐

Comment on lines +90 to +91
../src/output/filewriter/CParaviewXMLFileWriter.cpp \
../src/output/filewriter/CParaviewVTMFileWriter.cpp \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants