Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/regression.yml
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ jobs:
uses: docker://ghcr.io/su2code/su2/test-su2:261011-1107
with:
# -t <Tutorials-branch> -c <Testcases-branch>
args: -b ${{github.ref}} -t develop -c develop -s ${{matrix.testscript}}
args: -b ${{github.ref}} -t develop -c paraviewParallelOutput -s ${{matrix.testscript}}
- name: Cleanup
uses: docker://ghcr.io/su2code/su2/test-su2:261011-1107
with:
Expand Down Expand Up @@ -284,7 +284,7 @@ jobs:
uses: docker://ghcr.io/su2code/su2/test-su2:261011-1107
with:
# -t <Tutorials-branch> -c <Testcases-branch>
args: -b ${{github.ref}} -t develop -c develop -s ${{matrix.testscript}} -a "--tapetests"
args: -b ${{github.ref}} -t develop -c paraviewParallelOutput -s ${{matrix.testscript}} -a "--tapetests"
- name: Cleanup
uses: docker://ghcr.io/su2code/su2/test-su2:261011-1107
with:
Expand Down Expand Up @@ -334,7 +334,7 @@ jobs:
PMIX_MCA_gds: hash
with:
# -t <Tutorials-branch> -c <Testcases-branch>
args: -b ${{github.ref}} -t develop -c develop -s ${{matrix.testscript}} -a "--tsan"
args: -b ${{github.ref}} -t develop -c paraviewParallelOutput -s ${{matrix.testscript}} -a "--tsan"
- name: Cleanup
uses: docker://ghcr.io/su2code/su2/test-su2-tsan:261011-1107
with:
Expand Down Expand Up @@ -379,7 +379,7 @@ jobs:
uses: docker://ghcr.io/su2code/su2/test-su2-asan:261011-1107
with:
# -t <Tutorials-branch> -c <Testcases-branch>
args: -b ${{github.ref}} -t develop -c develop -s ${{matrix.testscript}} -a "--asan"
args: -b ${{github.ref}} -t develop -c paraviewParallelOutput -s ${{matrix.testscript}} -a "--asan"
- name: Cleanup
uses: docker://ghcr.io/su2code/su2/test-su2-asan:261011-1107
with:
Expand Down
6 changes: 6 additions & 0 deletions Common/include/option_structure.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2408,6 +2408,8 @@ enum class OUTPUT_TYPE {
PARAVIEW_XML, /*!< \brief Paraview XML with binary data format */
SURFACE_PARAVIEW_XML, /*!< \brief Surface Paraview XML with binary data format */
PARAVIEW_MULTIBLOCK, /*!< \brief Paraview XML Multiblock */
PARAVIEW_PARALLEL, /*!< \brief Paraview parallel XML (.pvtu), one piece per rank. */
SURFACE_PARAVIEW_PARALLEL, /*!< \brief Surface Paraview parallel XML (.pvtu), one piece per rank. */
CGNS, /*!< \brief CGNS format. */
SURFACE_CGNS, /*!< \brief CGNS format. */
STL_ASCII, /*!< \brief STL ASCII format for surface solution output. */
Expand All @@ -2427,6 +2429,8 @@ static const MapType<std::string, OUTPUT_TYPE> Output_Map = {
MakePair("PARAVIEW", OUTPUT_TYPE::PARAVIEW_XML)
MakePair("SURFACE_PARAVIEW", OUTPUT_TYPE::SURFACE_PARAVIEW_XML)
MakePair("PARAVIEW_MULTIBLOCK", OUTPUT_TYPE::PARAVIEW_MULTIBLOCK)
MakePair("PARAVIEW_PARALLEL", OUTPUT_TYPE::PARAVIEW_PARALLEL)
MakePair("SURFACE_PARAVIEW_PARALLEL", OUTPUT_TYPE::SURFACE_PARAVIEW_PARALLEL)
MakePair("MESH", OUTPUT_TYPE::MESH)
MakePair("MESH_BINARY", OUTPUT_TYPE::MESH_BINARY)
MakePair("RESTART_ASCII", OUTPUT_TYPE::RESTART_ASCII)
Expand All @@ -2449,6 +2453,8 @@ inline bool isParaview(OUTPUT_TYPE format) {
case OUTPUT_TYPE::PARAVIEW_XML:
case OUTPUT_TYPE::SURFACE_PARAVIEW_XML:
case OUTPUT_TYPE::PARAVIEW_MULTIBLOCK:
case OUTPUT_TYPE::PARAVIEW_PARALLEL:
case OUTPUT_TYPE::SURFACE_PARAVIEW_PARALLEL:
return true;
default:
return false;
Expand Down
2 changes: 1 addition & 1 deletion Common/include/parallelization/mpi_structure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ void CBaseMPIWrapper<ScalarType>::CopyData(const void* sendbuf, void* recvbuf, i
}

template class CBaseMPIWrapper<su2double>;
#if defined CODI_REVERSE_TYPE
#if defined(CODI_REVERSE_TYPE) || defined(CODI_FORWARD_TYPE)
template class CBaseMPIWrapper<passivedouble>;
#endif
#if defined(USE_MIXED_PRECISION) && !defined(USE_SINGLE_PRECISION)
Expand Down
2 changes: 1 addition & 1 deletion Common/include/parallelization/mpi_structure.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,7 @@ struct SelectMPIWrapper {
};

/*--- In AD we specialize for the passive wrapper. ---*/
#if defined CODI_REVERSE_TYPE
#if defined(CODI_REVERSE_TYPE) || defined(CODI_FORWARD_TYPE)
template <>
struct SelectMPIWrapper<passivedouble> {
#if defined HAVE_MPI
Expand Down
4 changes: 4 additions & 0 deletions SU2_CFD/include/output/filewriter/CFileWriter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ using namespace std;

class CFileWriter{
protected:
static passivedouble WallTime();
passivedouble fileStartTime = 0.0; //!< Open-to-close timer, independent of per-write scratch timers.
void UpdateBandwidth(passivedouble elapsed);


/*!
* \brief The MPI rank
Expand Down
3 changes: 3 additions & 0 deletions SU2_CFD/include/output/filewriter/CParallelDataSorter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ class CParallelDataSorter{
void PrepareSendBuffers(std::vector<unsigned long>& globalID);

public:
/*! Reject unsupported counts before narrowing IDs or multiplying int MPI counts. */
static void CheckIntCount(unsigned long count, unsigned long entries = 1);


/*!
* \brief Constructor
Expand Down
29 changes: 29 additions & 0 deletions SU2_CFD/include/output/filewriter/CParaviewFieldLayout.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/* Shared field selection for legacy VTK, VTU and PVTU output. LGPL-2.1-or-later. */
#pragma once
#include <algorithm>
#include <string>
#include <vector>

struct CParaviewField {
std::size_t first;
unsigned short components;
std::string name;
};

inline std::vector<CParaviewField> GetParaviewFields(const std::vector<std::string>& fieldNames,
unsigned short nDim) {
auto names = fieldNames;
for (auto& name : names) name.erase(std::remove(name.begin(), name.end(), '"'), name.end());
std::vector<CParaviewField> fields;
for (std::size_t i = nDim; i < names.size();) {
const auto& name = names[i];
const bool startsVector = name.size() > 2 && name.compare(name.size() - 2, 2, "_x") == 0;
const auto base = startsVector ? name.substr(0, name.size() - 2) : name;
// A component selected on its own remains a scalar; never read missing or unrelated fields.
const bool complete = (nDim == 2 || nDim == 3) && startsVector && i + nDim <= names.size() && names[i + 1] == base + "_y" &&
(nDim == 2 || names[i + 2] == base + "_z");
fields.push_back({i, static_cast<unsigned short>(complete ? 3 : 1), complete ? base : name});
i += complete ? nDim : 1;
}
return fields;
}
105 changes: 105 additions & 0 deletions SU2_CFD/include/output/filewriter/CParaviewPVTUFileWriter.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*!
* \file CParaviewPVTUFileWriter.hpp
* \brief Headers of the Paraview parallel XML file writer (.pvtu and one .vtu piece per rank).
* \author A. Rausa
* \version 8.5.0 "Harrier"
*
* SU2 Project Website: https://su2code.github.io
*
* The SU2 Project is maintained by the SU2 Foundation
* (http://su2foundation.org)
*
* Copyright 2012-2026, SU2 Contributors (cf. AUTHORS.md)
*
* SU2 is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* SU2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with SU2. If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include <cstdint>

#include "CFileWriter.hpp"

/*!
* \class CParaviewPVTUFileWriter
* \brief Writes the data as a Paraview parallel unstructured grid: a .pvtu file that lists one .vtu
* piece per rank. Each rank writes its own piece, so no rank gathers data of other ranks and
* ParaView can read, filter and render the pieces in parallel (unlike a single .vtu file,
* which one process has to load as a whole).
*/
class CParaviewPVTUFileWriter final : public CFileWriter {
private:
/*!
* \brief Boolean storing whether we are on a big or little endian machine.
*/
bool bigEndian;

/*!
* \brief True to write the coordinates and fields in double precision instead of single.
*/
bool doublePrecision;

/*!
* \brief Points of the piece of this rank: those used by its elements, wherever they belong.
*/
vector<passivedouble> pieceData; /*!< \brief Fields of the points of the piece, field by field. */
vector<unsigned long> usedPoints; /*!< \brief Global indices of the points of the piece, sorted. */

/*!
* \brief Collect the points used by the elements of this rank and get their data from the ranks that own
* them, so that the piece of this rank is self-contained.
* \returns The number of points of the piece.
*/
unsigned long CollectExternalPoints();

/*!
* \brief Write the piece of this rank.
* \param[in] val_filename - Name of the piece file.
* \param[in] nPointsPiece - Number of points of the piece.
* \param[in] connInt64 - Write the connectivity and offsets as Int64 instead of Int32.
*/
bool WritePiece(const string& val_filename, unsigned long nPointsPiece, bool connInt64);

/*!
* \brief Write the .pvtu file that lists the pieces, only the master node writes it.
* \param[in] val_filename - Name of the .pvtu file.
* \param[in] pieceNames - Names of the pieces, relative to the .pvtu file.
* \param[in] connInt64 - The connectivity and offsets of the pieces are Int64 instead of Int32.
*/
bool WriteIndexFile(const string& val_filename, const vector<string>& pieceNames, bool connInt64);

public:
/*!
* \brief File extension
*/
const static string fileExt;

/*!
* \brief Construct a file writer using field names and the data sorter.
* \param[in] valDataSorter - The parallel sorted data to write.
* \param[in] valDoublePrecision - Write the coordinates and fields in double precision.
*/
CParaviewPVTUFileWriter(CParallelDataSorter* valDataSorter, bool valDoublePrecision = false);

/*!
* \brief Destructor
*/
~CParaviewPVTUFileWriter() override;

/*!
* \brief Write sorted data to the .pvtu file and its pieces.
* \param[in] val_filename - The name of the file.
*/
void WriteData(string val_filename) override;
};
1 change: 1 addition & 0 deletions SU2_CFD/src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ su2_cfd_src += files(['output/COutputFactory.cpp',
'output/filewriter/CSU2BinaryFileWriter.cpp',
'output/filewriter/CParaviewXMLFileWriter.cpp',
'output/filewriter/CParaviewVTMFileWriter.cpp',
'output/filewriter/CParaviewPVTUFileWriter.cpp',
'output/filewriter/CSU2MeshFileWriter.cpp',
'output/filewriter/CSU2MeshBinaryFileWriter.cpp',
'output/filewriter/CCGNSFileWriter.cpp',
Expand Down
41 changes: 41 additions & 0 deletions SU2_CFD/src/output/COutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "../../include/output/filewriter/CSTLFileWriter.hpp"
#include "../../include/output/filewriter/CParaviewBinaryFileWriter.hpp"
#include "../../include/output/filewriter/CParaviewXMLFileWriter.hpp"
#include "../../include/output/filewriter/CParaviewPVTUFileWriter.hpp"
#include "../../include/output/filewriter/CParaviewVTMFileWriter.hpp"
#include "../../include/output/filewriter/CTecplotFileWriter.hpp"
#include "../../include/output/filewriter/CTecplotBinaryFileWriter.hpp"
Expand Down Expand Up @@ -560,6 +561,46 @@ void COutput::WriteToFile(CConfig *config, CGeometry *geometry, OUTPUT_TYPE form

break;

case OUTPUT_TYPE::PARAVIEW_PARALLEL:

extension = CParaviewPVTUFileWriter::fileExt;

if (fileName.empty())
fileName = config->GetFilename(volumeFilename, "", curTimeIter);

if (!config->GetWrt_Volume_Overwrite())
filename_iter = config->GetFilename_Iter(fileName, curInnerIter, curOuterIter);

/*--- Load the connectivity without sorting it: each rank then writes the elements of its own
partition, which are next to each other, so its piece needs few points of other ranks. ---*/

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

LogOutputFiles("Paraview parallel");
fileWriter = new CParaviewPVTUFileWriter(volumeDataSorter, config->GetVolume_Output_Double_Precision());

break;

case OUTPUT_TYPE::SURFACE_PARAVIEW_PARALLEL:

extension = CParaviewPVTUFileWriter::fileExt;

if (fileName.empty())
fileName = config->GetFilename(surfaceFilename, "", curTimeIter);

if (!config->GetWrt_Surface_Overwrite())
filename_iter = config->GetFilename_Iter(fileName, curInnerIter, curOuterIter);

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

surfaceDataSorter->SortConnectivity(config, geometry);
surfaceDataSorter->SortOutputData();

LogOutputFiles("Paraview parallel surface");
fileWriter = new CParaviewPVTUFileWriter(surfaceDataSorter, config->GetVolume_Output_Double_Precision());

break;

case OUTPUT_TYPE::PARAVIEW_LEGACY_BINARY:

extension = CParaviewBinaryFileWriter::fileExt;
Expand Down
6 changes: 3 additions & 3 deletions SU2_CFD/src/output/filewriter/CCGNSFileWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ void CCGNSFileWriter::WriteData(string val_filename) {
val_filename.append(fileExt);

/*--- Set a timer for the file writing. ---*/
startTime = SU2_MPI::Wtime();
startTime = WallTime();

/*--- Names of all the nodes, before the file is opened: a duplicate name would stop the run with the file open. ---*/
PrepareNames();
Expand Down Expand Up @@ -75,10 +75,10 @@ void CCGNSFileWriter::WriteData(string val_filename) {
#endif

/*--- Compute and store the write time and the bandwidth. ---*/
stopTime = SU2_MPI::Wtime();
stopTime = WallTime();
usedTime = stopTime - startTime;
fileSize = DetermineFilesize(val_filename);
bandwidth = fileSize / (1.0e6) / usedTime;
UpdateBandwidth(SU2_TYPE::GetValue(usedTime));

#endif
}
Expand Down
2 changes: 2 additions & 0 deletions SU2_CFD/src/output/filewriter/CFEMDataSorter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ CFEMDataSorter::CFEMDataSorter(CConfig *config, CGeometry *geometry, const vecto

/*--- Create a linear partition --- */

CheckIntCount(nGlobalPointBeforeSort);
linearPartitioner.Initialize(nGlobalPointBeforeSort, 0);

/*--- Prepare the send buffers ---*/
Expand Down Expand Up @@ -150,6 +151,7 @@ void CFEMDataSorter::SortVolumetricConnectivity(CConfig *config, CGeometry *geom

/* Allocate the memory to store the connectivity if the size is
larger than zero. */
CheckIntCount(nSubElem_Local, NODES_PER_ELEMENT);
int *Conn_SubElem = nullptr;
if(nSubElem_Local > 0) Conn_SubElem = new int[nSubElem_Local*NODES_PER_ELEMENT];

Expand Down
3 changes: 3 additions & 0 deletions SU2_CFD/src/output/filewriter/CFVMDataSorter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ void CFVMDataSorter::SetHaloPoints(CGeometry *geometry, CConfig *config){
}

void CFVMDataSorter::SortConnectivity(CConfig *config, CGeometry *geometry, bool val_sort) {
CheckIntCount(geometry->GetnElem());

/*--- Sort connectivity for each type of element (excluding halos). Note
In these routines, we sort the connectivity into a linear partitioning
Expand Down Expand Up @@ -242,7 +243,9 @@ void CFVMDataSorter::SortVolumetricConnectivity(CConfig *config,
if ((ii != rank) && (nElem_Send[ii+1] > 0)) nSends++;
if ((ii != rank) && (nElem_Cum[ii+1] > 0)) nRecvs++;

CheckIntCount(static_cast<unsigned long>(nElem_Send[ii]) + nElem_Send[ii+1], NODES_PER_ELEMENT);
nElem_Send[ii+1] += nElem_Send[ii];
CheckIntCount(static_cast<unsigned long>(nElem_Cum[ii]) + nElem_Cum[ii+1], NODES_PER_ELEMENT);
nElem_Cum[ii+1] += nElem_Cum[ii];
}

Expand Down
11 changes: 11 additions & 0 deletions SU2_CFD/src/output/filewriter/CParallelDataSorter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
#include "../../../include/output/filewriter/CParallelDataSorter.hpp"
#include <cassert>
#include <numeric>
#include <limits>

void CParallelDataSorter::CheckIntCount(unsigned long count, unsigned long entries) {
if (entries && count > static_cast<unsigned long>(std::numeric_limits<int>::max()) / entries)
SU2_MPI::Error("Output exceeds the supported 32-bit node ID or MPI count range", CURRENT_FUNCTION);
}

CParallelDataSorter::CParallelDataSorter(CConfig *config, const vector<string> &valFieldNames) :
rank(SU2_MPI::GetRank()),
Expand Down Expand Up @@ -240,6 +246,8 @@ void CParallelDataSorter::SortOutputData() {
}

void CParallelDataSorter::PrepareSendBuffers(std::vector<unsigned long>& globalID){
CheckIntCount(nGlobalPointBeforeSort);
CheckIntCount(nLocalPointsBeforeSort);

unsigned long iPoint;
unsigned short iProcessor;
Expand Down Expand Up @@ -281,7 +289,9 @@ void CParallelDataSorter::PrepareSendBuffers(std::vector<unsigned long>& globalI
if ((ii != rank) && (nPoint_Send[ii+1] > 0)) nSends++;
if ((ii != rank) && (nPoint_Recv[ii+1] > 0)) nRecvs++;

CheckIntCount(static_cast<unsigned long>(nPoint_Send[ii]) + nPoint_Send[ii+1], 1);
nPoint_Send[ii+1] += nPoint_Send[ii];
CheckIntCount(static_cast<unsigned long>(nPoint_Recv[ii]) + nPoint_Recv[ii+1], 1);
nPoint_Recv[ii+1] += nPoint_Recv[ii];
}

Expand Down Expand Up @@ -378,6 +388,7 @@ void CParallelDataSorter::SetTotalElements(){

nElemGlobal = std::accumulate(nElemPerTypeGlobal.begin(), nElemPerTypeGlobal.end(), 0ul);
nElem = std::accumulate(nElemPerType.begin(), nElemPerType.end(), 0ul);
CheckIntCount(nElemGlobal);

nConn = 0;
nConnGlobal = 0;
Expand Down
Loading
Loading