From 87a4eecfdf9f3b626d8836221d8334358f172f5c Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 6 Feb 2026 11:41:18 +0100 Subject: [PATCH 01/70] first attempt new version of log table perforation --- .../mesh/ElementRegionManager.cpp | 26 +++ .../mesh/WellElementSubRegion.cpp | 197 +++++++++--------- .../mesh/WellElementSubRegion.hpp | 51 ++++- .../mesh/generators/WellGeneratorBase.cpp | 15 -- 4 files changed, 171 insertions(+), 118 deletions(-) diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index 367d0bb2662..055cae2fc76 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -20,6 +20,9 @@ #include "common/DataLayouts.hpp" #include "common/TimingMacros.hpp" +#include "common/logger/Logger.hpp" +#include "mesh/WellElementRegion.hpp" +#include "mesh/WellElementSubRegion.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "SurfaceElementRegion.hpp" #include "constitutive/ConstitutiveManager.hpp" @@ -228,6 +231,29 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM } ); + + meshLevel.getElemManager().forElementRegions< WellElementRegion >( [&]( WellElementRegion & region ){ + TableData dataPerforation; + TableLayout const layoutPerforation ( GEOS_FMT( "Well '{}' Perforation Table", region.getName()), + { "Perforation no.", "Coordinates", "Well element no.", "Cell region", "Cell sub-region", "Cell ID" } ); + region.forElementSubRegions< WellElementSubRegion >( [&]( WellElementSubRegion & subRegion ){ + for( globalIndex iperf = 0; iperf < subRegion.getPerforationData()->getNumPerforationsGlobal(); ++iperf ) + { + if( subRegion.getGlobalIndex() != -1 ) + { + arrayView2d< real64 > const perfLocation = subRegion.getPerforationData()->getLocation(); + dataPerforation.addRow( iperf, + perfLocation[iperf], + subRegion.getPerforationData()->getWellElements()[iperf], + subRegion.getRegionName(), + subRegion.getSubRegionName(), subRegion.getGlobalIndex()); + } + } + TableTextFormatter formatter( layoutPerforation ); + GEOS_LOG_RANK_0( formatter.toString( dataPerforation )); + } ); + } ); + // communicate to rebuild global node info since we modified global ordering nodeManager.setMaxGlobalIndex(); } diff --git a/src/coreComponents/mesh/WellElementSubRegion.cpp b/src/coreComponents/mesh/WellElementSubRegion.cpp index b58343bdd12..fbe888d168b 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.cpp +++ b/src/coreComponents/mesh/WellElementSubRegion.cpp @@ -377,107 +377,6 @@ void initializeLocalSearch( MeshLevel const & mesh, // note that this reservoir element does not necessarily contains "location" eiInit = ret.second; } - -/** - * @brief Search for the reservoir element that contains the well element. - To do that, loop over the reservoir elements that are in the neighborhood of (erInit,esrInit,eiInit) - * @param[in] meshLevel the mesh object (single level only) - * @param[in] location the location of that we are trying to match with a reservoir element - * @param[in] targetRegionIndex the target region index for the reservoir element - * @param[inout] esrMatched the subregion index of the reservoir element that contains "location", if any - * @param[inout] eiMatched the element index of the reservoir element that contains "location", if any - * @param[inout] giMatched the element global index of the reservoir element that contains "location", if any - */ -bool searchLocalElements( MeshLevel const & mesh, - real64 const (&location)[3], - localIndex const & searchDepth, - localIndex const & targetRegionIndex, - localIndex & esrMatched, - localIndex & eiMatched, - globalIndex & giMatched, - real64 const geomTol ) -{ - ElementRegionBase const & region = mesh.getElemManager().getRegion< ElementRegionBase >( targetRegionIndex ); - - bool resElemFound = false; - for( localIndex esr = 0; esr < region.numSubRegions(); ++esr ) - { - ElementSubRegionBase const & subRegionBase = region.getSubRegion( esr ); - region.applyLambdaToContainer< CellElementSubRegion, SurfaceElementSubRegion >( subRegionBase, [&]( auto const & subRegion ) - { - GEOS_LOG_RANK_0( GEOS_FMT( " searching well connections with region/subregion: {}/{}", region.getName(), subRegion.getName() ) ); - - // first, we search for the reservoir element that is the *closest* from the center of well element - // note that this reservoir element does not necessarily contain the center of the well element - // this "init" reservoir element will be used later to find the reservoir element that - // contains the well element - localIndex eiInit = -1; - - initializeLocalSearch( mesh, location, targetRegionIndex, esr, eiInit ); - - if( eiInit < 0 ) // nothing found, skip the rest - return; - - // loop over the reservoir elements that are in the neighborhood of (esrInit,eiInit) - // search locally, starting from the location of the previous perforation - // the assumption here is that perforations have been entered in order of depth - - SortedArray< localIndex > nodes; - SortedArray< globalIndex > elements; - - // here is how the search is done: - // 1 - We check if "location" is within the "init" reservoir element defined by (erInit,esrMatched,eiMatched) - // 2 - If yes, stop - // - If not, a) collect the nodes of the reservoir element defined by (erInit,esrMatched,eiMatched) - // b) use these nodes to grab the neighbors of (erInit,esrMatched,eiMatched) - // c) check if "location" is within the neighbors. If not, grab the neighbors of the neighbors, and so - // on... - - // collect the nodes of the current element - // they will be used to access the neighbors and check if they contain the perforation - collectElementNodes( subRegion, eiInit, nodes ); - - // if no match is found, enlarge the neighborhood m_searchDepth'th times - for( localIndex d = 0; d < searchDepth; ++d ) - { - localIndex nNodes = nodes.size(); - - // search the reservoir elements that can be accessed from the set "nodes" - // stop if a reservoir element containing the perforation is found - // if not, enlarge the set "nodes" - - resElemFound = - visitNeighborElements< TYPEOFREF( subRegion ) >( mesh, - location, - nodes, - elements, - targetRegionIndex, - esr, - eiMatched, - giMatched, - geomTol ); - - if( resElemFound || nNodes == nodes.size()) - { - if( resElemFound ) - { - esrMatched = esr; - GEOS_LOG( GEOS_FMT( " found {}/{}/{}", region.getName(), subRegion.getName(), giMatched ) ); - } - return; - } - } - } ); - - if( resElemFound ) - { - break; - } - } - - return resElemFound; -} - } void WellElementSubRegion::generate( MeshLevel & mesh, @@ -583,12 +482,106 @@ void WellElementSubRegion::generate( MeshLevel & mesh, } +bool WellElementSubRegion::searchLocalElements( MeshLevel const & mesh, + real64 const (&location)[3], + localIndex const & searchDepth, + localIndex const & targetRegionIndex, + localIndex & esrMatched, + localIndex & eiMatched, + globalIndex & giMatched, + real64 const geomTol ) +{ + ElementRegionBase const & region = mesh.getElemManager().getRegion< ElementRegionBase >( targetRegionIndex ); + + bool resElemFound = false; + for( localIndex esr = 0; esr < region.numSubRegions(); ++esr ) + { + ElementSubRegionBase const & subRegionBase = region.getSubRegion( esr ); + region.applyLambdaToContainer< CellElementSubRegion, SurfaceElementSubRegion >( subRegionBase, [&]( auto const & subRegion ) + { + GEOS_LOG_RANK_0( GEOS_FMT( " searching well connections with region/subregion: {}/{}", region.getName(), subRegion.getName() ) ); + + // first, we search for the reservoir element that is the *closest* from the center of well element + // note that this reservoir element does not necessarily contain the center of the well element + // this "init" reservoir element will be used later to find the reservoir element that + // contains the well element + localIndex eiInit = -1; + + initializeLocalSearch( mesh, location, targetRegionIndex, esr, eiInit ); + + if( eiInit < 0 ) // nothing found, skip the rest + return; + + // loop over the reservoir elements that are in the neighborhood of (esrInit,eiInit) + // search locally, starting from the location of the previous perforation + // the assumption here is that perforations have been entered in order of depth + + SortedArray< localIndex > nodes; + SortedArray< globalIndex > elements; + + // here is how the search is done: + // 1 - We check if "location" is within the "init" reservoir element defined by (erInit,esrMatched,eiMatched) + // 2 - If yes, stop + // - If not, a) collect the nodes of the reservoir element defined by (erInit,esrMatched,eiMatched) + // b) use these nodes to grab the neighbors of (erInit,esrMatched,eiMatched) + // c) check if "location" is within the neighbors. If not, grab the neighbors of the neighbors, and so + // on... + + // collect the nodes of the current element + // they will be used to access the neighbors and check if they contain the perforation + collectElementNodes( subRegion, eiInit, nodes ); + + // if no match is found, enlarge the neighborhood m_searchDepth'th times + for( localIndex d = 0; d < searchDepth; ++d ) + { + localIndex nNodes = nodes.size(); + + // search the reservoir elements that can be accessed from the set "nodes" + // stop if a reservoir element containing the perforation is found + // if not, enlarge the set "nodes" + + resElemFound = + visitNeighborElements< TYPEOFREF( subRegion ) >( mesh, + location, + nodes, + elements, + targetRegionIndex, + esr, + eiMatched, + giMatched, + geomTol ); + + if( resElemFound || nNodes == nodes.size()) + { + if( resElemFound ) + { + esrMatched = esr; + m_perfoGlobalIndex = giMatched; + m_regionName = region.getName(); + m_subRegionName = subRegion.getName(); + GEOS_LOG( GEOS_FMT( " found {}/{}/{}", region.getName(), subRegion.getName(), giMatched ) ); + } + return; + } + } + } ); + + if( resElemFound ) + { + break; + } + } + + return resElemFound; +} + + void WellElementSubRegion::assignUnownedElementsInReservoir( MeshLevel & mesh, LineBlockABC const & lineBlock, SortedArray< globalIndex > const & unownedElems, SortedArray< globalIndex > & localElems, arrayView1d< integer > & elemStatusGlobal, - real64 const geomTol ) const + real64 const geomTol ) { ElementRegionManager const & elemManager = mesh.getElemManager(); // get the well and reservoir element coordinates diff --git a/src/coreComponents/mesh/WellElementSubRegion.hpp b/src/coreComponents/mesh/WellElementSubRegion.hpp index 26089a42838..00f67e8ae9a 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.hpp +++ b/src/coreComponents/mesh/WellElementSubRegion.hpp @@ -383,6 +383,29 @@ class WellElementSubRegion : public ElementSubRegionBase * @return list of indicies */ array1d< globalIndex > const & getGlobalElementIndex() const { return m_globalElementIndex; } + + /** + * @return The global index perfo ?? + */ + globalIndex getGlobalIndex() const + { + return m_perfoGlobalIndex; + } + /** + * @return todo + */ + string getSubRegionName() const + { + return m_subRegionName; + } + /** + * @return todo + */ + string getRegionName() const + { + return m_regionName; + } + private: /** @@ -403,7 +426,7 @@ class WellElementSubRegion : public ElementSubRegionBase SortedArray< globalIndex > const & unownedElems, SortedArray< globalIndex > & localElems, arrayView1d< integer > & elemStatusGlobal, - real64 geomTol ) const; + real64 geomTol ); /** * @brief Check that all the well elements have been assigned to a single rank. @@ -461,6 +484,26 @@ class WellElementSubRegion : public ElementSubRegionBase */ void updateNodeManagerNodeToElementMap( MeshLevel & mesh ); + /** + * @brief Search for the reservoir element that contains the well element. + To do that, loop over the reservoir elements that are in the neighborhood of (erInit,esrInit,eiInit) + * @param[in] meshLevel the mesh object (single level only) + * @param[in] location the location of that we are trying to match with a reservoir element + * @param[in] targetRegionIndex the target region index for the reservoir element + * @param[inout] esrMatched the subregion index of the reservoir element that contains "location", if any + * @param[inout] eiMatched the element index of the reservoir element that contains "location", if any + * @param[inout] giMatched the element global index of the reservoir element that contains "location", if any + */ +bool searchLocalElements( MeshLevel const & mesh, + real64 const (&location)[3], + localIndex const & searchDepth, + localIndex const & targetRegionIndex, + localIndex & esrMatched, + localIndex & eiMatched, + globalIndex & giMatched, + real64 const geomTol ); + + /** * @brief Pack element-to-node and element-to-face maps * @tparam the flag for the bufferOps::Pack function @@ -522,6 +565,12 @@ class WellElementSubRegion : public ElementSubRegionBase /// Number of segment per rank array1d< localIndex > m_elementPerRank; + + globalIndex m_perfoGlobalIndex = -1; + string m_regionName; + string m_subRegionName; + + }; } /* namespace geos */ diff --git a/src/coreComponents/mesh/generators/WellGeneratorBase.cpp b/src/coreComponents/mesh/generators/WellGeneratorBase.cpp index f55ba78049d..2f8c37a7b12 100644 --- a/src/coreComponents/mesh/generators/WellGeneratorBase.cpp +++ b/src/coreComponents/mesh/generators/WellGeneratorBase.cpp @@ -140,7 +140,6 @@ void WellGeneratorBase::generateWellGeometry( ) if( isLogLevelActive< logInfo::GenerateWell >( this->getLogLevel() ) && MpiWrapper::commRank() == 0 ) { logInternalWell(); - logPerforationTable(); } } @@ -557,18 +556,4 @@ void WellGeneratorBase::logInternalWell() const GEOS_LOG_RANK_0( wellFormatter.toString( wellData )); } -void WellGeneratorBase::logPerforationTable() const -{ - TableData dataPerforation; - for( globalIndex iperf = 0; iperf < m_numPerforations; ++iperf ) - { - dataPerforation.addRow( iperf, m_perfCoords[iperf], m_perfElemId[iperf] ); - } - - TableLayout const layoutPerforation ( GEOS_FMT( "Well '{}' Perforation Table", getName()), - { "Perforation no.", "Coordinates", "Well element no." } ); - TableTextFormatter const logPerforation( layoutPerforation ); - GEOS_LOG_RANK_0( logPerforation.toString( dataPerforation )); -} - } From 56380622b1d6fc20b8215c81defad6d41d669257 Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 6 Feb 2026 16:11:20 +0100 Subject: [PATCH 02/70] doxygen + add const --- .../mesh/ElementRegionManager.cpp | 29 ++++---- .../mesh/WellElementSubRegion.cpp | 7 +- .../mesh/WellElementSubRegion.hpp | 69 +++++++++---------- 3 files changed, 55 insertions(+), 50 deletions(-) diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index 055cae2fc76..5fa42d5fc4b 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -20,7 +20,6 @@ #include "common/DataLayouts.hpp" #include "common/TimingMacros.hpp" -#include "common/logger/Logger.hpp" #include "mesh/WellElementRegion.hpp" #include "mesh/WellElementSubRegion.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" @@ -231,26 +230,30 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM } ); - - meshLevel.getElemManager().forElementRegions< WellElementRegion >( [&]( WellElementRegion & region ){ - TableData dataPerforation; - TableLayout const layoutPerforation ( GEOS_FMT( "Well '{}' Perforation Table", region.getName()), - { "Perforation no.", "Coordinates", "Well element no.", "Cell region", "Cell sub-region", "Cell ID" } ); - region.forElementSubRegions< WellElementSubRegion >( [&]( WellElementSubRegion & subRegion ){ + meshLevel.getElemManager().forElementRegions< WellElementRegion >( [&]( WellElementRegion const & region ){ + region.forElementSubRegions< WellElementSubRegion >( [&]( WellElementSubRegion const & subRegion ){ + TableData dataPerforation; + TableLayout const layoutPerforation ( GEOS_FMT( "Well '{}' Perforation Table", region.getName()), + { "Perforation no.", "Well element no.", "Coordinates", + "Cell region", "Cell sub-region", "Cell ID" } ); for( globalIndex iperf = 0; iperf < subRegion.getPerforationData()->getNumPerforationsGlobal(); ++iperf ) { - if( subRegion.getGlobalIndex() != -1 ) + if( subRegion.getReservoirElementID() != -1 ) { - arrayView2d< real64 > const perfLocation = subRegion.getPerforationData()->getLocation(); + arrayView2d< const real64 > const perfLocation = subRegion.getPerforationData()->getLocation(); dataPerforation.addRow( iperf, - perfLocation[iperf], subRegion.getPerforationData()->getWellElements()[iperf], + perfLocation[iperf], subRegion.getRegionName(), - subRegion.getSubRegionName(), subRegion.getGlobalIndex()); + subRegion.getSubRegionName(), subRegion.getReservoirElementID()); + } } - TableTextFormatter formatter( layoutPerforation ); - GEOS_LOG_RANK_0( formatter.toString( dataPerforation )); + if( dataPerforation.getCellsData().size() > 0 ) + { + TableTextFormatter const formatter( layoutPerforation ); + GEOS_LOG( formatter.toString( dataPerforation )); + } } ); } ); diff --git a/src/coreComponents/mesh/WellElementSubRegion.cpp b/src/coreComponents/mesh/WellElementSubRegion.cpp index fbe888d168b..66e9c4babaa 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.cpp +++ b/src/coreComponents/mesh/WellElementSubRegion.cpp @@ -33,7 +33,10 @@ WellElementSubRegion::WellElementSubRegion( string const & name, Group * const p m_topWellElementIndex( -1 ), m_perforationData( groupKeyStruct::perforationDataString(), this ), m_topRank( -1 ), - m_searchDepth( 10 ) + m_searchDepth( 10 ), + m_reservoirElementID(-1), + m_regionName( "" ), + m_subRegionName( "" ) { m_elementType = ElementType::Line; @@ -556,7 +559,7 @@ bool WellElementSubRegion::searchLocalElements( MeshLevel const & mesh, if( resElemFound ) { esrMatched = esr; - m_perfoGlobalIndex = giMatched; + m_reservoirElementID = giMatched; m_regionName = region.getName(); m_subRegionName = subRegion.getName(); GEOS_LOG( GEOS_FMT( " found {}/{}/{}", region.getName(), subRegion.getName(), giMatched ) ); diff --git a/src/coreComponents/mesh/WellElementSubRegion.hpp b/src/coreComponents/mesh/WellElementSubRegion.hpp index 00f67e8ae9a..addae45e5f2 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.hpp +++ b/src/coreComponents/mesh/WellElementSubRegion.hpp @@ -385,26 +385,22 @@ class WellElementSubRegion : public ElementSubRegionBase array1d< globalIndex > const & getGlobalElementIndex() const { return m_globalElementIndex; } /** - * @return The global index perfo ?? - */ - globalIndex getGlobalIndex() const - { - return m_perfoGlobalIndex; - } + * @return The reservoir element that contains the perforation + */ + globalIndex getReservoirElementID() const + { return m_reservoirElementID; } + /** - * @return todo - */ + * @return The region name containing the reservoir element + */ string getSubRegionName() const - { - return m_subRegionName; - } + { return m_subRegionName; } + /** - * @return todo - */ + * @return The sub region name containing the reservoir element + */ string getRegionName() const - { - return m_regionName; - } + { return m_regionName; } private: @@ -485,24 +481,24 @@ class WellElementSubRegion : public ElementSubRegionBase void updateNodeManagerNodeToElementMap( MeshLevel & mesh ); /** - * @brief Search for the reservoir element that contains the well element. + * @brief Search for the reservoir element that contains the well element. To do that, loop over the reservoir elements that are in the neighborhood of (erInit,esrInit,eiInit) - * @param[in] meshLevel the mesh object (single level only) - * @param[in] location the location of that we are trying to match with a reservoir element - * @param[in] targetRegionIndex the target region index for the reservoir element - * @param[inout] esrMatched the subregion index of the reservoir element that contains "location", if any - * @param[inout] eiMatched the element index of the reservoir element that contains "location", if any - * @param[inout] giMatched the element global index of the reservoir element that contains "location", if any - */ -bool searchLocalElements( MeshLevel const & mesh, - real64 const (&location)[3], - localIndex const & searchDepth, - localIndex const & targetRegionIndex, - localIndex & esrMatched, - localIndex & eiMatched, - globalIndex & giMatched, - real64 const geomTol ); - + * @param[in] meshLevel the mesh object (single level only) + * @param[in] location the location of that we are trying to match with a reservoir element + * @param[in] targetRegionIndex the target region index for the reservoir element + * @param[inout] esrMatched the subregion index of the reservoir element that contains "location", if any + * @param[inout] eiMatched the element index of the reservoir element that contains "location", if any + * @param[inout] giMatched the element global index of the reservoir element that contains "location", if any + */ + bool searchLocalElements( MeshLevel const & mesh, + real64 const (&location)[3], + localIndex const & searchDepth, + localIndex const & targetRegionIndex, + localIndex & esrMatched, + localIndex & eiMatched, + globalIndex & giMatched, + real64 const geomTol ); + /** * @brief Pack element-to-node and element-to-face maps @@ -566,11 +562,14 @@ bool searchLocalElements( MeshLevel const & mesh, /// Number of segment per rank array1d< localIndex > m_elementPerRank; - globalIndex m_perfoGlobalIndex = -1; + /// The reservoir element that contains the perforation + globalIndex m_reservoirElementID; + /// the target region name for the reservoir element string m_regionName; + /// the target sub region name for the reservoir element string m_subRegionName; - + }; } /* namespace geos */ From 3b7ade4ac515c786ec8021c29eeafb74ccf213dc Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 6 Feb 2026 16:18:23 +0100 Subject: [PATCH 03/70] remove logPerfo header --- src/coreComponents/mesh/generators/WellGeneratorBase.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreComponents/mesh/generators/WellGeneratorBase.hpp b/src/coreComponents/mesh/generators/WellGeneratorBase.hpp index e9a2dd81046..0367b2f0109 100644 --- a/src/coreComponents/mesh/generators/WellGeneratorBase.hpp +++ b/src/coreComponents/mesh/generators/WellGeneratorBase.hpp @@ -306,7 +306,6 @@ class WellGeneratorBase : public MeshComponentBase /// @cond DO_NOT_DOCUMENT void logInternalWell() const; - void logPerforationTable() const; /// @endcond /// Global number of perforations From dbee251be6abdb4e26819b96ee0ba4039c65f8a0 Mon Sep 17 00:00:00 2001 From: arng40 Date: Tue, 10 Feb 2026 11:46:27 +0100 Subject: [PATCH 04/70] revert modif on wellElementSubRegion --- .../mesh/WellElementSubRegion.cpp | 202 +++++++++--------- .../mesh/WellElementSubRegion.hpp | 50 +---- 2 files changed, 104 insertions(+), 148 deletions(-) diff --git a/src/coreComponents/mesh/WellElementSubRegion.cpp b/src/coreComponents/mesh/WellElementSubRegion.cpp index 66e9c4babaa..b58343bdd12 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.cpp +++ b/src/coreComponents/mesh/WellElementSubRegion.cpp @@ -33,10 +33,7 @@ WellElementSubRegion::WellElementSubRegion( string const & name, Group * const p m_topWellElementIndex( -1 ), m_perforationData( groupKeyStruct::perforationDataString(), this ), m_topRank( -1 ), - m_searchDepth( 10 ), - m_reservoirElementID(-1), - m_regionName( "" ), - m_subRegionName( "" ) + m_searchDepth( 10 ) { m_elementType = ElementType::Line; @@ -380,6 +377,107 @@ void initializeLocalSearch( MeshLevel const & mesh, // note that this reservoir element does not necessarily contains "location" eiInit = ret.second; } + +/** + * @brief Search for the reservoir element that contains the well element. + To do that, loop over the reservoir elements that are in the neighborhood of (erInit,esrInit,eiInit) + * @param[in] meshLevel the mesh object (single level only) + * @param[in] location the location of that we are trying to match with a reservoir element + * @param[in] targetRegionIndex the target region index for the reservoir element + * @param[inout] esrMatched the subregion index of the reservoir element that contains "location", if any + * @param[inout] eiMatched the element index of the reservoir element that contains "location", if any + * @param[inout] giMatched the element global index of the reservoir element that contains "location", if any + */ +bool searchLocalElements( MeshLevel const & mesh, + real64 const (&location)[3], + localIndex const & searchDepth, + localIndex const & targetRegionIndex, + localIndex & esrMatched, + localIndex & eiMatched, + globalIndex & giMatched, + real64 const geomTol ) +{ + ElementRegionBase const & region = mesh.getElemManager().getRegion< ElementRegionBase >( targetRegionIndex ); + + bool resElemFound = false; + for( localIndex esr = 0; esr < region.numSubRegions(); ++esr ) + { + ElementSubRegionBase const & subRegionBase = region.getSubRegion( esr ); + region.applyLambdaToContainer< CellElementSubRegion, SurfaceElementSubRegion >( subRegionBase, [&]( auto const & subRegion ) + { + GEOS_LOG_RANK_0( GEOS_FMT( " searching well connections with region/subregion: {}/{}", region.getName(), subRegion.getName() ) ); + + // first, we search for the reservoir element that is the *closest* from the center of well element + // note that this reservoir element does not necessarily contain the center of the well element + // this "init" reservoir element will be used later to find the reservoir element that + // contains the well element + localIndex eiInit = -1; + + initializeLocalSearch( mesh, location, targetRegionIndex, esr, eiInit ); + + if( eiInit < 0 ) // nothing found, skip the rest + return; + + // loop over the reservoir elements that are in the neighborhood of (esrInit,eiInit) + // search locally, starting from the location of the previous perforation + // the assumption here is that perforations have been entered in order of depth + + SortedArray< localIndex > nodes; + SortedArray< globalIndex > elements; + + // here is how the search is done: + // 1 - We check if "location" is within the "init" reservoir element defined by (erInit,esrMatched,eiMatched) + // 2 - If yes, stop + // - If not, a) collect the nodes of the reservoir element defined by (erInit,esrMatched,eiMatched) + // b) use these nodes to grab the neighbors of (erInit,esrMatched,eiMatched) + // c) check if "location" is within the neighbors. If not, grab the neighbors of the neighbors, and so + // on... + + // collect the nodes of the current element + // they will be used to access the neighbors and check if they contain the perforation + collectElementNodes( subRegion, eiInit, nodes ); + + // if no match is found, enlarge the neighborhood m_searchDepth'th times + for( localIndex d = 0; d < searchDepth; ++d ) + { + localIndex nNodes = nodes.size(); + + // search the reservoir elements that can be accessed from the set "nodes" + // stop if a reservoir element containing the perforation is found + // if not, enlarge the set "nodes" + + resElemFound = + visitNeighborElements< TYPEOFREF( subRegion ) >( mesh, + location, + nodes, + elements, + targetRegionIndex, + esr, + eiMatched, + giMatched, + geomTol ); + + if( resElemFound || nNodes == nodes.size()) + { + if( resElemFound ) + { + esrMatched = esr; + GEOS_LOG( GEOS_FMT( " found {}/{}/{}", region.getName(), subRegion.getName(), giMatched ) ); + } + return; + } + } + } ); + + if( resElemFound ) + { + break; + } + } + + return resElemFound; +} + } void WellElementSubRegion::generate( MeshLevel & mesh, @@ -485,106 +583,12 @@ void WellElementSubRegion::generate( MeshLevel & mesh, } -bool WellElementSubRegion::searchLocalElements( MeshLevel const & mesh, - real64 const (&location)[3], - localIndex const & searchDepth, - localIndex const & targetRegionIndex, - localIndex & esrMatched, - localIndex & eiMatched, - globalIndex & giMatched, - real64 const geomTol ) -{ - ElementRegionBase const & region = mesh.getElemManager().getRegion< ElementRegionBase >( targetRegionIndex ); - - bool resElemFound = false; - for( localIndex esr = 0; esr < region.numSubRegions(); ++esr ) - { - ElementSubRegionBase const & subRegionBase = region.getSubRegion( esr ); - region.applyLambdaToContainer< CellElementSubRegion, SurfaceElementSubRegion >( subRegionBase, [&]( auto const & subRegion ) - { - GEOS_LOG_RANK_0( GEOS_FMT( " searching well connections with region/subregion: {}/{}", region.getName(), subRegion.getName() ) ); - - // first, we search for the reservoir element that is the *closest* from the center of well element - // note that this reservoir element does not necessarily contain the center of the well element - // this "init" reservoir element will be used later to find the reservoir element that - // contains the well element - localIndex eiInit = -1; - - initializeLocalSearch( mesh, location, targetRegionIndex, esr, eiInit ); - - if( eiInit < 0 ) // nothing found, skip the rest - return; - - // loop over the reservoir elements that are in the neighborhood of (esrInit,eiInit) - // search locally, starting from the location of the previous perforation - // the assumption here is that perforations have been entered in order of depth - - SortedArray< localIndex > nodes; - SortedArray< globalIndex > elements; - - // here is how the search is done: - // 1 - We check if "location" is within the "init" reservoir element defined by (erInit,esrMatched,eiMatched) - // 2 - If yes, stop - // - If not, a) collect the nodes of the reservoir element defined by (erInit,esrMatched,eiMatched) - // b) use these nodes to grab the neighbors of (erInit,esrMatched,eiMatched) - // c) check if "location" is within the neighbors. If not, grab the neighbors of the neighbors, and so - // on... - - // collect the nodes of the current element - // they will be used to access the neighbors and check if they contain the perforation - collectElementNodes( subRegion, eiInit, nodes ); - - // if no match is found, enlarge the neighborhood m_searchDepth'th times - for( localIndex d = 0; d < searchDepth; ++d ) - { - localIndex nNodes = nodes.size(); - - // search the reservoir elements that can be accessed from the set "nodes" - // stop if a reservoir element containing the perforation is found - // if not, enlarge the set "nodes" - - resElemFound = - visitNeighborElements< TYPEOFREF( subRegion ) >( mesh, - location, - nodes, - elements, - targetRegionIndex, - esr, - eiMatched, - giMatched, - geomTol ); - - if( resElemFound || nNodes == nodes.size()) - { - if( resElemFound ) - { - esrMatched = esr; - m_reservoirElementID = giMatched; - m_regionName = region.getName(); - m_subRegionName = subRegion.getName(); - GEOS_LOG( GEOS_FMT( " found {}/{}/{}", region.getName(), subRegion.getName(), giMatched ) ); - } - return; - } - } - } ); - - if( resElemFound ) - { - break; - } - } - - return resElemFound; -} - - void WellElementSubRegion::assignUnownedElementsInReservoir( MeshLevel & mesh, LineBlockABC const & lineBlock, SortedArray< globalIndex > const & unownedElems, SortedArray< globalIndex > & localElems, arrayView1d< integer > & elemStatusGlobal, - real64 const geomTol ) + real64 const geomTol ) const { ElementRegionManager const & elemManager = mesh.getElemManager(); // get the well and reservoir element coordinates diff --git a/src/coreComponents/mesh/WellElementSubRegion.hpp b/src/coreComponents/mesh/WellElementSubRegion.hpp index addae45e5f2..26089a42838 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.hpp +++ b/src/coreComponents/mesh/WellElementSubRegion.hpp @@ -383,25 +383,6 @@ class WellElementSubRegion : public ElementSubRegionBase * @return list of indicies */ array1d< globalIndex > const & getGlobalElementIndex() const { return m_globalElementIndex; } - - /** - * @return The reservoir element that contains the perforation - */ - globalIndex getReservoirElementID() const - { return m_reservoirElementID; } - - /** - * @return The region name containing the reservoir element - */ - string getSubRegionName() const - { return m_subRegionName; } - - /** - * @return The sub region name containing the reservoir element - */ - string getRegionName() const - { return m_regionName; } - private: /** @@ -422,7 +403,7 @@ class WellElementSubRegion : public ElementSubRegionBase SortedArray< globalIndex > const & unownedElems, SortedArray< globalIndex > & localElems, arrayView1d< integer > & elemStatusGlobal, - real64 geomTol ); + real64 geomTol ) const; /** * @brief Check that all the well elements have been assigned to a single rank. @@ -480,26 +461,6 @@ class WellElementSubRegion : public ElementSubRegionBase */ void updateNodeManagerNodeToElementMap( MeshLevel & mesh ); - /** - * @brief Search for the reservoir element that contains the well element. - To do that, loop over the reservoir elements that are in the neighborhood of (erInit,esrInit,eiInit) - * @param[in] meshLevel the mesh object (single level only) - * @param[in] location the location of that we are trying to match with a reservoir element - * @param[in] targetRegionIndex the target region index for the reservoir element - * @param[inout] esrMatched the subregion index of the reservoir element that contains "location", if any - * @param[inout] eiMatched the element index of the reservoir element that contains "location", if any - * @param[inout] giMatched the element global index of the reservoir element that contains "location", if any - */ - bool searchLocalElements( MeshLevel const & mesh, - real64 const (&location)[3], - localIndex const & searchDepth, - localIndex const & targetRegionIndex, - localIndex & esrMatched, - localIndex & eiMatched, - globalIndex & giMatched, - real64 const geomTol ); - - /** * @brief Pack element-to-node and element-to-face maps * @tparam the flag for the bufferOps::Pack function @@ -561,15 +522,6 @@ class WellElementSubRegion : public ElementSubRegionBase /// Number of segment per rank array1d< localIndex > m_elementPerRank; - - /// The reservoir element that contains the perforation - globalIndex m_reservoirElementID; - /// the target region name for the reservoir element - string m_regionName; - /// the target sub region name for the reservoir element - string m_subRegionName; - - }; } /* namespace geos */ From b6f5ca6b59529990ea304fd0e4c96f639f6204c3 Mon Sep 17 00:00:00 2001 From: arng40 Date: Tue, 10 Feb 2026 11:47:03 +0100 Subject: [PATCH 05/70] new method to get cell id & region / subregion --- .../mesh/ElementRegionManager.cpp | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index 5fa42d5fc4b..932812fc8f3 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -20,6 +20,7 @@ #include "common/DataLayouts.hpp" #include "common/TimingMacros.hpp" +#include "mesh/ElementSubRegionBase.hpp" #include "mesh/WellElementRegion.hpp" #include "mesh/WellElementSubRegion.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" @@ -230,22 +231,29 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM } ); - meshLevel.getElemManager().forElementRegions< WellElementRegion >( [&]( WellElementRegion const & region ){ - region.forElementSubRegions< WellElementSubRegion >( [&]( WellElementSubRegion const & subRegion ){ + meshLevel.getElemManager().forElementRegions< WellElementRegion >( [&]( WellElementRegion const & wellRegion ){ + wellRegion.forElementSubRegions< WellElementSubRegion >( [&]( WellElementSubRegion const & wellSubRegion ){ TableData dataPerforation; - TableLayout const layoutPerforation ( GEOS_FMT( "Well '{}' Perforation Table", region.getName()), + TableLayout const layoutPerforation ( GEOS_FMT( "Well '{}' Perforation Table", wellRegion.getName()), { "Perforation no.", "Well element no.", "Coordinates", "Cell region", "Cell sub-region", "Cell ID" } ); - for( globalIndex iperf = 0; iperf < subRegion.getPerforationData()->getNumPerforationsGlobal(); ++iperf ) + for( globalIndex iperf = 0; iperf < wellSubRegion.getPerforationData()->getNumPerforationsGlobal(); ++iperf ) { - if( subRegion.getReservoirElementID() != -1 ) + globalIndex cellId = wellSubRegion.getPerforationData()->getReservoirElementGlobalIndex()[iperf]; + if( cellId != -1 ) { - arrayView2d< const real64 > const perfLocation = subRegion.getPerforationData()->getLocation(); + localIndex targetRegionIndex = wellSubRegion.getPerforationData()->getMeshElements().m_toElementRegion[iperf]; + localIndex targetSubRegionIndex = wellSubRegion.getPerforationData()->getMeshElements().m_toElementSubRegion[iperf]; + ElementRegionBase const & region = meshLevel.getElemManager().getRegion< ElementRegionBase >( targetRegionIndex ); + ElementSubRegionBase const & subRegion = region.getSubRegion< ElementSubRegionBase >( targetSubRegionIndex ); + + arrayView2d< const real64 > const perfLocation = wellSubRegion.getPerforationData()->getLocation(); dataPerforation.addRow( iperf, - subRegion.getPerforationData()->getWellElements()[iperf], + wellSubRegion.getPerforationData()->getWellElements()[iperf], perfLocation[iperf], - subRegion.getRegionName(), - subRegion.getSubRegionName(), subRegion.getReservoirElementID()); + region.getName(), + subRegion.getName(), + cellId ); } } From f10caa55994fa2ab8315f1242f35ffd1bfc65d9a Mon Sep 17 00:00:00 2001 From: arng40 Date: Tue, 10 Feb 2026 17:38:54 +0100 Subject: [PATCH 06/70] wip MPI for table perfo --- .../mesh/ElementRegionManager.cpp | 72 +++++++++++++------ 1 file changed, 50 insertions(+), 22 deletions(-) diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index 932812fc8f3..3011115ed4e 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -19,7 +19,12 @@ #include "ElementRegionManager.hpp" #include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/MpiWrapper.hpp" +#include "common/StdContainerWrappers.hpp" #include "common/TimingMacros.hpp" +#include "common/logger/Logger.hpp" +#include "dataRepository/BufferOps.hpp" #include "mesh/ElementSubRegionBase.hpp" #include "mesh/WellElementRegion.hpp" #include "mesh/WellElementSubRegion.hpp" @@ -32,6 +37,8 @@ #include "schema/schemaUtilities.hpp" #include "mesh/generators/LineBlockABC.hpp" #include "mesh/CellElementRegionSelector.hpp" +#include "dataRepository/BufferOps.hpp" +#include "dataRepository/BufferOps_inline.hpp" namespace geos @@ -231,38 +238,59 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM } ); - meshLevel.getElemManager().forElementRegions< WellElementRegion >( [&]( WellElementRegion const & wellRegion ){ - wellRegion.forElementSubRegions< WellElementSubRegion >( [&]( WellElementSubRegion const & wellSubRegion ){ - TableData dataPerforation; - TableLayout const layoutPerforation ( GEOS_FMT( "Well '{}' Perforation Table", wellRegion.getName()), - { "Perforation no.", "Well element no.", "Coordinates", - "Cell region", "Cell sub-region", "Cell ID" } ); - for( globalIndex iperf = 0; iperf < wellSubRegion.getPerforationData()->getNumPerforationsGlobal(); ++iperf ) + forElementRegions< WellElementRegion >( [&]( WellElementRegion const & wellRegion ){ + + WellElementSubRegion const & + wellSubRegion = wellRegion.getGroup( ElementRegionBase::viewKeyStruct::elementSubRegions() ) + .getGroup< WellElementSubRegion >( wellRegion.getSubRegionName() ); + TableData dataPerforation; + TableLayout const layoutPerforation ( GEOS_FMT( "Well '{}' Perforation Table", wellRegion.getWellGeneratorName()), + { "Perforation no.", "Well element no.", "Coordinates", + "Cell region", "Cell sub-region", "Cell ID" } ); + for( globalIndex iperf = 0; iperf < wellSubRegion.getPerforationData()->getNumPerforationsGlobal(); ++iperf ) + { + globalIndex const cellId = wellSubRegion.getPerforationData()->getReservoirElementGlobalIndex()[iperf]; + if( cellId != -1 ) { - globalIndex cellId = wellSubRegion.getPerforationData()->getReservoirElementGlobalIndex()[iperf]; - if( cellId != -1 ) - { - localIndex targetRegionIndex = wellSubRegion.getPerforationData()->getMeshElements().m_toElementRegion[iperf]; - localIndex targetSubRegionIndex = wellSubRegion.getPerforationData()->getMeshElements().m_toElementSubRegion[iperf]; - ElementRegionBase const & region = meshLevel.getElemManager().getRegion< ElementRegionBase >( targetRegionIndex ); - ElementSubRegionBase const & subRegion = region.getSubRegion< ElementSubRegionBase >( targetSubRegionIndex ); + auto const & meshElems = wellSubRegion.getPerforationData()->getMeshElements(); + localIndex const targetRegionIndex = meshElems.m_toElementRegion[iperf]; + localIndex const targetSubRegionIndex = meshElems.m_toElementSubRegion[iperf]; + ElementRegionBase const & region = meshLevel.getElemManager().getRegion< ElementRegionBase >( targetRegionIndex ); + ElementSubRegionBase const & subRegion = region.getSubRegion< ElementSubRegionBase >( targetSubRegionIndex ); + + arrayView2d< const real64 > const perfLocation = wellSubRegion.getPerforationData()->getLocation(); + + string regionString( region.getName() ); - arrayView2d< const real64 > const perfLocation = wellSubRegion.getPerforationData()->getLocation(); + //stdVector< buffer_unit_type > rcvBuffer; + //stdVector< string > destBuffer; + //buffer_unit_type * bRegion = new buffer_unit_type[ sizeof(regionString.size()) ](); + //bufferOps::Pack< true >( bRegion, regionString ); + + stdVector< string > rcvRegionBuffer; + MpiWrapper::gather( ®ion.getName(), 1, rcvRegionBuffer.data(), 1, 0, MPI_COMM_GEOS ); + // buffer_unit_type const * localDestBuffer = rcvBuffer.data(); + // bufferOps::Unpack( localDestBuffer, destBuffer[0] ); + + if( MpiWrapper::commRank() == 0 ) + { + std::cout << "size buffer region "<< rcvRegionBuffer.size()<< " id "<< rcvRegionBuffer[0]<< std::endl; dataPerforation.addRow( iperf, wellSubRegion.getPerforationData()->getWellElements()[iperf], perfLocation[iperf], region.getName(), subRegion.getName(), cellId ); - } + } - if( dataPerforation.getCellsData().size() > 0 ) - { - TableTextFormatter const formatter( layoutPerforation ); - GEOS_LOG( formatter.toString( dataPerforation )); - } - } ); + } + if( dataPerforation.getCellsData().size() > 0 ) + { + TableTextFormatter const formatter( layoutPerforation ); + GEOS_LOG_RANK_0( formatter.toString( dataPerforation )); + } + } ); // communicate to rebuild global node info since we modified global ordering From f29df71b83982b54069abc3f0d36464e898be451 Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 13 Feb 2026 10:45:59 +0100 Subject: [PATCH 07/70] MPI gather string - code MPI duplicate with negative pressure cell --- src/coreComponents/common/MpiWrapper.cpp | 105 ++++++++++++++++++ src/coreComponents/common/MpiWrapper.hpp | 6 + .../mesh/ElementRegionManager.cpp | 51 ++++++--- 3 files changed, 148 insertions(+), 14 deletions(-) diff --git a/src/coreComponents/common/MpiWrapper.cpp b/src/coreComponents/common/MpiWrapper.cpp index b80d0aa802a..682dbc2facc 100644 --- a/src/coreComponents/common/MpiWrapper.cpp +++ b/src/coreComponents/common/MpiWrapper.cpp @@ -518,6 +518,111 @@ template<> MPI_Datatype getMpiPairType< double, double >() } /* namespace internal */ + +template<> +void MpiWrapper::gatherStringSet< stdVector >( stdVector< string > const & strSet, + stdVector< string > & result, + MPI_Comm MPI_PARAM( comm )) +{ + int rank = MpiWrapper::commRank(); + int size = MpiWrapper::commSize(); + + string localAllStrings; + stdVector< int > localStrSizes; + localAllStrings.reserve( strSet.size() * 32 ); + + for( auto const & str : strSet ) + { + localAllStrings += str; + localStrSizes.push_back( static_cast< int >(str.size())); + } + + //1 - We gather the metadata across all ranks + struct MetaData + { + int count; + int size; + }; + MetaData localMeta = { static_cast< int >(strSet.size()), static_cast< int >(localAllStrings.size()) }; + + stdVector< MetaData > allMeta; + if( rank == 0 ) + { + allMeta.resize( size ); + } + + int localMetaArr[2] = { localMeta.count, localMeta.size }; + stdVector< int > allMetaArr; + + if( rank == 0 ) + allMetaArr.resize( size * 2 ); + + MpiWrapper::gather( localMetaArr, 2, allMetaArr.data(), 2, 0, comm ); + + //2 - Prepare displacement arrays for rank 0 + stdVector< int > allStrSizes; + string allStrings; + stdVector< int > counts_counts( size ); + stdVector< int > displs_counts( size ); + stdVector< int > counts_chars( size ); + stdVector< int > displs_chars( size ); + + int totalStrCount = 0; + + if( rank == 0 ) + { + int currentCountOffset = 0; + int currentCharOffset = 0; + + for( int currRank = 0; currRank < size; ++currRank ) + { + int c_count = allMetaArr[2*currRank]; + int c_size = allMetaArr[2*currRank + 1]; + + counts_counts[currRank] = c_count; + displs_counts[currRank] = currentCountOffset; + + counts_chars[currRank] = c_size; + displs_chars[currRank] = currentCharOffset; + + currentCountOffset += c_count; + currentCharOffset += c_size; + } + + totalStrCount = currentCountOffset; + + allStrSizes.resize( totalStrCount ); + allStrings.resize( currentCharOffset ); + } + + // 3. Gatherv des tailles de chaรฎnes + MpiWrapper::gatherv( localStrSizes.data(), localMeta.count, + allStrSizes.data(), counts_counts.data(), displs_counts.data(), + 0, comm ); + + // 4. Gatherv du contenu (chars) + MpiWrapper::gatherv( localAllStrings.c_str(), localMeta.size, + allStrings.data(), counts_chars.data(), displs_chars.data(), + 0, comm ); + + // 5. Reconstruction + if( rank == 0 ) + { + const char * dataPtr = allStrings.c_str(); + int currentOffset = 0; + for( int i = 0; i < totalStrCount; ++i ) + { + int len = allStrSizes[i]; + + std::string const temp( dataPtr + currentOffset, len ); + + result.emplace( result.end(), temp ); + currentOffset += len; + } + } + +} + } /* namespace geos */ #if defined(__clang__) diff --git a/src/coreComponents/common/MpiWrapper.hpp b/src/coreComponents/common/MpiWrapper.hpp index fd3264a5317..4b7428770d7 100644 --- a/src/coreComponents/common/MpiWrapper.hpp +++ b/src/coreComponents/common/MpiWrapper.hpp @@ -22,6 +22,7 @@ #include "common/DataTypes.hpp" #include "common/Span.hpp" +#include "common/StdContainerWrappers.hpp" #include "common/TypesHelpers.hpp" #include @@ -331,6 +332,11 @@ struct MpiWrapper */ static int nodeCommSize(); + template< template< class > class CONTAINER = stdVector > + void static gatherStringSet( CONTAINER< string > const & strSet, + CONTAINER< string > & result, + MPI_Comm MPI_PARAM( comm )); + /** * @brief Strongly typed wrapper around MPI_Allgather. * @tparam T_SEND The pointer type for \p sendbuf diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index 3011115ed4e..939782c4eab 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -14,10 +14,12 @@ */ #include +#include #include #include "ElementRegionManager.hpp" +#include "codingUtilities/RTTypes.hpp" #include "common/DataLayouts.hpp" #include "common/DataTypes.hpp" #include "common/MpiWrapper.hpp" @@ -238,6 +240,9 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM } ); + int rank = MpiWrapper::commRank(); + // int size = MpiWrapper::commSize(); + forElementRegions< WellElementRegion >( [&]( WellElementRegion const & wellRegion ){ WellElementSubRegion const & @@ -258,28 +263,46 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM ElementRegionBase const & region = meshLevel.getElemManager().getRegion< ElementRegionBase >( targetRegionIndex ); ElementSubRegionBase const & subRegion = region.getSubRegion< ElementSubRegionBase >( targetSubRegionIndex ); - arrayView2d< const real64 > const perfLocation = wellSubRegion.getPerforationData()->getLocation(); + arrayView2d< const real64 > perfLocation = wellSubRegion.getPerforationData()->getLocation(); - string regionString( region.getName() ); + stdVector< string > setRegionName( {region.getName()} ); + stdVector< string > resultRegionName; + stdVector< string > setSubRegionName( {subRegion.getName()} ); + stdVector< string > resultSubRegionName; + MpiWrapper::gatherStringSet< stdVector >( setRegionName, resultRegionName, MPI_COMM_WORLD ); + MpiWrapper::gatherStringSet< stdVector >( setSubRegionName, resultSubRegionName, MPI_COMM_WORLD ); + array1d< globalIndex > rcvPerfo; + rcvPerfo.resize( 3 ); - //stdVector< buffer_unit_type > rcvBuffer; - //stdVector< string > destBuffer; - //buffer_unit_type * bRegion = new buffer_unit_type[ sizeof(regionString.size()) ](); - //bufferOps::Pack< true >( bRegion, regionString ); + if( rank == 0 ) + { + if( perfLocation.empty()) + { + MpiWrapper::recv( rcvPerfo, MPI_ANY_SOURCE, 123, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); + } + else + { + LvArray::forValuesInSlice( perfLocation.toSlice(), [&]( real64 const & v ){rcvPerfo.emplace_back( v ); } ); + } + } + else + { + if( !perfLocation.empty()) + { + MpiWrapper::send( perfLocation.data(), 3, 0, 123, MPI_COMM_WORLD ); + } + } - stdVector< string > rcvRegionBuffer; - MpiWrapper::gather( ®ion.getName(), 1, rcvRegionBuffer.data(), 1, 0, MPI_COMM_GEOS ); - // buffer_unit_type const * localDestBuffer = rcvBuffer.data(); - // bufferOps::Unpack( localDestBuffer, destBuffer[0] ); - if( MpiWrapper::commRank() == 0 ) + if( rank == 0 ) { - std::cout << "size buffer region "<< rcvRegionBuffer.size()<< " id "<< rcvRegionBuffer[0]<< std::endl; + std::cout << "destBuffer "<< rcvPerfo[0]<< " "<getWellElements()[iperf], perfLocation[iperf], - region.getName(), - subRegion.getName(), + resultRegionName[0], + setSubRegionName[0], cellId ); } From c09f8bfe8f62cf67371ed6ce0df397496660e834 Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 13 Feb 2026 10:49:47 +0100 Subject: [PATCH 08/70] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 82269bc4f0e92fc25f8c9e8ee054b6b39627597d Merge: 28643c97c6 cf245f7b94 Author: Nicola Castelletto <38361926+castelletto1@users.noreply.github.com> Date: Thu Feb 12 17:31:28 2026 -0800 Merge branch 'develop' into feature/rey/negative-pressure-cells commit 28643c97c6ac83f73ac7eadc1cfe34e68803058e Merge: 9be8d0b3d3 f6d06635c9 Author: MelReyCG <122801580+MelReyCG@users.noreply.github.com> Date: Thu Feb 12 13:51:40 2026 +0100 Merge branch 'develop' into feature/rey/negative-pressure-cells commit 9be8d0b3d37d32ba2b9b455493ea59b0583ffe54 Merge: fe602227ee be4591402d Author: MelReyCG <122801580+MelReyCG@users.noreply.github.com> Date: Wed Feb 11 16:52:42 2026 +0100 Merge branch 'develop' into feature/rey/negative-pressure-cells commit fe602227ee7e5f51e70ede6f28528d685ceed658 Author: MelReyCG Date: Mon Feb 9 16:14:35 2026 +0100 ๐Ÿ”Š pressures/densities equal to 0.0 are also reported (not only negatives) commit 168bd0c005e49d65a82403c580c0735fb49a0dc8 Merge: b3094e4dc7 4103efdb30 Author: MelReyCG <122801580+MelReyCG@users.noreply.github.com> Date: Tue Nov 18 11:30:20 2025 +0100 Merge branch 'develop' into feature/rey/negative-pressure-cells commit b3094e4dc703a701b11ad71eed5beb4910c1efa5 Merge: 370da84f2a 889ea4e797 Author: MelReyCG <122801580+MelReyCG@users.noreply.github.com> Date: Wed Nov 5 09:48:33 2025 +0100 Merge branch 'develop' into feature/rey/negative-pressure-cells commit 370da84f2ac20c11617360682ca414b000a0b38e Author: MelReyCG Date: Tue Nov 4 17:10:52 2025 +0100 ๐Ÿ› unit test merge fix commit 89c5505246f650df3d3375ab054a9e7bcbe8d58c Author: MelReyCG Date: Tue Nov 4 15:17:52 2025 +0100 ๐Ÿ“ doc fix commit b5d66becd7e175c149bf8437aeec270837d08eac Author: MelReyCG Date: Tue Nov 4 14:46:27 2025 +0100 ๐ŸŽจ ๐Ÿ“ code style & docs commit b3bfe1a880ddd9690b665c862e87e363d31321e1 Author: MelReyCG Date: Tue Nov 4 14:38:43 2025 +0100 ๐ŸŽจ copilot code checks commit 69cd64c57ffc358b2706777d423ee257b86eb1e7 Author: MelReyCG Date: Wed Oct 29 10:50:29 2025 +0100 โšฐ๏ธ merge missing variable commit c46879b8dfe0cbb0ec8f1e10ad3d73340447184e Merge: 9cf5abe9c1 178874f7a8 Author: MelReyCG Date: Wed Oct 29 10:28:02 2025 +0100 Merge remote-tracking branch 'origin/develop' into feature/rey/negative-pressure-cells commit 9cf5abe9c1f474adfb994acdf0a4fffe1589bd29 Author: MelReyCG Date: Tue Oct 28 14:36:31 2025 +0100 ๐Ÿ› typo 2 commit b78a3d79c1cfab6cbd828942f48f0144106d05a7 Author: MelReyCG Date: Mon Oct 27 16:52:03 2025 +0100 ๐Ÿ“ small precision on loginfo commit 79e1b11134179b39bb9fcefe0ac520423b379ddf Author: MelReyCG Date: Tue Oct 28 14:22:50 2025 +0100 ๐Ÿ› typo commit 2a45e9867fd9ec1acf659c5fcb799138d6dd8c57 Merge: e4431512e6 7416c57d6b Author: MelReyCG Date: Tue Oct 28 11:54:26 2025 +0100 Merge remote-tracking branch 'origin/develop' into feature/rey/negative-pressure-cells commit e4431512e691e9a748d289939921466adc934fd9 Author: MelReyCG Date: Tue Aug 26 15:46:38 2025 +0200 โ™ป๏ธ renamings (after Pavel review) commit 7812f759891d220ae496cb3e8fb193b56a52f065 Merge: f18cb8ec26 0cb3f1fec7 Author: MelReyCG Date: Tue Aug 26 10:46:30 2025 +0200 Merge branch 'develop' into feature/rey/negative-pressure-cells commit f18cb8ec26f4d5d3f8f0aff69d14f73ecdf9dcd7 Merge: de56d0df5f 43216af935 Author: Pavel Tomin Date: Thu Aug 7 12:43:10 2025 -0500 Merge branch 'develop' into feature/rey/negative-pressure-cells commit de56d0df5ff48a2037ddc3424200be8b2ac9592d Author: Pavel Tomin Date: Wed Aug 6 17:16:17 2025 -0500 code style commit a32f7d700dbcc4b2a12df9ee0d75ed4224e8f5fc Merge: 8bf347068d b7e609f00a Author: Pavel Tomin Date: Wed Aug 6 11:54:24 2025 -0500 Merge branch 'develop' into feature/rey/negative-pressure-cells commit 8bf347068d2c1ac95b60cd5d4c3429e1ba7eeec5 Author: MelReyCG Date: Mon Jul 21 16:01:43 2025 +0200 ๐Ÿ› compil fix commit 96ffe23a6e2ce8e2025dc785337f2e7f77b73aa6 Merge: 7a83961353 b05541b588 Author: MelReyCG Date: Mon Jul 21 16:01:31 2025 +0200 Merge remote-tracking branch 'origin/develop' into feature/rey/negative-pressure-cells commit 7a839613533aaa907f0d2354350a792761aae8f7 Author: MelReyCG Date: Fri Jul 18 15:42:12 2025 +0200 ๐Ÿ“ added an idea commit 2e4193cef7744bca39f34872d845e5389f1cd30c Author: MelReyCG Date: Fri Jul 18 15:33:57 2025 +0200 ๐Ÿ“ previous commit fix commit 409f4619c648d9bd27d38c3ad10671e3c3574b34 Author: MelReyCG Date: Fri Jul 18 14:24:51 2025 +0200 ๐Ÿ“ documentation updates commit 937c446b42e21751566dc2c4076982cbc433c55f Author: MelReyCG Date: Thu Jul 17 16:12:09 2025 +0200 โšฐ๏ธ removed dead code commit aeb8ea02052759bcd5fee2a6a0e7088e5f6201f9 Author: MelReyCG Date: Wed Jul 16 17:21:42 2025 +0200 ๐Ÿ“ฆ schema commit 4b46f19f10e6e87825174dd44d1050c2240d7f37 Author: MelReyCG Date: Wed Jul 16 17:21:18 2025 +0200 ๐Ÿ› solve a bug where the last line of the table was cut (when the r0 had no content) commit 92e9abbdb5be474697c206a8c7e524b20a15b60e Author: MelReyCG Date: Wed Jul 16 17:04:55 2025 +0200 ๐Ÿงช adding a (failing) test to highlight a bug commit 63fe7e79c3188af554f8ac48aa6a9c0d23317e49 Merge: 8d50b4cb02 aa33980b27 Author: MelReyCG <122801580+MelReyCG@users.noreply.github.com> Date: Wed Jul 16 16:13:07 2025 +0200 Merge branch 'develop' into feature/rey/negative-pressure-cells commit 8d50b4cb020fd9bd16c75289abbe22582df7e41e Author: MelReyCG Date: Wed Jul 16 16:11:18 2025 +0200 โ™ป๏ธ set constant params const commit 89fe09444f9eed933eecd6b7634c94d3a628304a Merge: ef29d771be 7e85e747ec Author: MelReyCG Date: Tue Jul 8 15:50:59 2025 +0200 Merge remote-tracking branch 'origin/develop' into feature/rey/negative-pressure-cells commit ef29d771be9d734f01483d74530f682165c55fc6 Author: MelReyCG Date: Fri Jul 4 15:55:31 2025 +0200 ranksStrsDisps -> ranksStrsOffsets commit 61c4199041e44e81be0198b5d5e84e1db4478b4a Author: MelReyCG Date: Fri Jul 4 15:38:45 2025 +0200 ๐Ÿ“ doc fix commit 5af2601ebf61f44c61ce5c6146e85e9ca2c14641 Author: MelReyCG Date: Wed Jul 2 12:05:25 2025 +0200 ๐Ÿ“ missing last docs commit de75861c879c5c2a6d9d7272c16abba3128853d9 Merge: 8eb526bf24 125ffb92a8 Author: MelReyCG <122801580+MelReyCG@users.noreply.github.com> Date: Wed Jul 2 11:52:59 2025 +0200 Merge branch 'develop' into feature/rey/negative-pressure-cells commit 8eb526bf24fc2c9908cf35281fb70cd859f9c9a7 Author: MelReyCG Date: Wed Jul 2 11:51:48 2025 +0200 ๐ŸŽจ uncrustify commit 411636da54c1ab1acde6cd359b9e7bea006df4d1 Author: MelReyCG Date: Wed Jul 2 11:48:22 2025 +0200 ๐Ÿ“ Adding las docs commit e5ae68ec78694ae737a23292ed8581451b149f4d Author: MelReyCG Date: Tue Jul 1 17:54:36 2025 +0200 โœ… adding mpi tables unit test commit 112be17fb935f425d1461fbd1ceb99e4ab292e10 Author: MelReyCG Date: Tue Jul 1 17:54:09 2025 +0200 ๐Ÿ“ updating documentation commit b086a4f90e2e275edc7fccae615da50d2e98cf02 Author: MelReyCG Date: Tue Jul 1 15:46:33 2025 +0200 ๐Ÿ› fixing scarce crash when mpi-tables are constructed from more than 2 ranks commit 04754361d56ad26a96486c5bb896b33c3a3b8a54 Author: MelReyCG Date: Tue Jul 1 15:45:59 2025 +0200 โšฐ๏ธ unused variables commit 72e8ecdf301da46d80354a3e045289e8a5e9917d Author: MelReyCG Date: Fri Jun 6 10:22:27 2025 +0200 ๐Ÿ’„ transposing table layout for clarity (user review) commit 390e451f746fb6d3612b93955560d5f209f58031 Author: MelReyCG Date: Fri Jun 6 10:18:17 2025 +0200 โ™ป๏ธ Adding missing signatures commit 9b6cd4d79a3ea03ee1c28507303f54cf432ac053 Merge: 5ab8421400 c2768e6ecd Author: MelReyCG Date: Wed Jun 4 11:46:45 2025 +0200 Merge remote-tracking branch 'origin/develop' into feature/rey/negative-pressure-cells commit 5ab8421400cf2143049706dc84eb022be131f910 Author: MelReyCG Date: Wed Jun 4 11:46:15 2025 +0200 โœจ adding ranks separator titles commit 6a43cb9dd0d24def34d0acad25ed376cf1c0a8df Author: MelReyCG Date: Tue Jun 3 18:24:38 2025 +0200 โœจ finishing MPI tables with a different approach (log output on rank0 only) commit 6487d6c2b3e774eb86e0ea64f4a6f389cb99e6f2 Author: MelReyCG Date: Mon Jun 2 14:13:33 2025 +0200 โœจ ๐Ÿงช first attempt at creating MPI tables commit 854dc3e11a464e60b365edf729b1c09a06172c64 Author: MelReyCG Date: Wed May 28 14:34:17 2025 +0200 โ™ป๏ธ minor refactor of TableFormatter.cpp commit 66f2d727e9c1df6c1c5c805082e5be0f76db5657 Author: MelReyCG Date: Wed May 28 14:33:57 2025 +0200 โœจ adding info to warn the user to increase a logLevel to get the report commit 4a9f7803e20fb9cb676864b68eea3f5863bbea52 Author: MelReyCG Date: Wed May 28 14:16:22 2025 +0200 โœจextending reported data to pressure/density (IdReporter -> ElementReporter) commit 00d8c577c219a1785c1ebe581838d81a08719119 Author: MelReyCG Date: Wed May 28 11:00:31 2025 +0200 โšฐ๏ธ dead code commit da89daf1784259f994b7be243ff848d54089af4b Author: MelReyCG Date: Tue May 27 17:09:02 2025 +0200 ๐Ÿ’„ new table format commit e7f73cf188698b44b110f98ef235314c50d5e4c0 Author: MelReyCG Date: Mon May 26 17:49:19 2025 +0200 โœจ offering control on alignement when using columns-free table layouts commit 3fd0c12e336f924a27a00b7d273b81fdab774c67 Author: MelReyCG Date: Mon May 26 17:48:52 2025 +0200 โ™ป๏ธ ๐Ÿ› simplifying & fixing visible columns counting commit 8f68eb515f0534be35d467dfc40a3a42b52c3e06 Author: MelReyCG Date: Mon May 26 17:47:25 2025 +0200 โ™ป๏ธ refactoring TableFormatter: give control to inheriting classes commit 5744a2af42292f5ed05e6cd88f289150019a87dd Merge: 58d1dce874 ef5e9406d7 Author: MelReyCG Date: Mon May 26 14:06:10 2025 +0200 Merge remote-tracking branch 'origin/develop' into feature/rey/negative-pressure-cells commit 58d1dce87471a359eb18a982f548e4c0dfb0812a Author: MelReyCG Date: Mon May 26 11:52:38 2025 +0200 โ™ป๏ธ refactoring TableFormatter: give control to inheriting classes commit 3eb2293a826a844df7c0a7f8b678f165fd0f6c79 Author: MelReyCG Date: Mon May 26 11:48:38 2025 +0200 โ™ป๏ธ removing double assessor + exposing non-const version commit 5fc7ea63c7da07b4f7364e9d2a5035c052a858ef Author: MelReyCG Date: Fri May 23 12:28:09 2025 +0200 โœจ adding support for no column titled table layout commit 47f5c5ce91bd396d355e4034b10caa26428ab74d Author: MelReyCG Date: Fri May 23 11:09:44 2025 +0200 โœจ adding table indentation commit de506c60bb0ee7b09eaac5518f72efe2a730dbb8 Author: MelReyCG Date: Fri May 23 10:09:42 2025 +0200 โœจ adding table formatting to allow for showing more data commit 0803a92e910f5274258ad742fd227cec4e5b9151 Author: MelReyCG Date: Thu May 22 16:53:04 2025 +0200 ๐Ÿ› CUDA crash fix + bug fix (data not moved from device) commit d29db451bc30b9c76a90873b3b0910de135d859e Author: MelReyCG Date: Tue May 20 17:42:52 2025 +0200 ๐Ÿ› adding one more barrier to not get the msg cut by other msgs. commit e0b104d7c12ac6230138e9d04b070684c87f5ad2 Author: MelReyCG Date: Tue May 20 17:22:31 2025 +0200 ๐Ÿ’„ msg slight rewriting commit 3f97e2bd5527ba9269893344374492be5982871b Author: MelReyCG Date: Tue May 20 14:33:40 2025 +0200 ๐Ÿ› fix for a CUDA target: explicit constructor call commit 6766e7e6a682bf49d6e99ba9a91b63ed0b6be961 Merge: 056ac9cf89 5a65081dca Author: MelReyCG Date: Tue May 20 11:37:03 2025 +0200 Merge remote-tracking branch 'origin/develop' into feature/rey/negative-pressure-cells commit 056ac9cf89e5d9d918a870c7525d734e896e9288 Author: MelReyCG Date: Tue May 20 11:29:21 2025 +0200 โœจ implementation of neg pressure ids output on other models commit 18703e3ef100a37c09ea9b8a057c9949a3e4b25a Author: MelReyCG Date: Tue May 20 11:28:20 2025 +0200 โ™ป๏ธ refactors to prevent computing mpi reduction twice + constness + naming commit 14a546fbb1eb3ef5254207058be2c63fbb2a8fb6 Author: MelReyCG Date: Mon May 19 16:10:47 2025 +0200 ๐Ÿ’„ adding msg precisions commit 4ebe3308a3e1486c85411c2ecfaf7ae981fb24e0 Author: MelReyCG Date: Mon May 19 15:48:26 2025 +0200 ๐Ÿ’„ slight msg change / fix 2 commit 5cf681482329ec2fd28aad90acc2a5d5b1160d0a Author: MelReyCG Date: Mon May 19 15:40:18 2025 +0200 ๐Ÿ’„ slight msg change / fix commit 96cd0a844cabf0e7465fc9d046edee117890e9ae Author: MelReyCG Date: Fri May 16 18:10:08 2025 +0200 โœจ activation de l'output des valeurs problรฉmatique en fยฐ d'un nouveau logLevel "SolutionDetails" commit cb0ae03efeef7fff41d2378e11e97d1c254174ca Author: MelReyCG Date: Fri May 16 12:34:53 2025 +0200 โ™ป๏ธ proper cpp/hpp file repartition commit 1434bd389f2db1f2cc9b060e798baae5a0cd9cfb Author: MelReyCG Date: Fri May 16 12:09:57 2025 +0200 โ™ป๏ธ removing unnecessary template commit 8d158fc0ded2c0dbf182e1317321a6aeeace65e5 Author: MelReyCG Date: Fri May 16 11:56:59 2025 +0200 โœจ added the IdReporter classes to facilitate outputing ids & their count from kernels (optionally) commit 76f4644c9011231612342e0d3e38575bec9891e8 Author: MelReyCG Date: Wed May 7 18:24:23 2025 +0200 ๐Ÿ’ฉ first attempt at outputing wrong cells in multiphase cases... work on CPU but doesn't on GPU build + suboptimal --- src/coreComponents/common/CMakeLists.txt | 10 +- .../common/format/table/TableData.cpp | 10 - .../common/format/table/TableData.hpp | 21 +- .../common/format/table/TableFormatter.cpp | 70 ++++--- .../common/format/table/TableFormatter.hpp | 62 ++++-- .../common/format/table/TableLayout.cpp | 43 +++- .../common/format/table/TableLayout.hpp | 85 ++++++-- .../format/table/TableMpiComponents.cpp | 160 +++++++++++++++ .../format/table/TableMpiComponents.hpp | 110 ++++++++++ .../format/table/unitTests/CMakeLists.txt | 20 ++ .../format/table/unitTests/testMpiTable.cpp | 149 ++++++++++++++ .../format/table/unitTests/testTable.cpp | 26 ++- .../parameters/KValueFlashParameters.cpp | 4 +- .../physicsSolvers/LogLevelsInfo.hpp | 6 + .../physicsSolvers/fluidFlow/CMakeLists.txt | 3 + .../fluidFlow/CompositionalMultiphaseFVM.cpp | 117 ++++++----- .../CompositionalMultiphaseHybridFVM.cpp | 4 +- .../fluidFlow/SinglePhaseBase.cpp | 32 +-- .../fluidFlow/SolutionCheckHelpers.cpp | 118 +++++++++++ .../fluidFlow/SolutionCheckHelpers.hpp | 190 ++++++++++++++++++ .../kernels/SolutionCheckKernelsHelpers.hpp | 137 +++++++++++++ .../compositional/SolutionCheckKernel.hpp | 159 +++++++++------ .../ThermalSolutionCheckKernel.hpp | 12 +- .../singlePhase/SolutionCheckKernel.hpp | 33 +-- .../wells/CompositionalMultiphaseWell.cpp | 118 +++++------ .../fluidFlow/wells/SinglePhaseWell.cpp | 35 ++-- 26 files changed, 1415 insertions(+), 319 deletions(-) create mode 100644 src/coreComponents/common/format/table/TableMpiComponents.cpp create mode 100644 src/coreComponents/common/format/table/TableMpiComponents.hpp create mode 100644 src/coreComponents/common/format/table/unitTests/testMpiTable.cpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/SolutionCheckHelpers.cpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/SolutionCheckHelpers.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/SolutionCheckKernelsHelpers.hpp diff --git a/src/coreComponents/common/CMakeLists.txt b/src/coreComponents/common/CMakeLists.txt index 0e37ba56703..d0143b9564b 100644 --- a/src/coreComponents/common/CMakeLists.txt +++ b/src/coreComponents/common/CMakeLists.txt @@ -24,9 +24,10 @@ Also provides commonly used components for such as logging, formatting, memory a # set( common_headers ${CMAKE_BINARY_DIR}/include/common/GeosxConfig.hpp - format/table/TableLayout.hpp - format/table/TableFormatter.hpp format/table/TableData.hpp + format/table/TableFormatter.hpp + format/table/TableLayout.hpp + format/table/TableMpiComponents.hpp format/EnumStrings.hpp format/LogPart.hpp format/Format.hpp @@ -71,9 +72,10 @@ endif( ) # Specify all sources # set( common_sources - format/table/TableLayout.cpp - format/table/TableFormatter.cpp format/table/TableData.cpp + format/table/TableFormatter.cpp + format/table/TableLayout.cpp + format/table/TableMpiComponents.cpp format/LogPart.cpp format/StringUtilities.cpp logger/GeosExceptions.cpp diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp index 072e3b1ca79..b9bfc885584 100644 --- a/src/coreComponents/common/format/table/TableData.cpp +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -89,16 +89,6 @@ void TableData::clear() getErrorsList().clear(); } -stdVector< stdVector< TableData::CellData > > const & TableData::getTableDataRows() const -{ - return m_rows; -} - -stdVector< stdVector< TableData::CellData > > & TableData::getTableDataRows() -{ - return m_rows; -} - void TableData2D::collectTableValues( arrayView1d< real64 const > dim0AxisCoordinates, arrayView1d< real64 const > dim1AxisCoordinates, arrayView1d< real64 const > values, diff --git a/src/coreComponents/common/format/table/TableData.hpp b/src/coreComponents/common/format/table/TableData.hpp index 22135105ecf..e36afb037c5 100644 --- a/src/coreComponents/common/format/table/TableData.hpp +++ b/src/coreComponents/common/format/table/TableData.hpp @@ -111,16 +111,6 @@ class TableData void clearErrors() { m_errors->clear(); } - /** - * @return The const rows of the table - */ - stdVector< stdVector< CellData > > const & getTableDataRows() const; - - /** - * @return The rows of the table - */ - stdVector< stdVector< CellData > > & getTableDataRows(); - /** * @brief Get all error messages * @return The vector of error messages @@ -133,16 +123,19 @@ class TableData DataRows const & getCellsData() const { return m_rows; } + /** + * @return The const table data rows + */ + DataRows & getCellsData() + { return m_rows; } + /** * @brief Comparison operator for data rows * @param comparingTable The tableData values to compare * @return The comparison result */ inline bool operator==( TableData const & comparingTable ) const - { - - return getCellsData() == comparingTable.getCellsData(); - } + { return getCellsData() == comparingTable.getCellsData(); } /** * @brief Get all error messages diff --git a/src/coreComponents/common/format/table/TableFormatter.cpp b/src/coreComponents/common/format/table/TableFormatter.cpp index e34eaa8d37c..bf5779fdc23 100644 --- a/src/coreComponents/common/format/table/TableFormatter.cpp +++ b/src/coreComponents/common/format/table/TableFormatter.cpp @@ -18,10 +18,10 @@ * @file TableFormatter.cpp */ -#include "TableFormatter.hpp" #include #include "common/format/StringUtilities.hpp" #include "common/logger/Logger.hpp" +#include "TableFormatter.hpp" namespace geos { @@ -157,7 +157,8 @@ string TableCSVFormatter::headerToString() const string TableCSVFormatter::dataToString( TableData const & tableData ) const { - RowsCellInput const rowsValues( tableData.getTableDataRows() ); + + RowsCellInput const rowsValues( tableData.getCellsData() ); string result; size_t total_size = 0; for( auto const & row : rowsValues ) @@ -232,12 +233,13 @@ string TableTextFormatter::toString< TableData >( TableData const & tableData ) initalizeTableGrids( m_tableLayout, tableData, headerCellsLayout, dataCellsLayout, errorCellsLayout, - tableTotalWidth ); - outputTable( m_tableLayout, tableOutput, - headerCellsLayout, dataCellsLayout, errorCellsLayout, - tableTotalWidth ); + tableTotalWidth, nullptr ); + + string const sepLine = string( tableTotalWidth, m_horizontalLine ); + outputTableHeader( tableOutput, m_tableLayout, headerCellsLayout, sepLine ); + outputTableData( tableOutput, m_tableLayout, dataCellsLayout ); + outputTableFooter( tableOutput, m_tableLayout, errorCellsLayout, sepLine, !dataCellsLayout.empty() ); - getErrorsList().clear(); return tableOutput.str(); } @@ -246,10 +248,11 @@ void TableTextFormatter::initalizeTableGrids( PreparedTableLayout const & tableL CellLayoutRows & headerCellsLayout, CellLayoutRows & dataCellsLayout, CellLayoutRows & errorCellsLayout, - size_t & tableTotalWidth ) const + size_t & tableTotalWidth, + ColumnWidthModifier columnWidthModifier ) const { + RowsCellInput const & inputDataValues( tableInputData.getCellsData() ); bool const hasColumnLayout = tableLayout.getColumnLayersCount() > 0; - RowsCellInput const & inputDataValues( tableInputData.getTableDataRows() ); size_t const inputDataRowsCount = !inputDataValues.empty() ? inputDataValues.front().size() : 0; size_t const nbVisibleColumns = std::max( size_t( 1 ), ( hasColumnLayout ? tableLayout.getVisibleLowermostColumnCount() : @@ -282,6 +285,9 @@ void TableTextFormatter::initalizeTableGrids( PreparedTableLayout const & tableL stretchColumnsByMergedCellsWidth( columnsWidth, dataCellsLayout, tableLayout, true ); stretchColumnsByMergedCellsWidth( columnsWidth, errorCellsLayout, tableLayout, true ); + if( columnWidthModifier ) + columnWidthModifier( columnsWidth ); + // the columns width array is now sized after all the table, we can compute the total table width tableTotalWidth = tableLayout.getBorderMargin() * 2 + 2; for( size_t columnId = 0; columnId < columnsWidth.size(); ++columnId ) @@ -308,14 +314,14 @@ void TableTextFormatter::populateTitleCellsLayout( PreparedTableLayout const & t // the title row consists in a row of cells merging with the last cell containing the title text headerCellsLayout.emplace_back() = { stdVector< TableLayout::CellLayout >( nbVisibleColumns, - TableLayout::CellLayout( CellType::MergeNext ) ), // cells + TableLayout::CellLayout( CellType::MergeNext ) ), // cells titleInput.getHeight(), // sublinesCount }; headerCellsLayout.back().cells.back() = titleInput; headerCellsLayout.emplace_back() = { stdVector< TableLayout::CellLayout >( nbVisibleColumns, - TableLayout::CellLayout( CellType::Separator ) ), // cells + TableLayout::CellLayout( CellType::Separator ) ), // cells 1, // sublinesCount }; } @@ -494,8 +500,8 @@ void TableTextFormatter::populateDataCellsLayout( PreparedTableLayout const & ta string_view( &m_horizontalLine, 1 ) : string_view( inputCell.value ); TableLayout::Alignment const alignment = inputCell.type == CellType::Header ? - tableLayout.defaultHeaderAlignment : - tableLayout.defaultValueAlignment; + tableLayout.getDefaultHeaderAlignment() : + tableLayout.getDefaultValueAlignment(); TableLayout::CellLayout & outputCell = outputRow.cells[idxColumn]; outputCell = TableLayout::CellLayout( inputCell.type, alignment ); @@ -702,34 +708,44 @@ void TableTextFormatter::applyColumnsWidth( stdVector< size_t > const & columnsW } } -void TableTextFormatter::outputTable( PreparedTableLayout const & tableLayout, - std::ostream & tableOutput, - CellLayoutRows const & headerCellsLayout, - CellLayoutRows const & dataCellsLayout, - CellLayoutRows & errorCellsLayout, - size_t const tableTotalWidth ) const +void TableTextFormatter::outputTableHeader( std::ostream & tableOutput, + PreparedTableLayout const & tableLayout, + CellLayoutRows const & headerCellsLayout, + string_view sepLine ) const { - string const sepLine = string( tableTotalWidth, m_horizontalLine ); if( tableLayout.isLineBreakEnabled()) { tableOutput << '\n'; } - tableOutput << sepLine << '\n'; + tableOutput << tableLayout.getIndentationStr() << sepLine << '\n'; outputLines( tableLayout, headerCellsLayout, tableOutput ); +} - if( !dataCellsLayout.empty()) +void TableTextFormatter::outputTableData( std::ostream & tableOutput, + PreparedTableLayout const & tableLayout, + CellLayoutRows const & dataCellsLayout ) const +{ + if( !dataCellsLayout.empty() ) { outputLines( tableLayout, dataCellsLayout, tableOutput ); } +} +void TableTextFormatter::outputTableFooter( std::ostream & tableOutput, + PreparedTableLayout const & tableLayout, + CellLayoutRows & errorCellsLayout, + string_view sepLine, + bool hasData ) const +{ if( !errorCellsLayout.empty()) { outputErrors( tableLayout, errorCellsLayout, tableOutput ); } - if( !dataCellsLayout.empty() || getErrorsList().hasErrors()) - tableOutput << sepLine; - + if( hasData || !errorCellsLayout.empty() ) + { + tableOutput << tableLayout.getIndentationStr() << sepLine; + } if( tableLayout.isLineBreakEnabled()) { @@ -816,6 +832,7 @@ void TableTextFormatter::outputLines( PreparedTableLayout const & tableLayout, if( isLeftBorderCell ) { // left table border isLeftBorderCell=false; + tableOutput << tableLayout.getIndentationStr(); tableOutput << m_verticalLine << string( nbBorderSpaces, cellSpaceChar ); } else @@ -845,4 +862,5 @@ void TableTextFormatter::outputLines( PreparedTableLayout const & tableLayout, idxRow++; } } -} + +} /* namespace geos */ diff --git a/src/coreComponents/common/format/table/TableFormatter.hpp b/src/coreComponents/common/format/table/TableFormatter.hpp index c2035bc2a1c..eed907975c2 100644 --- a/src/coreComponents/common/format/table/TableFormatter.hpp +++ b/src/coreComponents/common/format/table/TableFormatter.hpp @@ -86,7 +86,7 @@ class TableFormatter }; /** - * @brief class for CSV formatting + * @brief Class to format data in a formatted CSV format */ class TableCSVFormatter final : public TableFormatter { @@ -189,9 +189,10 @@ string TableCSVFormatter::toString< TableData >( TableData const & tableData ) c /** - * @brief class for log formatting + * @brief Class to format data in a formatted text format + * (for log output typically, expecting fixed character size). */ -class TableTextFormatter final : public TableFormatter +class TableTextFormatter : public TableFormatter { public: @@ -243,13 +244,15 @@ class TableTextFormatter final : public TableFormatter void toStream( std::ostream & outputStream, DATASOURCE const & tableData ) const { toStreamImpl( outputStream, toString( tableData ) ); } -private: +protected: /// symbol for separator construction static constexpr char m_verticalLine = '|'; /// for the extremity of a row static constexpr char m_horizontalLine = '-'; + /// A functor which allow to customize the columns width after their computation. + using ColumnWidthModifier = std::function< void ( stdVector< size_t > & ) >; /** * @brief Initializes the table layout with the given table data and prepares necessary layouts for headers and data cells. @@ -258,30 +261,54 @@ class TableTextFormatter final : public TableFormatter * @param headerCellsLayout A reference to a `CellLayoutRows` where the header cells will be populated. * @param dataCellsLayout A reference to a `CellLayoutRows` where the data cells will be populated. * @param errorCellsLayout A reference to a `CellLayoutRows` where the error cells will be populated. - * @param separatorLine A string that will be used as the table separator line + * @param tableTotalWidth A string that will be used as the table separator line + * @param columnWidthModifier A functor which allow to customize the columns width after their computation. */ void initalizeTableGrids( PreparedTableLayout const & tableLayout, TableData const & tableData, CellLayoutRows & dataCellsLayout, CellLayoutRows & headerCellsLayout, CellLayoutRows & errorCellsLayout, - size_t & tableTotalWidth ) const; + size_t & tableTotalWidth, + ColumnWidthModifier columnWidthModifier ) const; + + /** + * @brief Outputs the top part of the formatted table to the provided output stream. + * @param tableOutput A reference to an `std::ostream` where the formatted table will be written. + * @param tableLayout The layout of the table + * @param headerCellsLayout The header rows in a grid layout + * @param separatorLine A string that will be used as the table separator line + */ + void outputTableHeader( std::ostream & tableOutput, + PreparedTableLayout const & tableLayout, + CellLayoutRows const & headerCellsLayout, + string_view separatorLine ) const; /** - * @brief Outputs the formatted table to the provided output stream. + * @brief Outputs the data part of the formatted table to the provided output stream. + * @param tableOutput A reference to an `std::ostream` where the formatted table will be written. * @param tableLayout The layout of the table + * @param dataCellsLayout The data rows in a grid layout + */ + void outputTableData( std::ostream & tableOutput, + PreparedTableLayout const & tableLayout, + CellLayoutRows const & dataCellsLayout ) const; + + /** + * @brief Outputs the bottom part of the formatted table to the provided output stream. * @param tableOutput A reference to an `std::ostream` where the formatted table will be written. - * @param headerCellsLayout The layout of the header rows - * @param dataCellsLayout The layout of the data rows + * @param tableLayout The layout of the table + * @param separatorLine A string that will be used as the table separator line * @param errorCellsLayout The layout of the error rows - * @param separatorLine The string to be used as the table separator line + * @param hasData Indicates whether there is data in the table TableData. */ - void outputTable( PreparedTableLayout const & tableLayout, - std::ostream & tableOutput, - CellLayoutRows const & headerCellsLayout, - CellLayoutRows const & dataCellsLayout, - CellLayoutRows & errorCellsLayout, - size_t tableTotalWidth ) const; + void outputTableFooter( std::ostream & tableOutput, + PreparedTableLayout const & tableLayout, + CellLayoutRows & errorCellsLayout, + string_view separatorLine, + bool hasData ) const; + +private: /** * @brief Outputs the formatted table lines to the output stream. @@ -312,7 +339,7 @@ class TableTextFormatter final : public TableFormatter */ void populateTitleCellsLayout( PreparedTableLayout const & tableLayout, CellLayoutRows & headerCellsLayout, - size_t const nbVisibleColumn ) const; + size_t nbVisibleColumn ) const; /** * @brief Populate a grid of CellLayout with all visible columns of the given table layout. @@ -402,6 +429,7 @@ class TableTextFormatter final : public TableFormatter void formatCell( std::ostream & tableOutput, TableLayout::CellLayout const & cell, size_t idxLine ) const; + }; /** diff --git a/src/coreComponents/common/format/table/TableLayout.cpp b/src/coreComponents/common/format/table/TableLayout.cpp index 55446491cd2..67401ff9e67 100644 --- a/src/coreComponents/common/format/table/TableLayout.cpp +++ b/src/coreComponents/common/format/table/TableLayout.cpp @@ -24,31 +24,41 @@ namespace geos { -void TableLayout::addColumns( stdVector< string > const & columnNames ) +TableLayout & TableLayout::addColumns( stdVector< string > const & columnNames ) { for( auto const & columnName : columnNames ) { addColumn( columnName ); } + return *this; } -void TableLayout::addColumns( stdVector< TableLayout::Column > const & columns ) +TableLayout & TableLayout::addColumns( stdVector< TableLayout::Column > const & columns ) { for( auto const & column : columns ) { addColumn( column ); } + return *this; +} + +TableLayout & TableLayout::addColumns( TableLayoutArgs columns ) +{ + processArguments( columns ); + return *this; } -void TableLayout::addColumn( string_view columnName ) +TableLayout & TableLayout::addColumn( string_view columnName ) { TableLayout::Column column = TableLayout::Column().setName( columnName ); m_tableColumns.emplace_back( column ); + return *this; } -void TableLayout::addColumn( TableLayout::Column const & column ) +TableLayout & TableLayout::addColumn( TableLayout::Column const & column ) { m_tableColumns.emplace_back( column ); + return *this; } TableLayout & TableLayout::setTitle( string_view title ) @@ -78,6 +88,23 @@ TableLayout & TableLayout::setMaxColumnWidth( size_t width ) return *this; } +TableLayout & TableLayout::setIndentation( size_t spacesCount ) +{ + m_indentation = spacesCount; + return *this; +} + +TableLayout & TableLayout::setDefaultHeaderAlignment( TableLayout::Alignment alignment ) +{ + m_defaultHeaderAlignment = alignment; + return *this; +} +TableLayout & TableLayout::setDefaultValueAlignment( TableLayout::Alignment alignment ) +{ + m_defaultValueAlignment = alignment; + return *this; +} + bool TableLayout::isLineBreakEnabled() const { return m_lineBreakAtBegin; } @@ -159,7 +186,7 @@ void TableLayout::Cell::setText( string_view text ) } TableLayout::Column::Column(): - m_header( CellType::Header, defaultHeaderAlignment ) + m_header( CellType::Header, Alignment::center ) {} TableLayout::Column::Column( string_view name, TableLayout::ColumnAlignement alignment ): @@ -298,14 +325,16 @@ TableLayout::DeepFirstIterator TableLayout::beginDeepFirst() const PreparedTableLayout::PreparedTableLayout( ): TableLayout(), m_columnLayersCount( 0 ), - m_visibleLowermostColumnCount( 0 ) + m_visibleLowermostColumnCount( 0 ), + m_indentationStr( m_indentation, ' ' ) {} PreparedTableLayout::PreparedTableLayout( TableLayout const & other ): TableLayout( other ), m_columnLayersCount( 0 ), m_totalLowermostColumnCount( 0 ), - m_visibleLowermostColumnCount( 0 ) + m_visibleLowermostColumnCount( 0 ), + m_indentationStr( m_indentation, ' ' ) { prepareLayoutRecusive( m_tableColumns, 0 ); diff --git a/src/coreComponents/common/format/table/TableLayout.hpp b/src/coreComponents/common/format/table/TableLayout.hpp index 4ef156ad760..e08474aa064 100644 --- a/src/coreComponents/common/format/table/TableLayout.hpp +++ b/src/coreComponents/common/format/table/TableLayout.hpp @@ -41,12 +41,6 @@ class TableLayout /// Type of aligment for a column enum Alignment { right, left, center }; - /// default value for columns header cells alignement - static constexpr Alignment defaultHeaderAlignment = Alignment::center; - - /// default value for data cells alignement - static constexpr Alignment defaultValueAlignment = Alignment::right; - /// Space to apply between all data and border enum MarginValue : integer { @@ -67,9 +61,9 @@ class TableLayout struct ColumnAlignement { /// Alignment for column name. By default aligned to center - Alignment headerAlignment = defaultHeaderAlignment; + Alignment headerAlignment = Alignment::center; /// Alignment for column values. By default aligned to right side - Alignment valueAlignment = defaultValueAlignment; + Alignment valueAlignment = Alignment::right; }; /** @@ -618,6 +612,18 @@ class TableLayout string_view getTitleStr() const { return m_tableTitleStr; } + /** + * @return the default value for columns header cells alignement. Used with column-free layout. + */ + Alignment getDefaultHeaderAlignment() const + { return m_defaultHeaderAlignment; } + + /** + * @return the default value for data cells alignement. Used with column-free layout. + */ + Alignment getDefaultValueAlignment() const + { return m_defaultValueAlignment; } + /** * @param title The table title * @return The tableLayout reference @@ -645,6 +651,27 @@ class TableLayout */ TableLayout & setMaxColumnWidth( size_t width ); + /** + * @brief Set the indentation of the whole table. + * @param spacesCount The number of indentation spaces. + * @return the TableLayout instance, for builder pattern + */ + TableLayout & setIndentation( size_t spacesCount ); + + /** + * @brief Sets the default value for columns header cells alignement. Used with column-free layout. + * @param alignment The desired alignment + * @return the TableLayout instance, for builder pattern + */ + TableLayout & setDefaultHeaderAlignment( Alignment alignment ); + + /** + * @brief Sets the default value for data cells alignement. Used with column-free layout. + * @param alignment The desired alignment + * @return the TableLayout instance, for builder pattern + */ + TableLayout & setDefaultValueAlignment( Alignment alignment ); + /** * @brief check if a column max width has been set * @return Truef a column max width has been set, otherwise false @@ -681,29 +708,46 @@ class TableLayout size_t const & getMaxColumnWidth() const { return m_maxColumnWidth; } + /** + * @return The number of spaces at the left of the table. + */ + size_t const & getIndentation() const + { return m_indentation; } + /** * @brief Create and add columns to the columns vector given a string vector * @param columnNames The columns name + * @return the TableLayout instance, for builder pattern */ - void addColumns( stdVector< TableLayout::Column > const & columnNames ); + TableLayout & addColumns( stdVector< Column > const & columnNames ); /** * @brief Create and add columns to the columns vector given a string vector * @param columns The columns list + * @return the TableLayout instance, for builder pattern + */ + TableLayout & addColumns( stdVector< string > const & columns ); + + /** + * @brief Create and add columns to the columns vector given a string and/or columns + * @param columns brace enclosed parameters, consisting of column names or Column instances + * @return the TableLayout instance, for builder pattern */ - void addColumns( stdVector< string > const & columns ); + TableLayout & addColumns( TableLayoutArgs columns ); /** * @brief Create and add a column to the columns vector given a string * @param columnName The column name + * @return the TableLayout instance, for builder pattern */ - void addColumn( string_view columnName ); + TableLayout & addColumn( string_view columnName ); /** * @brief Create and add a column to the columns vector given a Column * @param column Vector containing addition information on the column + * @return the TableLayout instance, for builder pattern */ - void addColumn( TableLayout::Column const & column ); + TableLayout & addColumn( Column const & column ); protected: @@ -756,6 +800,15 @@ class TableLayout /// The number of margin spaces around contents. integer m_marginValue; + /// The number of spaces at the left of the table. + size_t m_indentation = 0; + + /// default value for columns header cells alignement. + Alignment m_defaultHeaderAlignment = Alignment::center; + + /// default value for data cells alignement. + Alignment m_defaultValueAlignment = Alignment::right; + }; /** @@ -814,6 +867,12 @@ class PreparedTableLayout : public TableLayout size_t getTotalLowermostColumnCount() const { return m_totalLowermostColumnCount; } + /** + * @return A string with the correct indentation space count to precede each lines of the formatted table. + */ + string_view getIndentationStr() const + { return m_indentationStr; } + private: // Number of column layers that a table layout has, default is 1; @@ -823,6 +882,8 @@ class PreparedTableLayout : public TableLayout // Numbers of lower most column that are visible size_t m_visibleLowermostColumnCount; + string m_indentationStr; + /** * @brief Recursive part of column layout preparation, see constructor documentation. * @param columns The list of columns to prepare. diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp new file mode 100644 index 00000000000..ad553f72771 --- /dev/null +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -0,0 +1,160 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + + +/** + * @file TableMpiComponents.cpp + */ + +#include "TableMpiComponents.hpp" +#include "common/MpiWrapper.hpp" + +namespace geos +{ + +TableTextMpiOutput::TableTextMpiOutput( TableMpiLayout mpiLayout ): + TableTextFormatter(), + m_mpiLayout( mpiLayout ) +{} + +TableTextMpiOutput::TableTextMpiOutput( TableLayout const & tableLayout, + TableMpiLayout mpiLayout ): + TableTextFormatter( tableLayout ), + m_mpiLayout( mpiLayout ) +{} + +template<> +void TableTextMpiOutput::toStream< TableData >( std::ostream & tableOutput, + TableData const & tableData ) const +{ + TableTextMpiOutput::Status status { + // m_isMasterRank (only the master rank does the output of the header && bottom of the table) + MpiWrapper::commRank() == 0, + // m_isContributing (some ranks does not have any output to produce) + !tableData.getCellsData().empty(), + // m_hasContent + false, + // m_sepLine + "" + }; + + CellLayoutRows headerCellsLayout; + CellLayoutRows dataCellsLayout; + CellLayoutRows errorCellsLayout; + size_t tableTotalWidth = 0; + + { + ColumnWidthModifier const columnWidthModifier = [this, status]( stdVector< size_t > & columnsWidth ) { + stretchColumnsByRanks( columnsWidth, status ); + }; + initalizeTableGrids( m_tableLayout, tableData, + headerCellsLayout, dataCellsLayout, errorCellsLayout, + tableTotalWidth, columnWidthModifier ); + status.m_sepLine = string( tableTotalWidth, m_horizontalLine ); + } + + if( status.m_isMasterRank ) + { + outputTableHeader( tableOutput, m_tableLayout, headerCellsLayout, status.m_sepLine ); + tableOutput.flush(); + } + + outputTableDataToRank0( tableOutput, m_tableLayout, dataCellsLayout, status ); + + if( status.m_isMasterRank ) + { + outputTableFooter( tableOutput, m_tableLayout, errorCellsLayout, + status.m_sepLine, status.m_hasContent ); + tableOutput.flush(); + } +} + +void TableTextMpiOutput::stretchColumnsByRanks( stdVector< size_t > & columnsWidth, + TableTextMpiOutput::Status const & status ) const +{ + { // we ensure we have the correct amount of columns on all ranks (for correct MPI reduction operation) + size_t const rankColumnsCount = columnsWidth.size(); + size_t const maxRanksColumnsCount = MpiWrapper::max( rankColumnsCount ); + + // TODO: contribute to the new table error system with this one + if( status.m_isContributing ) + GEOS_ASSERT_EQ( rankColumnsCount, maxRanksColumnsCount ); + + columnsWidth.resize( maxRanksColumnsCount, 0 ); + } + + // the ranks that does not contribute must not interfere in the column width computing + if( !status.m_isContributing ) + std::fill( columnsWidth.begin(), columnsWidth.end(), 0 ); + + // we keep the largest column widths so we have the same layout on all ranks + MpiWrapper::allReduce( columnsWidth, columnsWidth, MpiWrapper::Reduction::Max ); +} + +void TableTextMpiOutput::outputTableDataToRank0( std::ostream & tableOutput, + PreparedTableLayout const & tableLayout, + CellLayoutRows const & dataCellsLayout, + TableTextMpiOutput::Status & status ) const +{ + integer const ranksCount = MpiWrapper::commSize(); + + // master rank does the output directly to the output, other ranks will have to send it through a string. + std::ostringstream localStringStream; + std::ostream & rankOutput = status.m_isMasterRank ? tableOutput : localStringStream; + + if( status.m_isContributing ) + { + if( m_mpiLayout.m_separatorBetweenRanks ) + { + string const rankSepLine = GEOS_FMT( "{:-^{}}", m_mpiLayout.m_rankTitle, status.m_sepLine.size() - 2 ); + rankOutput << tableLayout.getIndentationStr() << m_verticalLine << rankSepLine << m_verticalLine << '\n'; + } + outputTableData( rankOutput, tableLayout, dataCellsLayout ); + } + + // all other ranks than rank 0 render their output in a string and comunicate its size + std::vector< integer > ranksStrsSizes = std::vector( ranksCount, 0 ); + string const rankStr = !status.m_isMasterRank && status.m_isContributing ? localStringStream.str() : ""; + integer const rankStrSize = rankStr.size(); + MpiWrapper::allgather( &rankStrSize, 1, ranksStrsSizes.data(), 1 ); + + // we compute the memory layout of the ranks strings + std::vector< integer > ranksStrsOffsets = std::vector( ranksCount, 0 ); + integer ranksStrsTotalSize = 0; + for( integer rankId = 1; rankId < ranksCount; ++rankId ) + { + ranksStrsOffsets[rankId] = ranksStrsTotalSize; + ranksStrsTotalSize += ranksStrsSizes[rankId]; + } + + // finally, we can send all text data to rank 0, then we output it in the output stream. + string ranksStrs = string( ranksStrsTotalSize, '\0' ); + MpiWrapper::gatherv( &rankStr[0], rankStrSize, + &ranksStrs[0], ranksStrsSizes.data(), ranksStrsOffsets.data(), + 0, MPI_COMM_GEOS ); + if( status.m_isMasterRank ) + { + for( integer rankId = 1; rankId < ranksCount; ++rankId ) + { + if( ranksStrsSizes[rankId] > 0 ) + { + status.m_hasContent = true; + tableOutput << string_view( &ranksStrs[ranksStrsOffsets[rankId]], ranksStrsSizes[rankId] ); + } + } + } +} + +} /* namespace geos */ diff --git a/src/coreComponents/common/format/table/TableMpiComponents.hpp b/src/coreComponents/common/format/table/TableMpiComponents.hpp new file mode 100644 index 00000000000..aeb37caa0ce --- /dev/null +++ b/src/coreComponents/common/format/table/TableMpiComponents.hpp @@ -0,0 +1,110 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file TableMpiComponents.hpp + * @brief contains variation of tables components for MPI communication. + */ + +#ifndef GEOS_COMMON_FORMAT_TABLE_TABLEMPICOMPONENTS_HPP +#define GEOS_COMMON_FORMAT_TABLE_TABLEMPICOMPONENTS_HPP + +#include "TableFormatter.hpp" + +namespace geos +{ + +/** + * @struct TableMpiLayout + * @brief Layout information specific to MPI distributed tables, completing those in TableLayout. + */ +struct TableMpiLayout +{ + /// Enable a separating line between ranks in the table output. + bool m_separatorBetweenRanks = false; + /// Title for each rank's section visible in the separating line. + string m_rankTitle; +}; + +/** + * @brief class to format data in a formatted text format, allowing contributions from multiple + * MPI ranks. + */ +class TableTextMpiOutput : public TableTextFormatter +{ +public: + /// base class + using Base = TableTextFormatter; + + /** + * @brief Construct a default Table Formatter without layout specification (to only insert data in it, + * without any column / title). Feature is not tested. + * @param mpiLayout MPI-specific layout information (default is having contiguous ranks data). + */ + TableTextMpiOutput( TableMpiLayout mpiLayout = TableMpiLayout() ); + + /** + * @brief Construct a new TableTextMpiOutput from a tableLayout + * @param tableLayout Contain all tableColumnData names and optionnaly the table title + * @param mpiLayout MPI-specific layout information (default is having contiguous ranks data). + */ + TableTextMpiOutput( TableLayout const & tableLayout, + TableMpiLayout mpiLayout = TableMpiLayout() ); + + /** + * @brief Convert a data source to a table string. + * @param tableData The data source to convert. + * @param outputStream The target output stream for rank 0, to output the table string representation + * of the TableData. Each rank contributing to the common rank 0 output stream + * with their local data. It may be the log or a file stream. + * @note This method must be called by all MPI ranks. + */ + template< typename DATASOURCE > + void toStream( std::ostream & outputStream, DATASOURCE const & tableData ) const; + +private: + + // hiding toString() methods as they are not implemented with MPI support. + using Base::toString; + + struct Status + { + bool const m_isMasterRank; + bool const m_isContributing; + bool m_hasContent; + string m_sepLine; + }; + + TableMpiLayout m_mpiLayout; + + /** + * @brief Expend the columns width to accomodate with the content of all MPI ranks. + * As it is based on MPI communications, every ranks must call this method. + * @param columnsWidth The array to store the resulting columns width in. + * @param tableGrid The grid of cells containing content. + */ + void stretchColumnsByRanks( stdVector< size_t > & columnsWidth, + Status const & status ) const; + + void outputTableDataToRank0( std::ostream & tableOutput, + PreparedTableLayout const & tableLayout, + CellLayoutRows const & dataCellsLayout, + Status & status ) const; + +}; + +} + +#endif /* GEOS_COMMON_FORMAT_TABLE_TABLEMPICOMPONENTS_HPP */ diff --git a/src/coreComponents/common/format/table/unitTests/CMakeLists.txt b/src/coreComponents/common/format/table/unitTests/CMakeLists.txt index f5a4a358e97..594f08577a7 100644 --- a/src/coreComponents/common/format/table/unitTests/CMakeLists.txt +++ b/src/coreComponents/common/format/table/unitTests/CMakeLists.txt @@ -2,6 +2,9 @@ set( gtest_geosx_tests testTable.cpp ) +set( gtest_geosx_mpi_tests + testMpiTable.cpp ) + set( dependencyList gtest common ${parallelDeps} ) # Add gtest C++ based tests @@ -16,3 +19,20 @@ foreach(test ${gtest_geosx_tests}) COMMAND ${test_name} ) endforeach() + +if( ENABLE_MPI ) + set( nranks 4 ) + + foreach( test ${gtest_geosx_mpi_tests} ) + get_filename_component( file_we ${test} NAME_WE ) + set( test_name ${file_we}_mpi ) + blt_add_executable( NAME ${test_name} + SOURCES ${test} + OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} + DEPENDS_ON ${dependencyList} ) + + geos_add_test( NAME ${test_name} + COMMAND ${test_name} -x ${nranks} + NUM_MPI_TASKS ${nranks} ) + endforeach() +endif() diff --git a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp new file mode 100644 index 00000000000..7b01cf49515 --- /dev/null +++ b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp @@ -0,0 +1,149 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +// Source includes +#include "common/format/table/TableMpiComponents.hpp" +#include "common/initializeEnvironment.hpp" +#include "common/MpiWrapper.hpp" +// TPL includes +#include +#include + +using namespace geos; + +class MpiTestScope +{ +public: + + MpiTestScope( int argc, char * argv[] ) + { + ::testing::InitGoogleTest( &argc, argv ); + geos::setupEnvironment( argc, argv ); + } + + ~MpiTestScope() + { + geos::cleanupEnvironment(); + } + +}; + +TEST( testMpiTables, testDifferentRankData ) +{ + struct TestCase + { + stdVector< stdVector< std::pair< integer, real64 > > > m_ranksValues; + string m_expectedResult; + }; + + stdVector< TestCase > const testCases = + { + { + { // m_ranksValues: in this test, rank 2 has no value + { {1, 0.502} }, + { {2, 0.624}, {3, 0.791} }, + {}, + { {4, 0.243}, {5, 0.804}, {6, 0.302} }, + }, + "\n" // m_expectedResult + "-------------------------------------------\n" + "| Summary of negative pressure elements |\n" + "|-----------------------------------------|\n" + "| Global Id | pressure [Pa] |\n" + "|------------------|----------------------|\n" + "|------------Rank 0, 1 values-------------|\n" + "| 1 | 0.502 |\n" + "|------------Rank 1, 2 values-------------|\n" + "| 2 | 0.624 |\n" + "| 3 | 0.791 |\n" + "|------------Rank 3, 3 values-------------|\n" + "| 4 | 0.243 |\n" + "| 5 | 0.804 |\n" + "| 6 | 0.302 |\n" + "-------------------------------------------\n" + }, + { // m_ranksValues: in this test, rank 0 has no value + { + {}, + { {4, 0.243}, {5, 0.804}, {6, 0.302} }, + { {1, 0.502} }, + { {2, 0.624}, {3, 0.791} }, + }, + "\n" // m_expectedResult + "-------------------------------------------\n" + "| Summary of negative pressure elements |\n" + "|-----------------------------------------|\n" + "| Global Id | pressure [Pa] |\n" + "|------------------|----------------------|\n" + "|------------Rank 1, 3 values-------------|\n" + "| 4 | 0.243 |\n" + "| 5 | 0.804 |\n" + "| 6 | 0.302 |\n" + "|------------Rank 2, 1 values-------------|\n" + "| 1 | 0.502 |\n" + "|------------Rank 3, 2 values-------------|\n" + "| 2 | 0.624 |\n" + "| 3 | 0.791 |\n" + "-------------------------------------------\n" + }, + }; + for( TestCase const & testCase: testCases ) + { + int const rankId = MpiWrapper::commRank(); + int const nbRanks = MpiWrapper::commSize(); + if( nbRanks > 1 ) + { + ASSERT_EQ( nbRanks, 4 ); + + TableLayout const layout = TableLayout(). + setTitle( "Summary of negative pressure elements" ). + addColumns( { "Global Id", "pressure [Pa]" } ). + setDefaultHeaderAlignment( TableLayout::Alignment::left ); + TableData data; + auto const & rankTestData = testCase.m_ranksValues[rankId]; + + TableMpiLayout mpiLayout; + mpiLayout.m_separatorBetweenRanks = true; + + if( !rankTestData.empty() ) + { + mpiLayout.m_rankTitle = GEOS_FMT( "Rank {}, {} values", rankId, rankTestData.size() ); + for( auto const & [id, value] : rankTestData ) + { + data.addRow( id, value ); + } + } + + TableTextMpiOutput const formatter = TableTextMpiOutput( layout, mpiLayout ); + std::ostringstream oss; + formatter.toStream( oss, data ); + if( rankId == 0 ) + { + EXPECT_STREQ( testCase.m_expectedResult.data(), + oss.str().data() ); + } + } + } +} + +int main( int argc, char * * argv ) +{ + int r; + { + MpiTestScope testScope{ argc, argv }; + r = RUN_ALL_TESTS(); + } + return r; +} diff --git a/src/coreComponents/common/format/table/unitTests/testTable.cpp b/src/coreComponents/common/format/table/unitTests/testTable.cpp index a5201f10818..b8f76efa758 100644 --- a/src/coreComponents/common/format/table/unitTests/testTable.cpp +++ b/src/coreComponents/common/format/table/unitTests/testTable.cpp @@ -18,8 +18,6 @@ #include "common/format/table/TableFormatter.hpp" #include "common/format/table/TableLayout.hpp" #include "dataRepository/Group.hpp" -#include "common/DataTypes.hpp" -#include "LvArray/src/MallocBuffer.hpp" // TPL includes #include #include @@ -216,7 +214,7 @@ TEST( testTable, tableHiddenColumn ) TEST( testTable, tableMergeOverflowParadox ) { string const title = "Lorem Ipsum"; - TableLayout tableLayout( title, + TableLayout const tableLayout( title, { TableLayout::Column() .setName( "A" ), @@ -858,6 +856,28 @@ TEST( testTable, tableSpecialsValues ) ); } +TEST( testTable, testTitleWithNoColumnIndented ) +{ + TableLayout const tableLayout = TableLayout(). + setTitle( "Title" ). + setIndentation( 4 ). + setMargin( TableLayout::MarginValue::small ); + + TableData tableData; + tableData.addRow( "Global Id", 1234, 40, 5678, 60 ); + tableData.addRow( "pressure", 0.1234, 0.40, 0.5678, 0.60 ); + + TableTextFormatter const tableText( tableLayout ); + EXPECT_EQ( tableText.toString( tableData ), + "\n" + " -------------------------------------------\n" + " | Title |\n" + " |-----------------------------------------|\n" + " | Global Id | 1234 | 40 | 5678 | 60 |\n" + " | pressure | 0.1234 | 0.4 | 0.5678 | 0.6 |\n" + " -------------------------------------------\n" + ); +} int main( int argc, char * * argv ) { diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/parameters/KValueFlashParameters.cpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/parameters/KValueFlashParameters.cpp index 8a5e751d640..6e40b9848c5 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/parameters/KValueFlashParameters.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/parameters/KValueFlashParameters.cpp @@ -381,7 +381,7 @@ bool KValueFlashParameters< NUM_PHASE >::validateKValues( MultiFluidBase const * } hasAtLeastOneNegative = hasAtLeastOneNegative || hasNegative; hasAtLeastOneOneSided = hasAtLeastOneOneSided || (allMoreThanUnity || allLessThanUnity); - if( (allMoreThanUnity || allLessThanUnity || hasNegative) && tableData.getTableDataRows().size() < 5 ) + if( (allMoreThanUnity || allLessThanUnity || hasNegative) && tableData.getCellsData().size() < 5 ) { tableRow[0].value = phaseNames[phaseIndex+1]; tableRow[1].value = GEOS_FMT( "{0:.3e}", m_pressureValues[0][pressureIndex] ); @@ -397,7 +397,7 @@ bool KValueFlashParameters< NUM_PHASE >::validateKValues( MultiFluidBase const * } } - if( !tableData.getTableDataRows().empty()) + if( !tableData.getCellsData().empty()) { std::vector< TableLayout::Column > columns; columns.emplace_back( TableLayout::Column().setName( "Phase" ).setValuesAlignment( TableLayout::Alignment::left ) ); diff --git a/src/coreComponents/physicsSolvers/LogLevelsInfo.hpp b/src/coreComponents/physicsSolvers/LogLevelsInfo.hpp index e11aca92b2e..73037d8bb04 100644 --- a/src/coreComponents/physicsSolvers/LogLevelsInfo.hpp +++ b/src/coreComponents/physicsSolvers/LogLevelsInfo.hpp @@ -91,6 +91,12 @@ struct Solution static constexpr std::string_view getDescription() { return "Solution information (scaling, maximum changes, quality check)"; } }; +struct SolutionDetails +{ + static constexpr int getMinLogLevel() { return 2; } + static constexpr std::string_view getDescription() { return "Solution details (incoherent negative values ids)"; } +}; + struct SolverInitialization { static constexpr int getMinLogLevel() { return 1; } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt b/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt index 6eb55e9775a..1f6bd171acc 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt +++ b/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt @@ -39,9 +39,11 @@ set( fluidFlowSolvers_headers SinglePhaseHybridFVM.hpp SinglePhaseProppantBase.hpp StencilAccessors.hpp + SolutionCheckHelpers.hpp StencilDataCollection.hpp LogLevelsInfo.hpp kernels/MinPoreVolumeMaxPorosityKernel.hpp + kernels/SolutionCheckKernelsHelpers.hpp kernels/StencilWeightsUpdateKernel.hpp kernels/HybridFVMHelperKernels.hpp kernels/singlePhase/AccumulationKernels.hpp @@ -154,6 +156,7 @@ set( fluidFlowSolvers_sources SinglePhaseProppantBase.cpp SinglePhaseReactiveTransport.cpp SourceFluxStatistics.cpp + SolutionCheckHelpers.cpp StencilDataCollection.cpp kernels/singlePhase/proppant/ProppantFluxKernels.cpp kernels/compositional/AquiferBCKernel.cpp diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp index 40a8b4ddd62..89aec54eb4f 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp @@ -37,6 +37,7 @@ #include "physicsSolvers/LogLevelsInfo.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/SolutionCheckHelpers.hpp" #include "physicsSolvers/fluidFlow/kernels/compositional/ResidualNormKernel.hpp" #include "physicsSolvers/fluidFlow/kernels/compositional/ThermalResidualNormKernel.hpp" #include "physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingKernel.hpp" @@ -848,7 +849,11 @@ bool CompositionalMultiphaseFVM::checkSystemSolution( DomainPartition & domain, string const dofKey = dofManager.getKey( viewKeyStruct::elemDofFieldString() ); integer localCheck = 1; real64 minPres = 0.0, minDens = 0.0, minTotalDens = 0.0; - integer numNegPres = 0, numNegDens = 0, numNegTotalDens = 0; + integer numNegTotalDens = 0; + ElementsReporterBuffer rankNegPressureIds{ isLogLevelActive< logInfo::Solution >( getLogLevel() ), + isLogLevelActive< logInfo::SolutionDetails >( getLogLevel() ) ? 16 : 0 }; + ElementsReporterBuffer rankNegDensityIds{ isLogLevelActive< logInfo::Solution >( getLogLevel() ), + isLogLevelActive< logInfo::SolutionDetails >( this->getLogLevel() ) ? 16 : 0 }; forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, MeshLevel & mesh, @@ -867,52 +872,57 @@ bool CompositionalMultiphaseFVM::checkSystemSolution( DomainPartition & domain, arrayView1d< real64 > pressureScalingFactor = subRegion.getField< flow::pressureScalingFactor >(); arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< flow::temperatureScalingFactor >(); arrayView1d< real64 > compDensScalingFactor = subRegion.getField< flow::globalCompDensityScalingFactor >(); + auto const & cellLocalToGlobalIds = subRegion.localToGlobalMap(); + auto const negPresCollector = rankNegPressureIds.createCollector( cellLocalToGlobalIds ); + auto const negDensCollector = rankNegDensityIds.createCollector( cellLocalToGlobalIds ); + // check that pressure and component densities are non-negative // for thermal, check that temperature is above 273.15 K const integer temperatureOffset = m_numComponents+1; - auto const subRegionData = - m_isThermal - ? thermalCompositionalMultiphaseBaseKernels:: - SolutionCheckKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping, - m_allowNegativePressure, - m_scalingType, - scalingFactor, - pressure, - temperature, - compDens, - pressureScalingFactor, - temperatureScalingFactor, - compDensScalingFactor, - dofManager.rankOffset(), - m_numComponents, - dofKey, - subRegion, - localSolution, - temperatureOffset ) - : isothermalCompositionalMultiphaseBaseKernels:: - SolutionCheckKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping, - m_allowNegativePressure, - m_scalingType, - scalingFactor, - pressure, - compDens, - pressureScalingFactor, - compDensScalingFactor, - dofManager.rankOffset(), - m_numComponents, - dofKey, - subRegion, - localSolution ); + auto const subRegionData = m_isThermal ? + thermalCompositionalMultiphaseBaseKernels:: + SolutionCheckKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping, + m_allowNegativePressure, + m_scalingType, + scalingFactor, + pressure, + temperature, + compDens, + pressureScalingFactor, + temperatureScalingFactor, + compDensScalingFactor, + dofManager.rankOffset(), + m_numComponents, + dofKey, + subRegion, + localSolution, + negPresCollector, + negDensCollector, + temperatureOffset ) : + isothermalCompositionalMultiphaseBaseKernels:: + SolutionCheckKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping, + m_allowNegativePressure, + m_scalingType, + scalingFactor, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor, + dofManager.rankOffset(), + m_numComponents, + dofKey, + subRegion, + localSolution, + negPresCollector, + negDensCollector ); localCheck = std::min( localCheck, subRegionData.localMinVal ); - minPres = std::min( minPres, subRegionData.localMinPres ); - minDens = std::min( minDens, subRegionData.localMinDens ); - minTotalDens = std::min( minTotalDens, subRegionData.localMinTotalDens ); - numNegPres += subRegionData.localNumNegPressures; - numNegDens += subRegionData.localNumNegDens; + minPres = std::min( minPres, subRegionData.localMinNegPres ); + minDens = std::min( minDens, subRegionData.localMinNegDens ); + minTotalDens = std::min( minTotalDens, subRegionData.localMinNegTotalDens ); numNegTotalDens += subRegionData.localNumNegTotalDens; } ); } ); @@ -920,23 +930,20 @@ bool CompositionalMultiphaseFVM::checkSystemSolution( DomainPartition & domain, minPres = MpiWrapper::min( minPres ); minDens = MpiWrapper::min( minDens ); minTotalDens = MpiWrapper::min( minTotalDens ); - numNegPres = MpiWrapper::sum( numNegPres ); - numNegDens = MpiWrapper::sum( numNegDens ); numNegTotalDens = MpiWrapper::sum( numNegTotalDens ); - if( numNegPres > 0 ) - GEOS_LOG_LEVEL_RANK_0( logInfo::Solution, - GEOS_FMT( " {}: Number of negative pressure values: {}, minimum value: {} Pa", - getName(), numNegPres, fmt::format( "{:.{}f}", minPres, 3 ) ) ); - string const massUnit = m_useMass ? "kg/m3" : "mol/m3"; - if( numNegDens > 0 ) - GEOS_LOG_LEVEL_RANK_0( logInfo::Solution, - GEOS_FMT( " {}: Number of negative component density values: {}, minimum value: {} {}}", - getName(), numNegDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) ); - if( minTotalDens > 0 ) + rankNegPressureIds.createOutput().outputTooLowValues( GEOS_FMT( " {}: ", getName() ), + "negative pressure", minPres, units::Unit::Pressure ); + + units::Unit const massUnit = m_useMass ? units::Unit::Density : units::Unit::MolarDensity; + rankNegDensityIds.createOutput().outputTooLowValues( GEOS_FMT( " {}: ", getName() ), + "negative component density", minDens, massUnit ); + if( numNegTotalDens > 0 ) + { GEOS_LOG_LEVEL_RANK_0( logInfo::Solution, - GEOS_FMT( " {}: Number of negative total density values: {}, minimum value: {} {}}", - getName(), minTotalDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) ); + GEOS_FMT( " {}: Number of negative total density values: {}, minimum value: {} {}", + getName(), numNegTotalDens, fmt::format( "{:.{}f}", minTotalDens, 3 ), units::getSymbol( massUnit ) ) ); + } return MpiWrapper::min( localCheck ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp index 68d14faaebd..ede2009eb62 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp @@ -622,7 +622,9 @@ bool CompositionalMultiphaseHybridFVM::checkSystemSolution( DomainPartition & do m_numComponents, elemDofKey, subRegion, - localSolution ); + localSolution, + ElementsReporterCollector::disabled(), + ElementsReporterCollector::disabled() ); localCheck = std::min( localCheck, subRegionData.localMinVal ); } ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.cpp index 713367c05f0..5bd38614c34 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.cpp @@ -39,6 +39,7 @@ #include "physicsSolvers/KernelLaunchSelectors.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/SolutionCheckHelpers.hpp" #include "physicsSolvers/fluidFlow/kernels/singlePhase/MobilityKernel.hpp" #include "physicsSolvers/fluidFlow/kernels/singlePhase/SolutionCheckKernel.hpp" #include "physicsSolvers/fluidFlow/kernels/singlePhase/SolutionScalingKernel.hpp" @@ -1327,7 +1328,8 @@ bool SinglePhaseBase::checkSystemSolution( DomainPartition & domain, GEOS_MARK_FUNCTION; string const dofKey = dofManager.getKey( viewKeyStruct::elemDofFieldString() ); - integer numNegativePressures = 0; + ElementsReporterBuffer rankNegPressureIds{ isLogLevelActive< logInfo::Solution >( getLogLevel() ), + isLogLevelActive< logInfo::SolutionDetails >( getLogLevel() ) ? 16 : 0 }; real64 minPressure = 0.0; forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, @@ -1342,23 +1344,25 @@ bool SinglePhaseBase::checkSystemSolution( DomainPartition & domain, arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); arrayView1d< real64 const > const pres = subRegion.getField< flow::pressure >(); - - auto const statistics = - singlePhaseBaseKernels::SolutionCheckKernel:: - launch< parallelDevicePolicy<> >( localSolution, rankOffset, dofNumber, ghostRank, pres, scalingFactor ); - - numNegativePressures += statistics.first; - minPressure = std::min( minPressure, statistics.second ); + auto const negPresCollector = rankNegPressureIds.createCollector( subRegion.localToGlobalMap().toViewConst() ); + + auto const statistics = singlePhaseBaseKernels::SolutionCheckKernel:: + launch< parallelDevicePolicy<> >( localSolution, + rankOffset, + dofNumber, + ghostRank, + pres, + scalingFactor, + negPresCollector ); + + minPressure = std::min( minPressure, statistics.minNegPres ); } ); } ); - numNegativePressures = MpiWrapper::sum( numNegativePressures ); - - if( numNegativePressures > 0 ) - GEOS_LOG_LEVEL_RANK_0( logInfo::Solution, GEOS_FMT( " {}: Number of negative pressure values: {}, minimum value: {} Pa", - getName(), numNegativePressures, fmt::format( "{:.{}f}", minPressure, 3 ) ) ); + rankNegPressureIds.createOutput().outputTooLowValues( GEOS_FMT( " {}: ", getName() ), + "negative pressure", minPressure, units::Unit::Pressure ); - return (m_allowNegativePressure || numNegativePressures == 0) ? 1 : 0; + return (m_allowNegativePressure || rankNegPressureIds.getSignaledElementsCount() == 0) ? 1 : 0; } void SinglePhaseBase::saveConvergedState( ElementSubRegionBase & subRegion ) const diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SolutionCheckHelpers.cpp b/src/coreComponents/physicsSolvers/fluidFlow/SolutionCheckHelpers.cpp new file mode 100644 index 00000000000..3d9366ef3b7 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/SolutionCheckHelpers.cpp @@ -0,0 +1,118 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolutionCheckKernel.cpp + */ + +#include "physicsSolvers/fluidFlow/SolutionCheckHelpers.hpp" +#include "common/MpiWrapper.hpp" +#include "common/format/StringUtilities.hpp" +#include "common/format/table/TableMpiComponents.hpp" + +namespace geos +{ + +ElementsReporterBuffer::ElementsReporterBuffer( bool enabled, ElementCount maxCollectionSize ): + m_elementsCounter( enabled ? 1 : 0 ), + m_elementsBuffer( enabled ? maxCollectionSize : 0 ) +{ + if( enabled ) + { + m_elementsCounter.zero(); + m_elementsBuffer.zero(); + } +} + +ElementsReporterCollector +ElementsReporterBuffer::createCollector( arrayView1d< globalIndex const > const & localToGlobalId ) const +{ + return ElementsReporterCollector( m_elementsCounter, m_elementsBuffer, localToGlobalId ); +} + +ElementsReporterOutput ElementsReporterBuffer::createOutput() const +{ + m_elementsCounter.move( LvArray::MemorySpace::host, false ); + m_elementsBuffer.move( LvArray::MemorySpace::host, false ); + return ElementsReporterOutput( *this ); +} + + +ElementsReporterOutput::ElementsReporterOutput( ElementsReporterBuffer const & buffer ): + m_buffer( buffer ), + m_ranksSignaledElementsCount( MpiWrapper::sum( buffer.getSignaledElementsCount() ) ), + m_ranksCollectedElementsCount( MpiWrapper::sum( buffer.getCollectedElementsCount() ) ) +{} + +void ElementsReporterOutput::outputTooLowValues( string_view linesPrefix, + string_view valueNaming, + real64 minValue, + units::Unit unit ) const +{ + if( m_buffer.enabled() ) + { + if( m_ranksSignaledElementsCount > 0 ) + { + string const minValueStr = GEOS_FMT( "{:.{}f} [{}]", minValue, 3, units::getSymbol( unit ) ); + GEOS_LOG_RANK_0( GEOS_FMT( "{}{} {} values encountered. Minimum value: {}.", + linesPrefix, m_ranksSignaledElementsCount, valueNaming, minValueStr ) ); + + if( m_ranksCollectedElementsCount > 0 ) + { + TableLayout const layout = TableLayout(). + setTitle( GEOS_FMT( "Summary of {} elements", valueNaming ) ). + addColumns( { "Global Id", units::getDescription( unit ) } ). + enableLineBreak( false ). + setIndentation( linesPrefix.size() ). + setDefaultHeaderAlignment( TableLayout::Alignment::left ); + TableData data; + integer const signaledCount = m_buffer.getSignaledElementsCount(); + integer const collectedCount = m_buffer.getCollectedElementsCount(); + integer const omittedCount = signaledCount - collectedCount; + + TableMpiLayout mpiLayout; + mpiLayout.m_separatorBetweenRanks = true; + + if( signaledCount > 0 ) + { + mpiLayout.m_rankTitle = GEOS_FMT( "Rank {}, {} / {} values", + MpiWrapper::commRank(), collectedCount, signaledCount ); + + for( ElementReport const & report : m_buffer ) + { + data.addRow( report.m_id, report.m_value ); + } + + // adding one last line for signaling partial data & readability + if( omittedCount > 0 ) + { + data.addRow( "...", "..." ); + } + } + + TableTextMpiOutput const formatter = TableTextMpiOutput( layout, mpiLayout ); + formatter.toStream( std::cout, data ); + GEOS_LOG_RANK_0( '\n' ); + } + else + { + GEOS_LOG( GEOS_FMT( "{}Increase the log level to enable a reporting of the {} values.", + string( linesPrefix.size(), ' ' ), valueNaming ) ); + } + } + } +} + +} // namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SolutionCheckHelpers.hpp b/src/coreComponents/physicsSolvers/fluidFlow/SolutionCheckHelpers.hpp new file mode 100644 index 00000000000..9965dcb3d75 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/SolutionCheckHelpers.hpp @@ -0,0 +1,190 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolutionCheckHelpers.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SOLUTIONCHECKHELPERS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SOLUTIONCHECKHELPERS_HPP + +#include "physicsSolvers/fluidFlow/kernels/SolutionCheckKernelsHelpers.hpp" +#include "common/Units.hpp" + +namespace geos +{ + +/** + * @brief A class to report elements collected by the solver. + */ +class ElementsReporterOutput +{ +public: + + /// Type alias for elements count (e.g., localIndex, globalIndex). + using ElementCount = ElementsReporterCollector::ElementCount; + + /** + * @brief Construct a preallocated buffer for collecting element ids in kernels. + * @param buffer The buffer that will be utilized for counting & collecting elements IDs during kernel execution. + */ + ElementsReporterOutput( ElementsReporterBuffer const & buffer ); + + /** + * @return The number of ranks that have signaled an id. + */ + ElementCount getRanksSignaledIdsCount() const + { return m_ranksSignaledElementsCount; } + + /** + * @return The total count of collected elements across all ranks for signaling ids. + */ + ElementCount getRanksCollectedIdsCount() const + { return m_ranksCollectedElementsCount; } + + /** + * @brief Report elements with values below a specified threshold in the log: + * Outputs lines indicating which variables have collected element ids whose corresponding + * solution components are too low, potentially signaling underflow or numerical instability. + * @param linesPrefix Prefix for the line of text to be printed + * @param valueNaming The name used when referring to variables within this context (e.g., "pressure", "density"). + * @param minValue Minimum acceptable solution component values. Values below this threshold are reported. + * @param valueUnit Unit in which `minValue` is expressed. + */ + void outputTooLowValues( string_view linesPrefix, + string_view valueNaming, + real64 minValue, + units::Unit valueUnit ) const; + +private: + + /// Preallocated buffer for collecting ids. + ElementsReporterBuffer const & m_buffer; + + /// Count of signaled elements per rank. + ElementCount m_ranksSignaledElementsCount; + + /// Total collected signaling id count across ranks. + ElementCount m_ranksCollectedElementsCount; + +}; + +/** + * @brief A buffer to count and store element ids during kernel execution. + * This facilitates the reporting mechanism by allowing a preallocated space for storing & counting elements. + */ +class ElementsReporterBuffer +{ +public: + + /// Type alias for elements count (e.g., localIndex, globalIndex). + using ElementCount = ElementsReporterCollector::ElementCount; + + /** + * @brief Construct a preallocated buffer to collect a limited quantity of ids in kernels. + * @param maxCollectionSize Limit of the buffer. + * If 0, the buffering functionnality is disabled and only the counting is enabled. + */ + ElementsReporterBuffer( bool enabled, ElementCount maxCollectionSize ); + + /** + * @brief Transfers ownership of an ElementsReporterBuffer to another instance (move semantics). + */ + ElementsReporterBuffer( ElementsReporterBuffer && other ) = default; + + /** + * @brief Transfers ownership of an ElementsReporterBuffer to another instance (move semantics). + */ + ElementsReporterBuffer & operator=( ElementsReporterBuffer && other ) = default; + + /** + * @brief Copying prevented as it doesn't seem relevant / useful. + */ + ElementsReporterBuffer( ElementsReporterBuffer const & ) = delete; + + /** + * @brief Copying prevented as it doesn't seem relevant / useful. + */ + ElementsReporterBuffer & operator=( ElementsReporterBuffer const & ) = delete; + + /** + * @return the count of signaled elements. + */ + ElementCount getSignaledElementsCount() const + { return m_elementsCounter.empty() ? 0 : m_elementsCounter[0]; } + + /** + * @return the collected elements that could effectivly be stored (zero if no collection is enabled). + */ + ElementCount getCollectedElementsCount() const + { return LvArray::math::min( getSignaledElementsCount(), m_elementsBuffer.size() ); } + + /** + * @return a reference to an element report by its ID within the buffer (0 -> collected count-1). + */ + ElementReport const & operator[]( ElementCount id ) const + { return m_elementsBuffer[id]; } + + /** + * @return iterator pointing at beginning of collected elements in the buffer. + */ + auto begin() const + { return m_elementsBuffer.begin(); } + + /** + * @return iterator pointing after the last collected element in the buffer. + */ + auto end() const + { return m_elementsBuffer.begin() + getCollectedElementsCount(); } + + /** + * @return true when the collection of elements is enabled. + */ + bool enabled() const + { return !m_elementsCounter.empty(); } + + /** + * @return true when there are no elements collected (always false when enabled() is false). + */ + bool empty() const + { return getCollectedElementsCount() == 0; } + + /** + * @return true if the collection of elements completely fills the buffer. + */ + bool isComplete() const + { return getCollectedElementsCount() < getSignaledElementsCount(); } + + /** + * @return A view on the ids array owned by the instance. -> change comment to explain the interest for kernels + */ + ElementsReporterCollector createCollector( arrayView1d< globalIndex const > const & localToGlobalId ) const; + + ElementsReporterOutput createOutput() const; + +private: + + // array of one element to get benefit of managed host-device memory. + array1d< ElementCount > m_elementsCounter; + + // Preallocated array of ids of detected elements + array1d< ElementReport > m_elementsBuffer; + +}; + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SOLUTIONCHECKHELPERS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/SolutionCheckKernelsHelpers.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/SolutionCheckKernelsHelpers.hpp new file mode 100644 index 00000000000..46a28a532b5 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/SolutionCheckKernelsHelpers.hpp @@ -0,0 +1,137 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolutionCheckKernelsHelpers.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SOLUTIONCHECKKERNELSHELPERS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SOLUTIONCHECKKERNELSHELPERS_HPP + +#include "common/DataTypes.hpp" + +namespace geos +{ + +class ElementsReporterBuffer; + +struct ElementReport +{ + /// the global id of the reported element + globalIndex m_id; + /// a value to report for the given element (i.e. a negative pressure, a density... Or if needed could be of a templated type for + /// composite values) + real64 m_value; +}; + +/** + * @brief Collects and reports elements ids and data using an atomic counter. + * This class provides functionality to collect data from multiple threads safely by incrementing + * through an atomic counter for each reported element's ID. The collected IDs are stored in a + * size limited buffer, which can be used later for reporting or analysis purposes. + */ +class ElementsReporterCollector +{ + friend class ElementsReporterBuffer; +public: + + using ElementCount = int32_t; + + /** + * @name Constructors + * @brief This object can be copied and moved as it only provides views to internal memory buffers. + */ + ///@{ + /** @cond DO_NOT_DOCUMENT */ + + ElementsReporterCollector( ElementsReporterCollector const & other ) = default; + + ElementsReporterCollector( ElementsReporterCollector && other ) = default; + + ElementsReporterCollector & operator=( ElementsReporterCollector const & other ) = default; + + ElementsReporterCollector & operator=( ElementsReporterCollector && other ) = default; + + /** @endcond */ + ///@} + + static ElementsReporterCollector disabled() + { + return ElementsReporterCollector( arrayView1d< ElementCount >(), + arrayView1d< ElementReport >(), + arrayView1d< globalIndex const >() ); + } + + /** + * @brief Collects a single element report and adds its ID to the output buffer if not disabled and + * there are available slots in the buffer. + * @tparam CollectorAtomicPolicy The atomic increment operation to use for thread-safe counter increments. + * @param report A constant reference to an `ElementReport` object containing data from a single element + */ + template< typename CollectorAtomicPolicy > + GEOS_HOST_DEVICE + void collectElement( CollectorAtomicPolicy, ElementReport const & report ) const + { + if( !m_elementsCounter.empty() ) + { + ElementCount const outputStart = RAJA::atomicInc< CollectorAtomicPolicy >( &m_elementsCounter[0] ); + + if( outputStart < m_elementsBuffer.size() ) + { + m_elementsBuffer[outputStart].m_id = m_localToGlobalId[report.m_id]; + m_elementsBuffer[outputStart].m_value = report.m_value; + } + } + } + + // // currently unused version for adding multiple ids from a given kernel + // template< typename AddedArray, typename ElementCount > + // GEOS_HOST_DEVICE + // void collectIds( AddedArray const & newIds, ElementCount newIdsCount ) + // { + // ElementCount const outputStart = RAJA::atomicAdd< CollectorAtomicPolicy >( &m_elementsCounter[0], newIdsCount ); + // ElementCount const maxNbIdToAdd = ElementCount( m_elementsBuffer.size() - outputStart ); + // newIdsCount = LvArray::math::min( newIdsCount, maxNbIdToAdd ); + // for( ElementCount i = 0; i < newIdsCount; ++i ) + // { + // m_elementsBuffer[outputStart + i] = newIds[i]; + // } + // } + +private: + + /// array of one element to get benefit of chai managed memory. + arrayView1d< ElementCount > m_elementsCounter; + + /// ids of detected elements, quantity limited to 'maxIdsCount' + arrayView1d< ElementReport > m_elementsBuffer; + + /// Maps local element IDs to their respective global indices. + arrayView1d< globalIndex const > m_localToGlobalId; + + ElementsReporterCollector( arrayView1d< ElementCount > const & elementsCounter, + arrayView1d< ElementReport > const & elementsBuffer, + arrayView1d< globalIndex const > const & localToGlobalId ): + m_elementsCounter( elementsCounter ), + m_elementsBuffer( elementsBuffer ), + m_localToGlobalId( localToGlobalId ) + {} + +}; + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SOLUTIONCHECKKERNELSHELPERS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp index 89d681bb02c..1e57ed629cf 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp @@ -21,6 +21,7 @@ #define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLUTIONCHECKKERNEL_HPP #include "physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingAndCheckingKernelBase.hpp" +#include "physicsSolvers/fluidFlow/kernels/SolutionCheckKernelsHelpers.hpp" namespace geos { @@ -71,7 +72,9 @@ class SolutionCheckKernel : public SolutionScalingAndCheckingKernelBase< integer integer const numComp, string const dofKey, ElementSubRegionBase const & subRegion, - arrayView1d< real64 const > const localSolution ) + arrayView1d< real64 const > const localSolution, + ElementsReporterCollector const & negPressureIds, + ElementsReporterCollector const & negDensityIds ) : Base( rankOffset, numComp, dofKey, @@ -84,44 +87,55 @@ class SolutionCheckKernel : public SolutionScalingAndCheckingKernelBase< integer m_allowCompDensChopping( allowCompDensChopping ), m_allowNegativePressure( allowNegativePressure ), m_scalingFactor( scalingFactor ), - m_scalingType( scalingType ) + m_scalingType( scalingType ), + m_negPressureIds( negPressureIds ), + m_negDensityIds( negDensityIds ) {} /** - * @struct StackVariables + * @struct KernelStats * @brief Kernel variables located on the stack */ - struct StackVariables : public Base::StackVariables + struct KernelStats : public Base::StackVariables { GEOS_HOST_DEVICE - StackVariables() - { } - - StackVariables( real64 _localMinVal, - real64 _localMinPres, - real64 _localMinDens, - real64 _localMinTotalDens, - integer _localNumNegPressures, - integer _localNumNegDens, - integer _localNumNegTotalDens ) + KernelStats(): + Base::StackVariables() + {} + + KernelStats( real64 _localMinVal, + real64 _localNegMinPres, + real64 _localMinNegDens, + real64 _localMinNegTotalDens, + integer _localNumNegTotalDens ) : Base::StackVariables( _localMinVal ), - localMinPres( _localMinPres ), - localMinDens( _localMinDens ), - localMinTotalDens( _localMinTotalDens ), - localNumNegPressures( _localNumNegPressures ), - localNumNegDens( _localNumNegDens ), + localMinNegPres( _localNegMinPres ), + localMinNegDens( _localMinNegDens ), + localMinNegTotalDens( _localMinNegTotalDens ), localNumNegTotalDens( _localNumNegTotalDens ) { } - real64 localMinPres; - real64 localMinDens; - real64 localMinTotalDens; + real64 localMinNegPres; + real64 localMinNegDens; + real64 localMinNegTotalDens; - integer localNumNegPressures; - integer localNumNegDens; - integer localNumNegTotalDens; + localIndex localNumNegTotalDens; // Can only be 0 or 1 in each kernel + }; + + /** + * @struct StackVariables + * @brief Kernel variables located on the stack + */ + struct StackVariables : public KernelStats + { + GEOS_HOST_DEVICE + StackVariables(): + KernelStats() + { } + localIndex localNumNegPres; + localIndex localNumNegDens; }; /** @@ -132,19 +146,20 @@ class SolutionCheckKernel : public SolutionScalingAndCheckingKernelBase< integer * @param[inout] kernelComponent the kernel component providing access to the compute function */ template< typename POLICY, typename KERNEL_TYPE > - static StackVariables + static KernelStats launch( localIndex const numElems, KERNEL_TYPE const & kernelComponent ) { - RAJA::ReduceMin< ReducePolicy< POLICY >, integer > globalMinVal( 1 ); + using reducePolicy = ReducePolicy< POLICY >; + using atomicPolicy = AtomicPolicy< POLICY >; - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minPres( 0.0 ); - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minDens( 0.0 ); - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minTotalDens( 0.0 ); + RAJA::ReduceMin< reducePolicy, integer > globalMinVal( 1 ); - RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegPressures( 0 ); - RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegDens( 0 ); - RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegTotalDens( 0 ); + RAJA::ReduceMin< reducePolicy, real64 > minPres( 0.0 ); + RAJA::ReduceMin< reducePolicy, real64 > minDens( 0.0 ); + RAJA::ReduceMin< reducePolicy, real64 > minTotalDens( 0.0 ); + + RAJA::ReduceSum< reducePolicy, localIndex > numNegTotalDens( 0 ); forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) { @@ -153,28 +168,30 @@ class SolutionCheckKernel : public SolutionScalingAndCheckingKernelBase< integer return; } - StackVariables stack; + StackVariables stack{}; kernelComponent.setup( ei, stack ); kernelComponent.compute( ei, stack ); globalMinVal.min( stack.localMinVal ); - minPres.min( stack.localMinPres ); - minDens.min( stack.localMinDens ); - minTotalDens.min( stack.localMinTotalDens ); + minPres.min( stack.localMinNegPres ); + minDens.min( stack.localMinNegDens ); + minTotalDens.min( stack.localMinNegTotalDens ); + + if( stack.localNumNegPres > 0 ) + kernelComponent.m_negPressureIds.collectElement( atomicPolicy{}, { ei, stack.localMinNegPres } ); + + if( stack.localNumNegDens > 0 ) + kernelComponent.m_negDensityIds.collectElement( atomicPolicy{}, { ei, stack.localMinNegDens } ); - numNegPressures += stack.localNumNegPressures; - numNegDens += stack.localNumNegDens; numNegTotalDens += stack.localNumNegTotalDens; } ); - return StackVariables( globalMinVal.get(), - minPres.get(), - minDens.get(), - minTotalDens.get(), - numNegPressures.get(), - numNegDens.get(), - numNegTotalDens.get() ); + return KernelStats( globalMinVal.get(), + minPres.get(), + minDens.get(), + minTotalDens.get(), + numNegTotalDens.get() ); } GEOS_HOST_DEVICE @@ -183,11 +200,11 @@ class SolutionCheckKernel : public SolutionScalingAndCheckingKernelBase< integer { Base::setup( ei, stack ); - stack.localMinPres = 0.0; - stack.localMinDens = 0.0; - stack.localMinTotalDens = 0.0; + stack.localMinNegPres = 0.0; + stack.localMinNegDens = 0.0; + stack.localMinNegTotalDens = 0.0; - stack.localNumNegPressures = 0; + stack.localNumNegPres = 0; stack.localNumNegDens = 0; stack.localNumNegTotalDens = 0; } @@ -220,15 +237,15 @@ class SolutionCheckKernel : public SolutionScalingAndCheckingKernelBase< integer bool const localScaling = m_scalingType == compositionalMultiphaseUtilities::ScalingType::Local; real64 const newPres = m_pressure[ei] + (localScaling ? m_pressureScalingFactor[ei] : m_scalingFactor) * m_localSolution[stack.localRow]; - if( newPres < 0 ) + if( newPres <= 0.0 ) { + stack.localNumNegPres = 1; + if( !m_allowNegativePressure ) - { stack.localMinVal = 0; - } - stack.localNumNegPressures += 1; - if( newPres < stack.localMinPres ) - stack.localMinPres = newPres; + + if( newPres < stack.localMinNegPres ) + stack.localMinNegPres = newPres; } // if component density chopping is not allowed, the time step fails if a component density is negative @@ -239,12 +256,13 @@ class SolutionCheckKernel : public SolutionScalingAndCheckingKernelBase< integer for( integer ic = 0; ic < m_numComp; ++ic ) { real64 const newDens = m_compDens[ei][ic] + (localScaling ? m_compDensScalingFactor[ei] : m_scalingFactor) * m_localSolution[stack.localRow + ic + 1]; - if( newDens < 0 ) + if( newDens <= 0.0 ) { + stack.localNumNegDens = 1; stack.localMinVal = 0; - stack.localNumNegDens += 1; - if( newDens < stack.localMinDens ) - stack.localMinDens = newDens; + + if( newDens < stack.localMinNegDens ) + stack.localMinNegDens = newDens; } } } @@ -256,12 +274,13 @@ class SolutionCheckKernel : public SolutionScalingAndCheckingKernelBase< integer real64 const newDens = m_compDens[ei][ic] + (localScaling ? m_compDensScalingFactor[ei] : m_scalingFactor) * m_localSolution[stack.localRow + ic + 1]; totalDens += ( newDens > 0.0 ) ? newDens : 0.0; } - if( totalDens < 0 ) + if( totalDens <= 0.0 ) { + stack.localNumNegTotalDens = 1; stack.localMinVal = 0; - stack.localNumNegTotalDens += 1; - if( totalDens < stack.localMinTotalDens ) - stack.localMinTotalDens = totalDens; + + if( totalDens < stack.localMinNegTotalDens ) + stack.localMinNegTotalDens = totalDens; } } @@ -282,6 +301,10 @@ class SolutionCheckKernel : public SolutionScalingAndCheckingKernelBase< integer /// scaling type (global or local) compositionalMultiphaseUtilities::ScalingType const m_scalingType; + ElementsReporterCollector const m_negPressureIds; + + ElementsReporterCollector const m_negDensityIds; + }; /** @@ -303,7 +326,7 @@ class SolutionCheckKernelFactory * @param[in] localSolution the Newton update */ template< typename POLICY > - static SolutionCheckKernel::StackVariables + static SolutionCheckKernel::KernelStats createAndLaunch( integer const allowCompDensChopping, integer const allowNegativePressure, compositionalMultiphaseUtilities::ScalingType const scalingType, @@ -316,11 +339,13 @@ class SolutionCheckKernelFactory integer const numComp, string const dofKey, ElementSubRegionBase & subRegion, - arrayView1d< real64 const > const localSolution ) + arrayView1d< real64 const > const localSolution, + ElementsReporterCollector const & negPressureIds, + ElementsReporterCollector const & negDensityIds ) { SolutionCheckKernel kernel( allowCompDensChopping, allowNegativePressure, scalingType, scalingFactor, pressure, compDens, pressureScalingFactor, compDensScalingFactor, rankOffset, - numComp, dofKey, subRegion, localSolution ); + numComp, dofKey, subRegion, localSolution, negPressureIds, negDensityIds ); return SolutionCheckKernel::launch< POLICY >( subRegion.size(), kernel ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionCheckKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionCheckKernel.hpp index b0447b33782..455eec757dd 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionCheckKernel.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionCheckKernel.hpp @@ -73,6 +73,8 @@ class SolutionCheckKernel : public isothermalCompositionalMultiphaseBaseKernels: string const dofKey, ElementSubRegionBase const & subRegion, arrayView1d< real64 const > const localSolution, + ElementsReporterCollector const & negPressureIds, + ElementsReporterCollector const & negDensityIds, integer const temperatureOffset ) : Base( allowCompDensChopping, allowNegativePressure, @@ -86,7 +88,9 @@ class SolutionCheckKernel : public isothermalCompositionalMultiphaseBaseKernels: numComp, dofKey, subRegion, - localSolution ), + localSolution, + negPressureIds, + negDensityIds ), m_temperature( temperature ), m_temperatureScalingFactor( temperatureScalingFactor ), m_temperatureOffset( temperatureOffset ) @@ -146,7 +150,7 @@ class SolutionCheckKernelFactory * @param[in] localSolution the Newton update */ template< typename POLICY > - static SolutionCheckKernel::StackVariables + static SolutionCheckKernel::KernelStats createAndLaunch( integer const allowCompDensChopping, integer const allowNegativePressure, compositionalMultiphaseUtilities::ScalingType const scalingType, @@ -162,11 +166,13 @@ class SolutionCheckKernelFactory string const dofKey, ElementSubRegionBase & subRegion, arrayView1d< real64 const > const localSolution, + ElementsReporterCollector const & negPressureIds, + ElementsReporterCollector const & negDensityIds, integer temperatureOffset ) { SolutionCheckKernel kernel( allowCompDensChopping, allowNegativePressure, scalingType, scalingFactor, pressure, temperature, compDens, pressureScalingFactor, compDensScalingFactor, temperatureScalingFactor, - rankOffset, numComp, dofKey, subRegion, localSolution, + rankOffset, numComp, dofKey, subRegion, localSolution, negPressureIds, negDensityIds, temperatureOffset ); return SolutionCheckKernel::launch< POLICY >( subRegion.size(), kernel ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolutionCheckKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolutionCheckKernel.hpp index 24529dda836..16bd95ea27d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolutionCheckKernel.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolutionCheckKernel.hpp @@ -22,6 +22,7 @@ #include "common/DataTypes.hpp" #include "common/GEOS_RAJA_Interface.hpp" +#include "physicsSolvers/fluidFlow/kernels/SolutionCheckKernelsHelpers.hpp" namespace geos { @@ -33,16 +34,24 @@ namespace singlePhaseBaseKernels struct SolutionCheckKernel { + + struct KernelStats + { + real64 minNegPres; + }; + template< typename POLICY > - static std::pair< integer, real64 > launch( arrayView1d< real64 const > const & localSolution, - globalIndex const rankOffset, - arrayView1d< globalIndex const > const & dofNumber, - arrayView1d< integer const > const & ghostRank, - arrayView1d< real64 const > const & pres, - real64 const scalingFactor ) + static KernelStats launch( arrayView1d< real64 const > const & localSolution, + globalIndex const rankOffset, + arrayView1d< globalIndex const > const & dofNumber, + arrayView1d< integer const > const & ghostRank, + arrayView1d< real64 const > const & pres, + real64 const scalingFactor, + ElementsReporterCollector const & negPressureIds ) { - RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegativePressures( 0 ); - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minPres( 0.0 ); + using reducePolicy = ReducePolicy< POLICY >; + using atomicPolicy = AtomicPolicy< POLICY >; + RAJA::ReduceMin< reducePolicy, real64 > minNegPres( 0.0 ); forAll< POLICY >( dofNumber.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) { @@ -51,16 +60,16 @@ struct SolutionCheckKernel localIndex const lid = dofNumber[ei] - rankOffset; real64 const newPres = pres[ei] + scalingFactor * localSolution[lid]; - if( newPres < 0.0 ) + if( newPres <= 0.0 ) { - numNegativePressures += 1; - minPres.min( newPres ); + minNegPres.min( newPres ); + negPressureIds.collectElement( atomicPolicy{}, { ei, newPres } ); } } } ); - return { numNegativePressures.get(), minPres.get() }; + return KernelStats{ minNegPres.get() }; } }; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 9f18e9741da..a786a4841e8 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -32,6 +32,7 @@ #include "mesh/WellElementSubRegion.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "physicsSolvers/LogLevelsInfo.hpp" +#include "physicsSolvers/fluidFlow/SolutionCheckHelpers.hpp" #include "physicsSolvers/fluidFlow/wells/LogLevelsInfo.hpp" #include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/wells/WellFields.hpp" @@ -1614,7 +1615,11 @@ CompositionalMultiphaseWell::checkSystemSolution( DomainPartition & domain, string const wellDofKey = dofManager.getKey( wellElementDofName() ); integer localCheck = 1; real64 minPres = 0.0, minDens = 0.0, minTotalDens = 0.0; - integer numNegPres = 0, numNegDens = 0, numNegTotalDens = 0; + integer numNegTotalDens = 0; + ElementsReporterBuffer rankNegPressureIds{ isLogLevelActive< logInfo::Solution >( getLogLevel() ), + isLogLevelActive< logInfo::SolutionDetails >( getLogLevel() ) ? 16 : 0 }; + ElementsReporterBuffer rankNegDensityIds{ isLogLevelActive< logInfo::Solution >( getLogLevel() ), + isLogLevelActive< logInfo::SolutionDetails >( this->getLogLevel() ) ? 16 : 0 }; forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, MeshLevel & mesh, @@ -1636,53 +1641,57 @@ CompositionalMultiphaseWell::checkSystemSolution( DomainPartition & domain, arrayView1d< real64 > pressureScalingFactor = subRegion.getField< well::pressureScalingFactor >(); arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< well::temperatureScalingFactor >(); arrayView1d< real64 > compDensScalingFactor = subRegion.getField< well::globalCompDensityScalingFactor >(); + auto const & cellLocalToGlobalIds = subRegion.localToGlobalMap(); + auto const negPresCollector = rankNegPressureIds.createCollector( cellLocalToGlobalIds ); + auto const negDensCollector = rankNegDensityIds.createCollector( cellLocalToGlobalIds ); // check that pressure and component densities are non-negative // for thermal, check that temperature is above 273.15 K const integer temperatureOffset = m_numComponents+2; - auto const subRegionData = - m_isThermal - ? thermalCompositionalMultiphaseBaseKernels:: - SolutionCheckKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping, - m_allowNegativePressure, - m_scalingType, - scalingFactor, - pressure, - temperature, - compDens, - pressureScalingFactor, - temperatureScalingFactor, - compDensScalingFactor, - dofManager.rankOffset(), - m_numComponents, - wellDofKey, - subRegion, - localSolution, - temperatureOffset ) - : isothermalCompositionalMultiphaseBaseKernels:: - SolutionCheckKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping, - m_allowNegativePressure, - m_scalingType, - scalingFactor, - pressure, - compDens, - pressureScalingFactor, - compDensScalingFactor, - dofManager.rankOffset(), - m_numComponents, - wellDofKey, - subRegion, - localSolution ); + auto const subRegionData = m_isThermal ? + thermalCompositionalMultiphaseBaseKernels:: + SolutionCheckKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping, + m_allowNegativePressure, + m_scalingType, + scalingFactor, + pressure, + temperature, + compDens, + pressureScalingFactor, + temperatureScalingFactor, + compDensScalingFactor, + dofManager.rankOffset(), + m_numComponents, + wellDofKey, + subRegion, + localSolution, + negPresCollector, + negDensCollector, + temperatureOffset ) : + isothermalCompositionalMultiphaseBaseKernels:: + SolutionCheckKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping, + m_allowNegativePressure, + m_scalingType, + scalingFactor, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor, + dofManager.rankOffset(), + m_numComponents, + wellDofKey, + subRegion, + localSolution, + negPresCollector, + negDensCollector ); localCheck = std::min( localCheck, subRegionData.localMinVal ); - minPres = std::min( minPres, subRegionData.localMinPres ); - minDens = std::min( minDens, subRegionData.localMinDens ); - minTotalDens = std::min( minTotalDens, subRegionData.localMinTotalDens ); - numNegPres += subRegionData.localNumNegPressures; - numNegDens += subRegionData.localNumNegDens; + minPres = std::min( minPres, subRegionData.localMinNegPres ); + minDens = std::min( minDens, subRegionData.localMinNegDens ); + minTotalDens = std::min( minTotalDens, subRegionData.localMinNegTotalDens ); numNegTotalDens += subRegionData.localNumNegTotalDens; } ); } ); @@ -1690,23 +1699,20 @@ CompositionalMultiphaseWell::checkSystemSolution( DomainPartition & domain, minPres = MpiWrapper::min( minPres ); minDens = MpiWrapper::min( minDens ); minTotalDens = MpiWrapper::min( minTotalDens ); - numNegPres = MpiWrapper::sum( numNegPres ); - numNegDens = MpiWrapper::sum( numNegDens ); numNegTotalDens = MpiWrapper::sum( numNegTotalDens ); - if( numNegPres > 0 ) - GEOS_LOG_LEVEL_RANK_0( logInfo::Solution, - GEOS_FMT( " {}: Number of negative well pressure values: {}, minimum value: {} Pa", - getName(), numNegPres, fmt::format( "{:.{}f}", minPres, 3 ) ) ); - string const massUnit = m_useMass ? "kg/m3" : "mol/m3"; - if( numNegDens > 0 ) - GEOS_LOG_LEVEL_RANK_0( logInfo::Solution, - GEOS_FMT( " {}: Number of negative well component density values: {}, minimum value: {} {} ", - getName(), numNegDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) ); - if( minTotalDens > 0 ) - GEOS_LOG_LEVEL_RANK_0( logInfo::Solution, - GEOS_FMT( " {}: Number of negative total well density values: {}, minimum value: {} {} ", - getName(), minTotalDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) ); + rankNegPressureIds.createOutput().outputTooLowValues( GEOS_FMT( " {}: ", getName() ), + "negative pressure", minPres, units::Unit::Pressure ); + + units::Unit const massUnit = m_useMass ? units::Unit::Density : units::Unit::MolarDensity; + rankNegDensityIds.createOutput().outputTooLowValues( GEOS_FMT( " {}: ", getName() ), + "negative component density", minDens, massUnit ); + if( numNegTotalDens > 0 ) + { + GEOS_LOG_LEVEL_RANK_0( logInfo::SolutionDetails, + GEOS_FMT( " {}: Number of negative total density values: {}, minimum value: {} {}", + getName(), numNegTotalDens, fmt::format( "{:.{}f}", minTotalDens, 3 ), units::getSymbol( massUnit ) ) ); + } return MpiWrapper::min( localCheck ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index 6414693bf22..875ddfba049 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -33,6 +33,7 @@ #include "physicsSolvers/LogLevelsInfo.hpp" #include "physicsSolvers/fluidFlow/wells/LogLevelsInfo.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp" +#include "physicsSolvers/fluidFlow/SolutionCheckHelpers.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/wells/WellFields.hpp" #include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" @@ -1016,8 +1017,9 @@ bool SinglePhaseWell::checkSystemSolution( DomainPartition & domain, GEOS_MARK_FUNCTION; string const wellDofKey = dofManager.getKey( wellElementDofName() ); - integer numNegativePressures = 0; - real64 minPressure = 0.0; + ElementsReporterBuffer rankNegPressureIds{ isLogLevelActive< logInfo::Solution >( getLogLevel() ), + isLogLevelActive< logInfo::SolutionDetails >( getLogLevel() ) ? 16 : 0 }; + real64 minNegPres = 0.0; forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel const & mesh, @@ -1041,25 +1043,26 @@ bool SinglePhaseWell::checkSystemSolution( DomainPartition & domain, arrayView1d< real64 const > const & pres = subRegion.getField< well::pressure >(); - auto const statistics = - singlePhaseBaseKernels::SolutionCheckKernel:: - launch< parallelDevicePolicy<> >( localSolution, rankOffset, dofNumber, ghostRank, pres, scalingFactor ); + auto const negPresCollector = rankNegPressureIds.createCollector( subRegion.localToGlobalMap().toViewConst() ); - numNegativePressures += statistics.first; - minPressure = std::min( minPressure, statistics.second ); + auto const results = singlePhaseBaseKernels::SolutionCheckKernel:: + launch< parallelDevicePolicy<> >( localSolution, + rankOffset, + dofNumber, + ghostRank, + pres, + scalingFactor, + negPresCollector ); + + minNegPres = std::min( minNegPres, results.minNegPres ); } ); } ); - numNegativePressures = MpiWrapper::sum( numNegativePressures ); - - if( numNegativePressures > 0 ) - { - GEOS_LOG_LEVEL_RANK_0( logInfo::Solution, - GEOS_FMT( " {}: Number of negative pressure values: {}, minimum value: {} Pa", - getName(), numNegativePressures, fmt::format( "{:.{}f}", minPressure, 3 ) ) ); - } + ElementsReporterOutput const rankNegPressureIdsOutput = rankNegPressureIds.createOutput(); + rankNegPressureIdsOutput.outputTooLowValues( GEOS_FMT( " {}: ", getName() ), + "negative pressure", minNegPres, units::Unit::Pressure ); - return (m_allowNegativePressure || numNegativePressures == 0) ? 1 : 0; + return (m_allowNegativePressure || rankNegPressureIdsOutput.getRanksSignaledIdsCount() == 0) ? 1 : 0; } void From 66863a1f30870d29106083e4280918e570ac38e8 Mon Sep 17 00:00:00 2001 From: arng40 Date: Wed, 18 Feb 2026 11:26:14 +0100 Subject: [PATCH 09/70] 1st version mpi table --- src/coreComponents/common/MpiWrapper.cpp | 221 ++++++++++-------- src/coreComponents/common/MpiWrapper.hpp | 7 +- .../format/table/TableMpiComponents.cpp | 39 +--- .../mesh/ElementRegionManager.cpp | 109 ++++----- 4 files changed, 187 insertions(+), 189 deletions(-) diff --git a/src/coreComponents/common/MpiWrapper.cpp b/src/coreComponents/common/MpiWrapper.cpp index 682dbc2facc..2cb5ae54ded 100644 --- a/src/coreComponents/common/MpiWrapper.cpp +++ b/src/coreComponents/common/MpiWrapper.cpp @@ -518,111 +518,148 @@ template<> MPI_Datatype getMpiPairType< double, double >() } /* namespace internal */ - template<> -void MpiWrapper::gatherStringSet< stdVector >( stdVector< string > const & strSet, - stdVector< string > & result, - MPI_Comm MPI_PARAM( comm )) +void MpiWrapper::gatherString< std::function< void(string_view) > > + ( string const & rankStr, std::function< void(string_view) > && func ) { - int rank = MpiWrapper::commRank(); - int size = MpiWrapper::commSize(); - - string localAllStrings; - stdVector< int > localStrSizes; - localAllStrings.reserve( strSet.size() * 32 ); - - for( auto const & str : strSet ) - { - localAllStrings += str; - localStrSizes.push_back( static_cast< int >(str.size())); - } + integer const ranksCount = MpiWrapper::commSize(); + integer const currRank = MpiWrapper::commRank(); + // all other ranks than rank 0 render their output in a string and comunicate its size + std::vector< integer > ranksStrsSizes = std::vector( ranksCount, 0 ); - //1 - We gather the metadata across all ranks - struct MetaData - { - int count; - int size; - }; - MetaData localMeta = { static_cast< int >(strSet.size()), static_cast< int >(localAllStrings.size()) }; + integer const rankStrSize = rankStr.size(); + MpiWrapper::gather( &rankStrSize, 1, ranksStrsSizes.data(), 1, 0 ); - stdVector< MetaData > allMeta; - if( rank == 0 ) + // we compute the memory layout of the ranks strings + std::vector< integer > ranksStrsOffsets = std::vector( ranksCount, 0 ); + integer ranksStrsTotalSize = 0; + for( integer rankId = 0; rankId < ranksCount; ++rankId ) { - allMeta.resize( size ); + ranksStrsOffsets[rankId] = ranksStrsTotalSize; + ranksStrsTotalSize += ranksStrsSizes[rankId]; } - int localMetaArr[2] = { localMeta.count, localMeta.size }; - stdVector< int > allMetaArr; - - if( rank == 0 ) - allMetaArr.resize( size * 2 ); - - MpiWrapper::gather( localMetaArr, 2, allMetaArr.data(), 2, 0, comm ); - - //2 - Prepare displacement arrays for rank 0 - stdVector< int > allStrSizes; - string allStrings; - stdVector< int > counts_counts( size ); - stdVector< int > displs_counts( size ); - stdVector< int > counts_chars( size ); - stdVector< int > displs_chars( size ); - - int totalStrCount = 0; - - if( rank == 0 ) + // finally, we can send all text data to rank 0, then we output it in the output stream. + string ranksStrs = string( ranksStrsTotalSize, '\0' ); + MpiWrapper::gatherv( rankStr.data(), rankStrSize, + ranksStrs.data(), ranksStrsSizes.data(), ranksStrsOffsets.data(), + 0, MPI_COMM_GEOS ); + if( currRank == 0 ) { - int currentCountOffset = 0; - int currentCharOffset = 0; - - for( int currRank = 0; currRank < size; ++currRank ) + for( integer rankId = 0; rankId < ranksCount; ++rankId ) { - int c_count = allMetaArr[2*currRank]; - int c_size = allMetaArr[2*currRank + 1]; - - counts_counts[currRank] = c_count; - displs_counts[currRank] = currentCountOffset; - - counts_chars[currRank] = c_size; - displs_chars[currRank] = currentCharOffset; - - currentCountOffset += c_count; - currentCharOffset += c_size; - } - - totalStrCount = currentCountOffset; - - allStrSizes.resize( totalStrCount ); - allStrings.resize( currentCharOffset ); - } - - // 3. Gatherv des tailles de chaรฎnes - MpiWrapper::gatherv( localStrSizes.data(), localMeta.count, - allStrSizes.data(), counts_counts.data(), displs_counts.data(), - 0, comm ); - - // 4. Gatherv du contenu (chars) - MpiWrapper::gatherv( localAllStrings.c_str(), localMeta.size, - allStrings.data(), counts_chars.data(), displs_chars.data(), - 0, comm ); - - // 5. Reconstruction - if( rank == 0 ) - { - const char * dataPtr = allStrings.c_str(); - int currentOffset = 0; - for( int i = 0; i < totalStrCount; ++i ) - { - int len = allStrSizes[i]; - - std::string const temp( dataPtr + currentOffset, len ); - - result.emplace( result.end(), temp ); - currentOffset += len; + if( ranksStrsSizes[rankId] > 0 ) + { + func( string_view( ranksStrs.data() + ranksStrsOffsets[rankId], ranksStrsSizes[rankId] ) ); + } } } - } +// template<> +// void MpiWrapper::gatherStringSet< stdVector >( stdVector< string > const & strSet, +// stdVector< string > & result, +// MPI_Comm MPI_PARAM( comm )) +// { +// int rank = MpiWrapper::commRank(); +// int size = MpiWrapper::commSize(); + +// string localAllStrings; +// stdVector< int > localStrSizes; +// localAllStrings.reserve( strSet.size() * 32 ); + +// for( auto const & str : strSet ) +// { +// localAllStrings += str; +// localStrSizes.push_back( static_cast< int >(str.size())); +// } + +// //1 - We gather the metadata across all ranks +// struct MetaData +// { +// int count; +// int size; +// }; +// MetaData localMeta = { static_cast< int >(strSet.size()), static_cast< int >(localAllStrings.size()) }; + +// stdVector< MetaData > allMeta; +// if( rank == 0 ) +// { +// allMeta.resize( size ); +// } + +// int localMetaArr[2] = { localMeta.count, localMeta.size }; +// stdVector< int > allMetaArr; + +// if( rank == 0 ) +// allMetaArr.resize( size * 2 ); + +// MpiWrapper::gather( localMetaArr, 2, allMetaArr.data(), 2, 0, comm ); + +// //2 - Prepare displacement arrays for rank 0 +// stdVector< int > allStrSizes; +// string allStrings; +// stdVector< int > counts_counts( size ); +// stdVector< int > displs_counts( size ); +// stdVector< int > counts_chars( size ); +// stdVector< int > displs_chars( size ); + +// int totalStrCount = 0; + +// if( rank == 0 ) +// { +// int currentCountOffset = 0; +// int currentCharOffset = 0; + +// for( int currRank = 0; currRank < size; ++currRank ) +// { +// int c_count = allMetaArr[2*currRank]; +// int c_size = allMetaArr[2*currRank + 1]; + +// counts_counts[currRank] = c_count; +// displs_counts[currRank] = currentCountOffset; + +// counts_chars[currRank] = c_size; +// displs_chars[currRank] = currentCharOffset; + +// currentCountOffset += c_count; +// currentCharOffset += c_size; +// } + +// totalStrCount = currentCountOffset; + +// allStrSizes.resize( totalStrCount ); +// allStrings.resize( currentCharOffset ); +// } + +// // 3. Gatherv des tailles de chaรฎnes +// MpiWrapper::gatherv( localStrSizes.data(), localMeta.count, +// allStrSizes.data(), counts_counts.data(), displs_counts.data(), +// 0, comm ); + +// // 4. Gatherv du contenu (chars) +// MpiWrapper::gatherv( localAllStrings.c_str(), localMeta.size, +// allStrings.data(), counts_chars.data(), displs_chars.data(), +// 0, comm ); + +// // 5. Reconstruction +// if( rank == 0 ) +// { +// const char * dataPtr = allStrings.c_str(); +// int currentOffset = 0; +// for( int i = 0; i < totalStrCount; ++i ) +// { +// int len = allStrSizes[i]; + +// std::string const temp( dataPtr + currentOffset, len ); + +// result.emplace( result.end(), temp ); +// currentOffset += len; +// } +// } + +// } + } /* namespace geos */ #if defined(__clang__) diff --git a/src/coreComponents/common/MpiWrapper.hpp b/src/coreComponents/common/MpiWrapper.hpp index 4b7428770d7..2377e023d71 100644 --- a/src/coreComponents/common/MpiWrapper.hpp +++ b/src/coreComponents/common/MpiWrapper.hpp @@ -332,10 +332,9 @@ struct MpiWrapper */ static int nodeCommSize(); - template< template< class > class CONTAINER = stdVector > - void static gatherStringSet( CONTAINER< string > const & strSet, - CONTAINER< string > & result, - MPI_Comm MPI_PARAM( comm )); + template< typename FUNC > + static void gatherString( string const & str, + FUNC && func ); /** * @brief Strongly typed wrapper around MPI_Allgather. diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index ad553f72771..b7acbd2a69e 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -20,6 +20,8 @@ #include "TableMpiComponents.hpp" #include "common/MpiWrapper.hpp" +#include +#include namespace geos { @@ -108,8 +110,6 @@ void TableTextMpiOutput::outputTableDataToRank0( std::ostream & tableOutput, CellLayoutRows const & dataCellsLayout, TableTextMpiOutput::Status & status ) const { - integer const ranksCount = MpiWrapper::commSize(); - // master rank does the output directly to the output, other ranks will have to send it through a string. std::ostringstream localStringStream; std::ostream & rankOutput = status.m_isMasterRank ? tableOutput : localStringStream; @@ -123,38 +123,11 @@ void TableTextMpiOutput::outputTableDataToRank0( std::ostream & tableOutput, } outputTableData( rankOutput, tableLayout, dataCellsLayout ); } - - // all other ranks than rank 0 render their output in a string and comunicate its size - std::vector< integer > ranksStrsSizes = std::vector( ranksCount, 0 ); string const rankStr = !status.m_isMasterRank && status.m_isContributing ? localStringStream.str() : ""; - integer const rankStrSize = rankStr.size(); - MpiWrapper::allgather( &rankStrSize, 1, ranksStrsSizes.data(), 1 ); - - // we compute the memory layout of the ranks strings - std::vector< integer > ranksStrsOffsets = std::vector( ranksCount, 0 ); - integer ranksStrsTotalSize = 0; - for( integer rankId = 1; rankId < ranksCount; ++rankId ) - { - ranksStrsOffsets[rankId] = ranksStrsTotalSize; - ranksStrsTotalSize += ranksStrsSizes[rankId]; - } - - // finally, we can send all text data to rank 0, then we output it in the output stream. - string ranksStrs = string( ranksStrsTotalSize, '\0' ); - MpiWrapper::gatherv( &rankStr[0], rankStrSize, - &ranksStrs[0], ranksStrsSizes.data(), ranksStrsOffsets.data(), - 0, MPI_COMM_GEOS ); - if( status.m_isMasterRank ) - { - for( integer rankId = 1; rankId < ranksCount; ++rankId ) - { - if( ranksStrsSizes[rankId] > 0 ) - { - status.m_hasContent = true; - tableOutput << string_view( &ranksStrs[ranksStrsOffsets[rankId]], ranksStrsSizes[rankId] ); - } - } - } + MpiWrapper::gatherString( rankStr, std::function< void(string_view) >( [&]( string_view str ){ + status.m_hasContent = true; + tableOutput << str; + } )); } } /* namespace geos */ diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index 01d4f44ae88..19971b5e042 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -14,7 +14,9 @@ */ #include +#include #include +#include #include #include "ElementRegionManager.hpp" @@ -25,9 +27,13 @@ #include "common/MpiWrapper.hpp" #include "common/StdContainerWrappers.hpp" #include "common/TimingMacros.hpp" +#include "common/format/table/TableData.hpp" +#include "common/format/table/TableFormatter.hpp" +#include "common/format/table/TableMpiComponents.hpp" #include "common/logger/Logger.hpp" #include "dataRepository/BufferOps.hpp" #include "mesh/ElementSubRegionBase.hpp" +#include "mesh/PerforationData.hpp" #include "mesh/WellElementRegion.hpp" #include "mesh/WellElementSubRegion.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" @@ -195,7 +201,7 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM MeshLevel & meshLevel ) { NodeManager & nodeManager = meshLevel.getNodeManager(); - + int const rankId = MpiWrapper::commRank(); // get the offsets to construct local-to-global maps for well nodes and elements nodeManager.setMaxGlobalIndex(); globalIndex const nodeOffsetGlobal = nodeManager.maxGlobalIndex() + 1; @@ -240,80 +246,63 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM } ); - int rank = MpiWrapper::commRank(); - // int size = MpiWrapper::commSize(); - forElementRegions< WellElementRegion >( [&]( WellElementRegion const & wellRegion ){ - WellElementSubRegion const & wellSubRegion = wellRegion.getGroup( ElementRegionBase::viewKeyStruct::elementSubRegions() ) .getGroup< WellElementSubRegion >( wellRegion.getSubRegionName() ); - TableData dataPerforation; - TableLayout const layoutPerforation ( GEOS_FMT( "Well '{}' Perforation Table", wellRegion.getWellGeneratorName()), - { "Perforation no.", "Well element no.", "Coordinates", - "Cell region", "Cell sub-region", "Cell ID" } ); - for( globalIndex iperf = 0; iperf < wellSubRegion.getPerforationData()->getNumPerforationsGlobal(); ++iperf ) - { - globalIndex const cellId = wellSubRegion.getPerforationData()->getReservoirElementGlobalIndex()[iperf]; - if( cellId != -1 ) + TableLayout const layoutPerforation ( GEOS_FMT( "Well '{}' Perforation Table", + wellRegion.getWellGeneratorName()), { - auto const & meshElems = wellSubRegion.getPerforationData()->getMeshElements(); - localIndex const targetRegionIndex = meshElems.m_toElementRegion[iperf]; - localIndex const targetSubRegionIndex = meshElems.m_toElementSubRegion[iperf]; - ElementRegionBase const & region = meshLevel.getElemManager().getRegion< ElementRegionBase >( targetRegionIndex ); - ElementSubRegionBase const & subRegion = region.getSubRegion< ElementSubRegionBase >( targetSubRegionIndex ); - - arrayView2d< const real64 > perfLocation = wellSubRegion.getPerforationData()->getLocation(); + "Perforation", "Well element", "Coordinates", + "Cell region", "Cell sub-region", "Cell ID" + } ); - stdVector< string > setRegionName( {region.getName()} ); - stdVector< string > resultRegionName; - stdVector< string > setSubRegionName( {subRegion.getName()} ); - stdVector< string > resultSubRegionName; - MpiWrapper::gatherStringSet< stdVector >( setRegionName, resultRegionName, MPI_COMM_WORLD ); - MpiWrapper::gatherStringSet< stdVector >( setSubRegionName, resultSubRegionName, MPI_COMM_WORLD ); - array1d< globalIndex > rcvPerfo; - rcvPerfo.resize( 3 ); + PerforationData const * wellSubRegionPerforationData= wellSubRegion.getPerforationData(); + arrayView2d< const real64 > wsrPerfLocation = wellSubRegionPerforationData->getLocation(); + TableData localPerfoData; + int nbPerfoPerRank = 0; + for( globalIndex iperfLocal = 0; iperfLocal < wellSubRegionPerforationData->getNumPerforationsGlobal(); ++iperfLocal ) + { + integer cellId = wellSubRegionPerforationData->getReservoirElementGlobalIndex()[iperfLocal]; + arrayView1d< globalIndex const >const globalIperf = wellSubRegionPerforationData->localToGlobalMap(); - if( rank == 0 ) - { - if( perfLocation.empty()) - { - MpiWrapper::recv( rcvPerfo, MPI_ANY_SOURCE, 123, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); - } - else - { - LvArray::forValuesInSlice( perfLocation.toSlice(), [&]( real64 const & v ){rcvPerfo.emplace_back( v ); } ); - } - } - else - { - if( !perfLocation.empty()) - { - MpiWrapper::send( perfLocation.data(), 3, 0, 123, MPI_COMM_WORLD ); - } - } + array1d< integer > localCoords; + if( cellId != 0 ) + { + auto const & meshElems = wellSubRegionPerforationData->getMeshElements(); + localIndex const targetRegionIndex = meshElems.m_toElementRegion[iperfLocal]; + localIndex const targetSubRegionIndex = meshElems.m_toElementSubRegion[iperfLocal]; - if( rank == 0 ) - { - std::cout << "destBuffer "<< rcvPerfo[0]<< " "<getWellElements()[iperf], - perfLocation[iperf], - resultRegionName[0], - setSubRegionName[0], - cellId ); - } + ElementRegionBase const & region = + meshLevel.getElemManager().getRegion< ElementRegionBase >( targetRegionIndex ); + ElementSubRegionBase const & subRegion = region.getSubRegion< ElementSubRegionBase >( targetSubRegionIndex ); + integer localWellElemIndices = wellSubRegion.getGlobalWellElementIndex()[iperfLocal]; + localCoords.emplace_back( wsrPerfLocation[iperfLocal][0] ); + localCoords.emplace_back( wsrPerfLocation[iperfLocal][1] ); + localCoords.emplace_back( wsrPerfLocation[iperfLocal][2] ); + localPerfoData.addRow( globalIperf[iperfLocal], localWellElemIndices, localCoords, + region.getName(), subRegion.getName(), cellId ); + + nbPerfoPerRank++; } } - if( dataPerforation.getCellsData().size() > 0 ) + + TableMpiLayout mpiLayout; + mpiLayout.m_separatorBetweenRanks = true; + mpiLayout.m_rankTitle = GEOS_FMT( "Rank {}, {} perforations", rankId, nbPerfoPerRank ); + TableTextMpiOutput const formatter = TableTextMpiOutput( layoutPerforation, mpiLayout ); + std::ostringstream osss; + formatter.toStream( osss, localPerfoData ); + if( rankId == 0 ) { - TableTextFormatter const formatter( layoutPerforation ); - GEOS_LOG_RANK_0( formatter.toString( dataPerforation )); + TableTextFormatter const globalFormatter( layoutPerforation ); + + GEOS_LOG( osss.str()); } + } ); // communicate to rebuild global node info since we modified global ordering From d6128eebe4d3e9b1da47b2bc2b8c380737684d9b Mon Sep 17 00:00:00 2001 From: arng40 Date: Wed, 18 Feb 2026 11:44:23 +0100 Subject: [PATCH 10/70] new version mpi table : sorted --- .../format/table/TableMpiComponents.cpp | 11 ++++++++++- .../mesh/ElementRegionManager.cpp | 19 ++++++------------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index b7acbd2a69e..3b2a9ed24e4 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -20,6 +20,7 @@ #include "TableMpiComponents.hpp" #include "common/MpiWrapper.hpp" +#include #include #include @@ -124,10 +125,18 @@ void TableTextMpiOutput::outputTableDataToRank0( std::ostream & tableOutput, outputTableData( rankOutput, tableLayout, dataCellsLayout ); } string const rankStr = !status.m_isMasterRank && status.m_isContributing ? localStringStream.str() : ""; + stdVector< string > strs; MpiWrapper::gatherString( rankStr, std::function< void(string_view) >( [&]( string_view str ){ status.m_hasContent = true; - tableOutput << str; + strs.emplace_back( str ); } )); + + if( status.m_isMasterRank && status.m_hasContent ) + { + std::sort( strs.begin(), strs.end()); + for( auto const & strSorted : strs ) + tableOutput << strSorted; + } } } /* namespace geos */ diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index 19971b5e042..06104e52588 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -260,11 +260,10 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM PerforationData const * wellSubRegionPerforationData= wellSubRegion.getPerforationData(); arrayView2d< const real64 > wsrPerfLocation = wellSubRegionPerforationData->getLocation(); TableData localPerfoData; - int nbPerfoPerRank = 0; for( globalIndex iperfLocal = 0; iperfLocal < wellSubRegionPerforationData->getNumPerforationsGlobal(); ++iperfLocal ) { - integer cellId = wellSubRegionPerforationData->getReservoirElementGlobalIndex()[iperfLocal]; - arrayView1d< globalIndex const >const globalIperf = wellSubRegionPerforationData->localToGlobalMap(); + integer const cellId = wellSubRegionPerforationData->getReservoirElementGlobalIndex()[iperfLocal]; + arrayView1d< globalIndex const > const globalIperf = wellSubRegionPerforationData->localToGlobalMap(); array1d< integer > localCoords; if( cellId != 0 ) @@ -278,31 +277,25 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM meshLevel.getElemManager().getRegion< ElementRegionBase >( targetRegionIndex ); ElementSubRegionBase const & subRegion = region.getSubRegion< ElementSubRegionBase >( targetSubRegionIndex ); - integer localWellElemIndices = wellSubRegion.getGlobalWellElementIndex()[iperfLocal]; + integer const localWellElemIndices = wellSubRegion.getGlobalWellElementIndex()[iperfLocal]; localCoords.emplace_back( wsrPerfLocation[iperfLocal][0] ); localCoords.emplace_back( wsrPerfLocation[iperfLocal][1] ); localCoords.emplace_back( wsrPerfLocation[iperfLocal][2] ); localPerfoData.addRow( globalIperf[iperfLocal], localWellElemIndices, localCoords, region.getName(), subRegion.getName(), cellId ); - - nbPerfoPerRank++; } } TableMpiLayout mpiLayout; - mpiLayout.m_separatorBetweenRanks = true; - mpiLayout.m_rankTitle = GEOS_FMT( "Rank {}, {} perforations", rankId, nbPerfoPerRank ); TableTextMpiOutput const formatter = TableTextMpiOutput( layoutPerforation, mpiLayout ); - std::ostringstream osss; - formatter.toStream( osss, localPerfoData ); + std::ostringstream outputStream; + formatter.toStream( outputStream, localPerfoData ); if( rankId == 0 ) { TableTextFormatter const globalFormatter( layoutPerforation ); - - GEOS_LOG( osss.str()); + GEOS_LOG( outputStream.str()); } - } ); // communicate to rebuild global node info since we modified global ordering From 254f20ee901fb67ffe505a277b0ccc40ca2fd3fb Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 20 Feb 2026 11:23:42 +0100 Subject: [PATCH 11/70] add sorting method --- .../common/format/table/TableData.cpp | 41 ++++++++++++++++++- .../common/format/table/TableData.hpp | 5 +++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp index b9bfc885584..3b3cbb3a178 100644 --- a/src/coreComponents/common/format/table/TableData.cpp +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -166,7 +166,7 @@ TableData2D::TableDataHolder TableData2D::buildTableData( string_view targetUnit std::set< real64 >::const_iterator columnIt = m_columnValues.begin(); for( auto const & [columnValue, cellValue] : rowMap ) { - // if a column value(s) is/are missing, insert empty entry(ies) + // if s1 column value(s) is/are missing, insert empty entry(ies) while( columnValue > *( columnIt++ ) && columnIt != m_columnValues.end() ) { currentRowValues.push_back( {CellType::Value, ""} ); @@ -180,4 +180,43 @@ TableData2D::TableDataHolder TableData2D::buildTableData( string_view targetUnit return tableData1D; } + +bool tabledatasorting::positiveNumberStringComp( std::string const & s1, std::string const & s2 ) +{ + auto split = [](std::string const & s, std::string & intPart, std::string & decPart) + { + size_t dotPos = s.find('.'); + if(dotPos == std::string::npos) + { + intPart = s; + decPart = ""; + } + else + { + intPart = s.substr(0, dotPos); + decPart = s.substr(dotPos + 1); + } + }; + + std::string s1Int, s1Dec, s2Int, s2Dec; + split(s1, s1Int, s1Dec); + split(s2, s2Int, s2Dec); + + if(s1Int.length() != s2Int.length()) + return s1Int.length() > s2Int.length(); + + if(s1Int != s2Int) + return s1Int > s2Int; + + size_t minLen = std::min(s1Dec.length(), s2Dec.length()); + for(size_t i = 0; i < minLen; ++i) + { + if(s1Dec[i] != s2Dec[i]) + return s1Dec[i] > s2Dec[i]; + } + + + return false; +} + } diff --git a/src/coreComponents/common/format/table/TableData.hpp b/src/coreComponents/common/format/table/TableData.hpp index e36afb037c5..9c60f375abe 100644 --- a/src/coreComponents/common/format/table/TableData.hpp +++ b/src/coreComponents/common/format/table/TableData.hpp @@ -302,5 +302,10 @@ void TableData2D::addCell( real64 const rowValue, real64 const columnValue, T co m_data.get_inserted( rowValue ).get_inserted( columnValue ) = GEOS_FMT( "{}", value ); } +namespace tabledatasorting +{ +bool positiveNumberStringComp( string const & a, string const & b ); +} + } #endif /* GEOS_COMMON_FORMAT_TABLE_TABLEDATA_HPP */ From 4600be347062a63a40f883658790663350799f36 Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 20 Feb 2026 11:24:17 +0100 Subject: [PATCH 12/70] extract outputLine function --- .../common/format/table/TableFormatter.cpp | 97 +++++++++++-------- .../common/format/table/TableFormatter.hpp | 9 ++ 2 files changed, 63 insertions(+), 43 deletions(-) diff --git a/src/coreComponents/common/format/table/TableFormatter.cpp b/src/coreComponents/common/format/table/TableFormatter.cpp index bf5779fdc23..2f87255d1b4 100644 --- a/src/coreComponents/common/format/table/TableFormatter.cpp +++ b/src/coreComponents/common/format/table/TableFormatter.cpp @@ -804,61 +804,72 @@ void TableTextFormatter::formatCell( std::ostream & tableOutput, } } -void TableTextFormatter::outputLines( PreparedTableLayout const & tableLayout, - CellLayoutRows const & rows, - std::ostream & tableOutput ) const +void TableTextFormatter::outputLine( PreparedTableLayout const & tableLayout, + CellLayoutRows const & rows, + CellLayoutRow const & row, + std::ostream & tableOutput, + size_t const idxRow ) const { size_t const nbRows = rows.size(); size_t const nbColumns = !rows.empty() ? rows.front().cells.size() : 0; + size_t const nbBorderSpaces = tableLayout.getBorderMargin(); size_t const nbColumnSpaces = ( tableLayout.getColumnMargin() - 1 ) / 2; - - size_t idxRow = 0; - for( CellLayoutRow const & row : rows ) + for( size_t idxSubLine = 0; idxSubLine < row.sublinesCount; idxSubLine++ ) { - for( size_t idxSubLine = 0; idxSubLine < row.sublinesCount; idxSubLine++ ) - { - bool isLeftBorderCell = true; + bool isLeftBorderCell = true; - for( size_t idxColumn = 0; idxColumn < nbColumns; ++idxColumn ) + for( size_t idxColumn = 0; idxColumn < nbColumns; ++idxColumn ) + { + auto & cell = row.cells[idxColumn]; + bool const isRightBorderCell = idxColumn == nbColumns - 1; + if( cell.m_cellType != CellType::MergeNext || isRightBorderCell ) { - auto & cell = row.cells[idxColumn]; - bool const isRightBorderCell = idxColumn == nbColumns - 1; - if( cell.m_cellType != CellType::MergeNext || isRightBorderCell ) - { - bool const isSeparator = cell.m_cellType == CellType::Separator; - char const cellSpaceChar = isSeparator ? m_horizontalLine : ' '; - - if( isLeftBorderCell ) - { // left table border - isLeftBorderCell=false; - tableOutput << tableLayout.getIndentationStr(); - tableOutput << m_verticalLine << string( nbBorderSpaces, cellSpaceChar ); - } - else - { // left side of a cell that have a neightboor - tableOutput << string( nbColumnSpaces, cellSpaceChar ); - } + bool const isSeparator = cell.m_cellType == CellType::Separator; + char const cellSpaceChar = isSeparator ? m_horizontalLine : ' '; + + if( isLeftBorderCell ) + { // left table border + isLeftBorderCell=false; + tableOutput << tableLayout.getIndentationStr(); + tableOutput << m_verticalLine << string( nbBorderSpaces, cellSpaceChar ); + } + else + { // left side of a cell that have a neightboor + tableOutput << string( nbColumnSpaces, cellSpaceChar ); + } - // cell content / fill - formatCell( tableOutput, cell, idxSubLine ); - - if( !isRightBorderCell ) - { // right side of a cell that have a neightboor - bool const isNextSeparator = row.cells[idxColumn + 1].m_cellType == CellType::Separator; - bool const upMerged = idxRow > 0 && rows[idxRow - 1].cells[idxColumn].m_cellType == CellType::MergeNext; - bool const downMerged = idxRow < nbRows - 1 && rows[idxRow + 1].cells[idxColumn].m_cellType == CellType::MergeNext; - tableOutput << string( nbColumnSpaces, cellSpaceChar ); - tableOutput << ( isSeparator && isNextSeparator && (upMerged || downMerged) ? - m_horizontalLine : m_verticalLine ); - } - else - { // right table border - tableOutput << string( nbBorderSpaces, cellSpaceChar ) << m_verticalLine << "\n"; - } + // cell content / fill + formatCell( tableOutput, cell, idxSubLine ); + + if( !isRightBorderCell ) + { // right side of a cell that have a neightboor + bool const isNextSeparator = row.cells[idxColumn + 1].m_cellType == CellType::Separator; + bool const upMerged = idxRow > 0 && rows[idxRow - 1].cells[idxColumn].m_cellType == CellType::MergeNext; + bool const downMerged = idxRow < nbRows - 1 && rows[idxRow + 1].cells[idxColumn].m_cellType == CellType::MergeNext; + tableOutput << string( nbColumnSpaces, cellSpaceChar ); + tableOutput << ( isSeparator && isNextSeparator && (upMerged || downMerged) ? + m_horizontalLine : m_verticalLine ); + } + else + { // right table border + tableOutput << string( nbBorderSpaces, cellSpaceChar ) << m_verticalLine << "\n"; } } } + } + +} + +void TableTextFormatter::outputLines( PreparedTableLayout const & tableLayout, + CellLayoutRows const & rows, + std::ostream & tableOutput ) const +{ + + size_t idxRow=0; + for( CellLayoutRow const & row : rows ) + { + outputLine( tableLayout, rows, row, tableOutput, idxRow ); idxRow++; } } diff --git a/src/coreComponents/common/format/table/TableFormatter.hpp b/src/coreComponents/common/format/table/TableFormatter.hpp index eed907975c2..3be6b9ed1a2 100644 --- a/src/coreComponents/common/format/table/TableFormatter.hpp +++ b/src/coreComponents/common/format/table/TableFormatter.hpp @@ -244,6 +244,7 @@ class TableTextFormatter : public TableFormatter void toStream( std::ostream & outputStream, DATASOURCE const & tableData ) const { toStreamImpl( outputStream, toString( tableData ) ); } + protected: /// symbol for separator construction @@ -308,6 +309,14 @@ class TableTextFormatter : public TableFormatter string_view separatorLine, bool hasData ) const; + void outputLine( PreparedTableLayout const & tableLayout, + CellLayoutRows const & rows, + CellLayoutRow const & row, + std::ostream & tableOutput, + size_t const idxRow ) const; + + + private: /** From bbae59740431cc7dfcfcf3702be694fc28569111 Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 20 Feb 2026 11:25:23 +0100 Subject: [PATCH 13/70] sorted mpi table --- .../common/format/table/TableFormatter.hpp | 1 - .../format/table/TableMpiComponents.cpp | 124 ++++++++++++++---- .../format/table/TableMpiComponents.hpp | 78 ++++++++++- .../format/table/unitTests/testMpiTable.cpp | 58 ++++++++ 4 files changed, 233 insertions(+), 28 deletions(-) diff --git a/src/coreComponents/common/format/table/TableFormatter.hpp b/src/coreComponents/common/format/table/TableFormatter.hpp index 3be6b9ed1a2..ca337f487d1 100644 --- a/src/coreComponents/common/format/table/TableFormatter.hpp +++ b/src/coreComponents/common/format/table/TableFormatter.hpp @@ -244,7 +244,6 @@ class TableTextFormatter : public TableFormatter void toStream( std::ostream & outputStream, DATASOURCE const & tableData ) const { toStreamImpl( outputStream, toString( tableData ) ); } - protected: /// symbol for separator construction diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index 3b2a9ed24e4..f5c45c8373d 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -68,20 +68,8 @@ void TableTextMpiOutput::toStream< TableData >( std::ostream & tableOutput, status.m_sepLine = string( tableTotalWidth, m_horizontalLine ); } - if( status.m_isMasterRank ) - { - outputTableHeader( tableOutput, m_tableLayout, headerCellsLayout, status.m_sepLine ); - tableOutput.flush(); - } - - outputTableDataToRank0( tableOutput, m_tableLayout, dataCellsLayout, status ); + gatherAndOutputTableDataRank0( tableOutput, m_tableLayout, dataCellsLayout, status ); - if( status.m_isMasterRank ) - { - outputTableFooter( tableOutput, m_tableLayout, errorCellsLayout, - status.m_sepLine, status.m_hasContent ); - tableOutput.flush(); - } } void TableTextMpiOutput::stretchColumnsByRanks( stdVector< size_t > & columnsWidth, @@ -106,10 +94,86 @@ void TableTextMpiOutput::stretchColumnsByRanks( stdVector< size_t > & columnsWid MpiWrapper::allReduce( columnsWidth, columnsWidth, MpiWrapper::Reduction::Max ); } -void TableTextMpiOutput::outputTableDataToRank0( std::ostream & tableOutput, - PreparedTableLayout const & tableLayout, - CellLayoutRows const & dataCellsLayout, - TableTextMpiOutput::Status & status ) const +void TableTextMpiOutput::convertDataCellRowsToString( CellLayoutRows const & dataCellsLayout, + stdVector< string > & rowsConvertedInString ) const +{ + std::ostringstream rowStringStream; + size_t rowIndex = 0; + + for( CellLayoutRow const & row : dataCellsLayout ) + { + outputLine( m_tableLayout, dataCellsLayout, row, rowStringStream, rowIndex ); + rowIndex++; + rowsConvertedInString.emplace_back( rowStringStream.str()); + rowStringStream.str( "" ); + } +} + +void TableTextMpiOutput::reconstructTableData( string_view str, + TableData & reconstructedTableData ) const +{ + string row( str.substr( 1 )); + string cell; + stdVector< TableData::CellData > reconstructedRow; + + std::string::size_type start = 0; + std::string::size_type end = 0; + + while( (end = row.find( m_verticalLine, start )) != string::npos ) + { + cell =std::string( stringutilities::trimSpaces( row.substr( start, end ))); + reconstructedRow.emplace_back( TableData::CellData( {CellType::Value, cell} )); + row =row.substr( end + 1, row.size()); + } + reconstructedTableData.addRow( reconstructedRow ); +} + +void TableTextMpiOutput::gatherAndSortRowsAcrossRanks ( TableData & reconstructedTableData, + stdVector< string > & rowsAsString, + TableTextMpiOutput::Status & status ) const +{ + array1d< int > rowsSizeAcrossAllRank( MpiWrapper::commSize()); + MpiWrapper::allGather( LvArray::integerConversion< int >( rowsAsString.size()), + rowsSizeAcrossAllRank ); + int const maxRowAcrossAllRanks = *std::max_element( rowsSizeAcrossAllRank.begin(), + rowsSizeAcrossAllRank.end()); + rowsAsString.resize( maxRowAcrossAllRanks, "" ); + + + for( string & row : rowsAsString ) + { + MpiWrapper::gatherString( row, std::function< void(string_view) >( [&]( string_view str ){ + status.m_hasContent = true; + reconstructTableData( str, reconstructedTableData ); + } )); + } + + std::sort( reconstructedTableData.getCellsData().begin(), + reconstructedTableData.getCellsData().end(), + *m_sortingFunctor ); +} + + +void TableTextMpiOutput::gatherSortAndOutput( std::ostream & tableOutput, + CellLayoutRows const & dataCellsLayout, + TableTextMpiOutput::Status & status ) const +{ + stdVector< string > rowsAsString; + convertDataCellRowsToString( dataCellsLayout, rowsAsString ); + + TableData reconstructedTableData; + gatherAndSortRowsAcrossRanks ( reconstructedTableData, rowsAsString, status ); + + if( status.m_isMasterRank && status.m_hasContent ) + { + tableOutput << toString( reconstructedTableData ); + } +} + +void TableTextMpiOutput::gatherAndOutputInRankOrder( std::ostream & tableOutput, + CellLayoutRows const & dataCellsLayout, + PreparedTableLayout const & tableLayout, + TableTextMpiOutput::Status & status ) const { // master rank does the output directly to the output, other ranks will have to send it through a string. std::ostringstream localStringStream; @@ -125,18 +189,34 @@ void TableTextMpiOutput::outputTableDataToRank0( std::ostream & tableOutput, outputTableData( rankOutput, tableLayout, dataCellsLayout ); } string const rankStr = !status.m_isMasterRank && status.m_isContributing ? localStringStream.str() : ""; - stdVector< string > strs; + stdVector< string > strsAccrossRanks; + MpiWrapper::gatherString( rankStr, std::function< void(string_view) >( [&]( string_view str ){ status.m_hasContent = true; - strs.emplace_back( str ); - } )); + strsAccrossRanks.emplace_back( str ); + } ));; if( status.m_isMasterRank && status.m_hasContent ) { - std::sort( strs.begin(), strs.end()); - for( auto const & strSorted : strs ) + for( auto const & strSorted : strsAccrossRanks ) tableOutput << strSorted; } } +void TableTextMpiOutput::gatherAndOutputTableDataRank0( std::ostream & tableOutput, + PreparedTableLayout const & tableLayout, + CellLayoutRows const & dataCellsLayout, + TableTextMpiOutput::Status & status ) const +{ + if( m_sortingFunctor ) + { + gatherSortAndOutput( tableOutput, dataCellsLayout, status ); + } + else + { + gatherAndOutputInRankOrder( tableOutput, dataCellsLayout, tableLayout, status ); + } + +} + } /* namespace geos */ diff --git a/src/coreComponents/common/format/table/TableMpiComponents.hpp b/src/coreComponents/common/format/table/TableMpiComponents.hpp index aeb37caa0ce..261c987f8e3 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.hpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.hpp @@ -22,6 +22,10 @@ #define GEOS_COMMON_FORMAT_TABLE_TABLEMPICOMPONENTS_HPP #include "TableFormatter.hpp" +#include "common/format/table/TableData.hpp" +#include +#include +#include namespace geos { @@ -47,7 +51,7 @@ class TableTextMpiOutput : public TableTextFormatter public: /// base class using Base = TableTextFormatter; - + using SortingFunc = std::function< bool (stdVector< TableData::CellData >, stdVector< TableData::CellData >) >; /** * @brief Construct a default Table Formatter without layout specification (to only insert data in it, * without any column / title). Feature is not tested. @@ -74,6 +78,10 @@ class TableTextMpiOutput : public TableTextFormatter template< typename DATASOURCE > void toStream( std::ostream & outputStream, DATASOURCE const & tableData ) const; + void setSortingFunc( SortingFunc && func ) + { m_sortingFunctor = std::make_unique< SortingFunc >( std::move( func )); } + + private: // hiding toString() methods as they are not implemented with MPI support. @@ -89,6 +97,9 @@ class TableTextMpiOutput : public TableTextFormatter TableMpiLayout m_mpiLayout; + /// The customized comparison function object for std::sort + std::unique_ptr< SortingFunc > m_sortingFunctor; + /** * @brief Expend the columns width to accomodate with the content of all MPI ranks. * As it is based on MPI communications, every ranks must call this method. @@ -98,10 +109,67 @@ class TableTextMpiOutput : public TableTextFormatter void stretchColumnsByRanks( stdVector< size_t > & columnsWidth, Status const & status ) const; - void outputTableDataToRank0( std::ostream & tableOutput, - PreparedTableLayout const & tableLayout, - CellLayoutRows const & dataCellsLayout, - Status & status ) const; + + /** + * @brief Convert each row to a string and stored as a single entry; + * @param dataCellsLayout The target CellLayoutRows to convert + * @param rowsConvertedInString The result vector of the convertion + */ + void convertDataCellRowsToString( CellLayoutRows const & dataCellsLayout, + stdVector< string > & rowsConvertedInString ) const; + + /** + * @brief Parse a serialized row string and append the resulting row to a TableData. + * @param str The serialized row string to parse. + * @param reconstructedTableData The TableData being reconstructed + */ + void reconstructTableData( string_view str, + TableData & reconstructedTableData ) const; + + /** + * @brief Gather serialized rows across all ranks, Reconstruct a TableData, + * and sort the TableData by the desired sorting functor + * @param reconstructedTableData The table data being reconstructed and sorted. + * @param rowsAsString Serialized rows by the current rank. + * @param status Updated with content availability. + */ + void gatherAndSortRowsAcrossRanks ( TableData & reconstructedTableData, + stdVector< string > & rowsAsString, + TableTextMpiOutput::Status & status ) const; + /** + * @brief Serializes data cell rows, gathers and sorts them across all MPI ranks, + * and outputs the result to rank 0. + * @param tableOutput The output stream to display the table + * @param dataCellsLayout The layout for the data cells + * @param status The TableMpi status for the current rank + */ + void gatherSortAndOutput( std::ostream & tableOutput, + CellLayoutRows const & dataCellsLayout, + TableTextMpiOutput::Status & status )const; + + /** + * @brief Serializes data cell rows, gathers them across all MPI ranks, + * and outputs the result to rank 0. + * @param tableOutput The output stream to display the resulting table + * @param dataCellsLayout The layout for the data cells + * @param tableLayout The layout of the table + * @param status The TableMpi status for the current rank + */ + void gatherAndOutputInRankOrder( std::ostream & tableOutput, + CellLayoutRows const & dataCellsLayout, + PreparedTableLayout const & tableLayout, + TableTextMpiOutput::Status & status )const; + /** + * @brief Select the output method and display the result to rank 0; + * @param tableOutput The output stream to display the resulting table + * @param tableLayout The layout of the table + * @param dataCellsLayout The layout for the data cells + * @param status The TableMpi status for the current rank + */ + void gatherAndOutputTableDataRank0( std::ostream & tableOutput, + PreparedTableLayout const & tableLayout, + CellLayoutRows const & dataCellsLayout, + Status & status ) const; }; diff --git a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp index 7b01cf49515..858a29a7e94 100644 --- a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp +++ b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp @@ -138,6 +138,64 @@ TEST( testMpiTables, testDifferentRankData ) } } +TEST( testMpiTables, testCompPositiveValueTable ) +{ + EXPECT_TRUE ( tabledatasorting::positiveNumberStringComp( "123", "45" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "45", "123" )); + EXPECT_TRUE ( tabledatasorting::positiveNumberStringComp( "99", "10" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "10", "99" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "42", "42" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "0", "0" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1000", "1000" )); + EXPECT_TRUE ( tabledatasorting::positiveNumberStringComp( "9", "1" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1", "9" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "5", "5" )); + EXPECT_TRUE ( tabledatasorting::positiveNumberStringComp( "10000000", "9999999" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "9999999", "10000000" )); + + EXPECT_TRUE ( tabledatasorting::positiveNumberStringComp( "10.5", "9.99" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "9.99", "10.5" )); + + EXPECT_TRUE ( tabledatasorting::positiveNumberStringComp( "9.1", "1.99" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1.99", "9.1" )); + + EXPECT_TRUE ( tabledatasorting::positiveNumberStringComp( "10", "9.999" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "9.999", "10" )); + + EXPECT_TRUE ( tabledatasorting::positiveNumberStringComp( "1.9", "1.1" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1.1", "1.9" )); + EXPECT_TRUE ( tabledatasorting::positiveNumberStringComp( "1.59", "1.51" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1.51", "1.59" )); + EXPECT_TRUE ( tabledatasorting::positiveNumberStringComp( "0.9", "0.49" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "0.49", "0.9" )); + + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1.2", "1.9" )); + EXPECT_TRUE ( tabledatasorting::positiveNumberStringComp( "1.9", "1.2" )); + + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1.5", "1.50" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1.50", "1.5" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1.500", "1.5" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1.5", "1.500" )); + + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1.51", "1.510" )); + EXPECT_TRUE ( tabledatasorting::positiveNumberStringComp( "1.51", "1.509" )); + + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "3.14", "3.14" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "0.001", "0.001" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "100.0", "100.0" )); + + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "5", "5.0" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "5.0", "5" )); + + EXPECT_TRUE ( tabledatasorting::positiveNumberStringComp( "6", "5.9" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "5.9", "6" )); + + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "5", "5.1" )); + EXPECT_TRUE ( tabledatasorting::positiveNumberStringComp( "5.1", "5" )); + + +} + int main( int argc, char * * argv ) { int r; From 77b28da6888fd97dcea125593c8753186d42a53d Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 20 Feb 2026 11:25:47 +0100 Subject: [PATCH 14/70] use sorting method --- src/coreComponents/mesh/ElementRegionManager.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index 06104e52588..a2da6fbdd38 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -287,9 +287,17 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM } TableMpiLayout mpiLayout; - TableTextMpiOutput const formatter = TableTextMpiOutput( layoutPerforation, mpiLayout ); + TableTextMpiOutput formatter = TableTextMpiOutput( layoutPerforation, mpiLayout ); + + formatter.setSortingFunc( + []( std::vector< TableData::CellData > const & row1, + std::vector< TableData::CellData > const & row2 ) { + return tabledatasorting::positiveNumberStringComp( row1[0].value, row2[0].value ); + } ); + std::ostringstream outputStream; formatter.toStream( outputStream, localPerfoData ); + if( rankId == 0 ) { TableTextFormatter const globalFormatter( layoutPerforation ); From 863e9699172a09f3de69445b078221aed00bc1fa Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 20 Feb 2026 13:59:48 +0100 Subject: [PATCH 15/70] add test in invert comparator --- .../common/format/table/TableData.cpp | 18 +- .../format/table/TableMpiComponents.cpp | 37 ++-- .../format/table/unitTests/testMpiTable.cpp | 161 ++++++++++++------ 3 files changed, 137 insertions(+), 79 deletions(-) diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp index 3b3cbb3a178..8322ce95463 100644 --- a/src/coreComponents/common/format/table/TableData.cpp +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -181,12 +181,12 @@ TableData2D::TableDataHolder TableData2D::buildTableData( string_view targetUnit return tableData1D; } -bool tabledatasorting::positiveNumberStringComp( std::string const & s1, std::string const & s2 ) +bool tabledatasorting::positiveNumberStringComp( string const & s1, string const & s2 ) { - auto split = [](std::string const & s, std::string & intPart, std::string & decPart) + auto split = [](string const & s, string & intPart, string & decPart) { size_t dotPos = s.find('.'); - if(dotPos == std::string::npos) + if(dotPos == string::npos) { intPart = s; decPart = ""; @@ -198,25 +198,25 @@ bool tabledatasorting::positiveNumberStringComp( std::string const & s1, std::st } }; - std::string s1Int, s1Dec, s2Int, s2Dec; + string s1Int, s1Dec, s2Int, s2Dec; split(s1, s1Int, s1Dec); split(s2, s2Int, s2Dec); if(s1Int.length() != s2Int.length()) - return s1Int.length() > s2Int.length(); + return s1Int.length() < s2Int.length(); if(s1Int != s2Int) - return s1Int > s2Int; - + return s1Int < s2Int; + size_t minLen = std::min(s1Dec.length(), s2Dec.length()); for(size_t i = 0; i < minLen; ++i) { if(s1Dec[i] != s2Dec[i]) - return s1Dec[i] > s2Dec[i]; + return s1Dec[i] < s2Dec[i]; } - return false; + return true; } } diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index f5c45c8373d..439a57a5648 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -68,8 +68,25 @@ void TableTextMpiOutput::toStream< TableData >( std::ostream & tableOutput, status.m_sepLine = string( tableTotalWidth, m_horizontalLine ); } - gatherAndOutputTableDataRank0( tableOutput, m_tableLayout, dataCellsLayout, status ); - + if( m_sortingFunctor ) + { + gatherSortAndOutput( tableOutput, dataCellsLayout, status ); + } + else + { + if( status.m_isMasterRank ) + { + outputTableHeader( tableOutput, m_tableLayout, headerCellsLayout, status.m_sepLine ); + tableOutput.flush(); + } + gatherAndOutputInRankOrder( tableOutput, dataCellsLayout, m_tableLayout, status ); + if( status.m_isMasterRank ) + { + outputTableFooter( tableOutput, m_tableLayout, errorCellsLayout, + status.m_sepLine, status.m_hasContent ); + tableOutput.flush(); + } + } } void TableTextMpiOutput::stretchColumnsByRanks( stdVector< size_t > & columnsWidth, @@ -203,20 +220,4 @@ void TableTextMpiOutput::gatherAndOutputInRankOrder( std::ostream & tableOutput, } } -void TableTextMpiOutput::gatherAndOutputTableDataRank0( std::ostream & tableOutput, - PreparedTableLayout const & tableLayout, - CellLayoutRows const & dataCellsLayout, - TableTextMpiOutput::Status & status ) const -{ - if( m_sortingFunctor ) - { - gatherSortAndOutput( tableOutput, dataCellsLayout, status ); - } - else - { - gatherAndOutputInRankOrder( tableOutput, dataCellsLayout, tableLayout, status ); - } - -} - } /* namespace geos */ diff --git a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp index 858a29a7e94..f0134435de0 100644 --- a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp +++ b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp @@ -14,6 +14,7 @@ */ // Source includes +#include "common/format/table/TableData.hpp" #include "common/format/table/TableMpiComponents.hpp" #include "common/initializeEnvironment.hpp" #include "common/MpiWrapper.hpp" @@ -138,60 +139,116 @@ TEST( testMpiTables, testDifferentRankData ) } } +TEST( testMpiTables, testSortingMethod ) +{ + struct TestCase + { + stdVector< stdVector< std::pair< integer, real64 > > > m_ranksValues; + string m_expectedResult; + }; + + TestCase const testCase = + { + { // m_ranksValues: in this test, rank 2 has no value + { {1, 0.502} }, + { {2, 0.624}, {3, 0.791} }, + {}, + { {4, 0.243}, {5, 0.804}, {6, 0.302} }, + }, + "\n" // m_expectedResult + "-------------------------------------------\n" + "| Summary of negative pressure elements |\n" + "|-----------------------------------------|\n" + "| Global Id | pressure [Pa] |\n" + "|------------------|----------------------|\n" + "| 1 | 0.502 |\n" + "| 2 | 0.624 |\n" + "| 3 | 0.791 |\n" + "| 4 | 0.243 |\n" + "| 5 | 0.804 |\n" + "| 6 | 0.302 |\n" + "-------------------------------------------\n" + }; + + int const rankId = MpiWrapper::commRank(); + int const nbRanks = MpiWrapper::commSize(); + if( nbRanks > 1 ) + { + ASSERT_EQ( nbRanks, 4 ); + + TableLayout const layout = TableLayout(). + setTitle( "Summary of negative pressure elements" ). + addColumns( { "Global Id", "pressure [Pa]" } ). + setDefaultHeaderAlignment( TableLayout::Alignment::left ); + TableData data; + auto const & rankTestData = testCase.m_ranksValues[rankId]; + + TableMpiLayout mpiLayout; + mpiLayout.m_separatorBetweenRanks = true; + + if( !rankTestData.empty() ) + { + mpiLayout.m_rankTitle = GEOS_FMT( "Rank {}, {} values", rankId, rankTestData.size() ); + for( auto const & [id, value] : rankTestData ) + { + data.addRow( id, value ); + } + } + + TableTextMpiOutput formatter = TableTextMpiOutput( layout, mpiLayout ); + formatter.setSortingFunc( []( std::vector< TableData::CellData > const & row1, + std::vector< TableData::CellData > const & row2 ) { + return tabledatasorting::positiveNumberStringComp( row1[0].value, row2[0].value ); + } ); + + std::ostringstream oss; + formatter.toStream( oss, data ); + if( rankId == 0 ) + { + std::cout << "ma boula """<< oss.str()< Date: Fri, 20 Feb 2026 14:55:18 +0100 Subject: [PATCH 16/70] fix sort method + doxygen + add rank column --- .../common/format/table/TableData.cpp | 7 ++++--- .../common/format/table/TableData.hpp | 9 +++++++- .../format/table/TableMpiComponents.cpp | 10 ++++----- .../format/table/TableMpiComponents.hpp | 9 +++----- .../mesh/ElementRegionManager.cpp | 21 +++---------------- 5 files changed, 23 insertions(+), 33 deletions(-) diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp index 8322ce95463..8e0d11bea81 100644 --- a/src/coreComponents/common/format/table/TableData.cpp +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -18,6 +18,7 @@ */ #include "TableData.hpp" +#include "common/DataTypes.hpp" #include "common/logger/Logger.hpp" namespace geos @@ -181,9 +182,9 @@ TableData2D::TableDataHolder TableData2D::buildTableData( string_view targetUnit return tableData1D; } -bool tabledatasorting::positiveNumberStringComp( string const & s1, string const & s2 ) +bool tabledatasorting::positiveNumberStringComp( string_view s1, string_view s2 ) { - auto split = [](string const & s, string & intPart, string & decPart) + auto split = [](string_view s, string & intPart, string & decPart) { size_t dotPos = s.find('.'); if(dotPos == string::npos) @@ -216,7 +217,7 @@ bool tabledatasorting::positiveNumberStringComp( string const & s1, string const } - return true; + return false; } } diff --git a/src/coreComponents/common/format/table/TableData.hpp b/src/coreComponents/common/format/table/TableData.hpp index 9c60f375abe..60f20781615 100644 --- a/src/coreComponents/common/format/table/TableData.hpp +++ b/src/coreComponents/common/format/table/TableData.hpp @@ -302,9 +302,16 @@ void TableData2D::addCell( real64 const rowValue, real64 const columnValue, T co m_data.get_inserted( rowValue ).get_inserted( columnValue ) = GEOS_FMT( "{}", value ); } +// Custom Comp function; namespace tabledatasorting { -bool positiveNumberStringComp( string const & a, string const & b ); +/** + * @brief Compare two number string by in ascending numerical order. + * @param a The string to compare + * @param b The string to compare + * @return True if a is greater than b + */ +bool positiveNumberStringComp( string_view a, string_view b ); } } diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index 439a57a5648..81f8ff2d052 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -20,9 +20,6 @@ #include "TableMpiComponents.hpp" #include "common/MpiWrapper.hpp" -#include -#include -#include namespace geos { @@ -129,6 +126,9 @@ void TableTextMpiOutput::convertDataCellRowsToString( CellLayoutRows const & dat void TableTextMpiOutput::reconstructTableData( string_view str, TableData & reconstructedTableData ) const { + if( str.size() < 1 ) + return; + string row( str.substr( 1 )); string cell; stdVector< TableData::CellData > reconstructedRow; @@ -215,8 +215,8 @@ void TableTextMpiOutput::gatherAndOutputInRankOrder( std::ostream & tableOutput, if( status.m_isMasterRank && status.m_hasContent ) { - for( auto const & strSorted : strsAccrossRanks ) - tableOutput << strSorted; + for( auto const & str : strsAccrossRanks ) + tableOutput << str; } } diff --git a/src/coreComponents/common/format/table/TableMpiComponents.hpp b/src/coreComponents/common/format/table/TableMpiComponents.hpp index 261c987f8e3..fd8e42bc6ca 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.hpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.hpp @@ -23,9 +23,6 @@ #include "TableFormatter.hpp" #include "common/format/table/TableData.hpp" -#include -#include -#include namespace geos { @@ -97,7 +94,7 @@ class TableTextMpiOutput : public TableTextFormatter TableMpiLayout m_mpiLayout; - /// The customized comparison function object for std::sort + /// The custom comparison function object for std::sort std::unique_ptr< SortingFunc > m_sortingFunctor; /** @@ -113,10 +110,10 @@ class TableTextMpiOutput : public TableTextFormatter /** * @brief Convert each row to a string and stored as a single entry; * @param dataCellsLayout The target CellLayoutRows to convert - * @param rowsConvertedInString The result vector of the convertion + * @param rowsAsString The result vector of the convertion */ void convertDataCellRowsToString( CellLayoutRows const & dataCellsLayout, - stdVector< string > & rowsConvertedInString ) const; + stdVector< string > & rowsAsString ) const; /** * @brief Parse a serialized row string and append the resulting row to a TableData. diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index a2da6fbdd38..1ea84e1aa9b 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -14,28 +14,13 @@ */ #include -#include -#include -#include #include #include "ElementRegionManager.hpp" -#include "codingUtilities/RTTypes.hpp" #include "common/DataLayouts.hpp" -#include "common/DataTypes.hpp" -#include "common/MpiWrapper.hpp" -#include "common/StdContainerWrappers.hpp" #include "common/TimingMacros.hpp" -#include "common/format/table/TableData.hpp" -#include "common/format/table/TableFormatter.hpp" #include "common/format/table/TableMpiComponents.hpp" -#include "common/logger/Logger.hpp" -#include "dataRepository/BufferOps.hpp" -#include "mesh/ElementSubRegionBase.hpp" -#include "mesh/PerforationData.hpp" -#include "mesh/WellElementRegion.hpp" -#include "mesh/WellElementSubRegion.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "SurfaceElementRegion.hpp" #include "constitutive/ConstitutiveManager.hpp" @@ -253,7 +238,7 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM TableLayout const layoutPerforation ( GEOS_FMT( "Well '{}' Perforation Table", wellRegion.getWellGeneratorName()), { - "Perforation", "Well element", "Coordinates", + "Rank", "Perforation", "Well element", "Coordinates", "Cell region", "Cell sub-region", "Cell ID" } ); @@ -281,7 +266,7 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM localCoords.emplace_back( wsrPerfLocation[iperfLocal][0] ); localCoords.emplace_back( wsrPerfLocation[iperfLocal][1] ); localCoords.emplace_back( wsrPerfLocation[iperfLocal][2] ); - localPerfoData.addRow( globalIperf[iperfLocal], localWellElemIndices, localCoords, + localPerfoData.addRow( rankId, globalIperf[iperfLocal], localWellElemIndices, localCoords, region.getName(), subRegion.getName(), cellId ); } } @@ -292,7 +277,7 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM formatter.setSortingFunc( []( std::vector< TableData::CellData > const & row1, std::vector< TableData::CellData > const & row2 ) { - return tabledatasorting::positiveNumberStringComp( row1[0].value, row2[0].value ); + return tabledatasorting::positiveNumberStringComp( row1[1].value, row2[1].value ); } ); std::ostringstream outputStream; From ff7e66d3cc9ede7a000c9a22c9d98a5d83a17644 Mon Sep 17 00:00:00 2001 From: arng40 Date: Thu, 12 Mar 2026 15:05:53 +0100 Subject: [PATCH 17/70] remove mpi code --- src/coreComponents/common/MpiWrapper.cpp | 104 ----------------------- 1 file changed, 104 deletions(-) diff --git a/src/coreComponents/common/MpiWrapper.cpp b/src/coreComponents/common/MpiWrapper.cpp index 2cb5ae54ded..9e7c6fd66ce 100644 --- a/src/coreComponents/common/MpiWrapper.cpp +++ b/src/coreComponents/common/MpiWrapper.cpp @@ -556,110 +556,6 @@ void MpiWrapper::gatherString< std::function< void(string_view) > > } } -// template<> -// void MpiWrapper::gatherStringSet< stdVector >( stdVector< string > const & strSet, -// stdVector< string > & result, -// MPI_Comm MPI_PARAM( comm )) -// { -// int rank = MpiWrapper::commRank(); -// int size = MpiWrapper::commSize(); - -// string localAllStrings; -// stdVector< int > localStrSizes; -// localAllStrings.reserve( strSet.size() * 32 ); - -// for( auto const & str : strSet ) -// { -// localAllStrings += str; -// localStrSizes.push_back( static_cast< int >(str.size())); -// } - -// //1 - We gather the metadata across all ranks -// struct MetaData -// { -// int count; -// int size; -// }; -// MetaData localMeta = { static_cast< int >(strSet.size()), static_cast< int >(localAllStrings.size()) }; - -// stdVector< MetaData > allMeta; -// if( rank == 0 ) -// { -// allMeta.resize( size ); -// } - -// int localMetaArr[2] = { localMeta.count, localMeta.size }; -// stdVector< int > allMetaArr; - -// if( rank == 0 ) -// allMetaArr.resize( size * 2 ); - -// MpiWrapper::gather( localMetaArr, 2, allMetaArr.data(), 2, 0, comm ); - -// //2 - Prepare displacement arrays for rank 0 -// stdVector< int > allStrSizes; -// string allStrings; -// stdVector< int > counts_counts( size ); -// stdVector< int > displs_counts( size ); -// stdVector< int > counts_chars( size ); -// stdVector< int > displs_chars( size ); - -// int totalStrCount = 0; - -// if( rank == 0 ) -// { -// int currentCountOffset = 0; -// int currentCharOffset = 0; - -// for( int currRank = 0; currRank < size; ++currRank ) -// { -// int c_count = allMetaArr[2*currRank]; -// int c_size = allMetaArr[2*currRank + 1]; - -// counts_counts[currRank] = c_count; -// displs_counts[currRank] = currentCountOffset; - -// counts_chars[currRank] = c_size; -// displs_chars[currRank] = currentCharOffset; - -// currentCountOffset += c_count; -// currentCharOffset += c_size; -// } - -// totalStrCount = currentCountOffset; - -// allStrSizes.resize( totalStrCount ); -// allStrings.resize( currentCharOffset ); -// } - -// // 3. Gatherv des tailles de chaรฎnes -// MpiWrapper::gatherv( localStrSizes.data(), localMeta.count, -// allStrSizes.data(), counts_counts.data(), displs_counts.data(), -// 0, comm ); - -// // 4. Gatherv du contenu (chars) -// MpiWrapper::gatherv( localAllStrings.c_str(), localMeta.size, -// allStrings.data(), counts_chars.data(), displs_chars.data(), -// 0, comm ); - -// // 5. Reconstruction -// if( rank == 0 ) -// { -// const char * dataPtr = allStrings.c_str(); -// int currentOffset = 0; -// for( int i = 0; i < totalStrCount; ++i ) -// { -// int len = allStrSizes[i]; - -// std::string const temp( dataPtr + currentOffset, len ); - -// result.emplace( result.end(), temp ); -// currentOffset += len; -// } -// } - -// } - } /* namespace geos */ #if defined(__clang__) From 0261d8f9767826c4c7870d434bcd4a9f8437f873 Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 13 Mar 2026 15:19:32 +0100 Subject: [PATCH 18/70] refactor gatherString using gatherBuffer --- src/coreComponents/common/MpiWrapper.cpp | 42 ++++------- src/coreComponents/common/MpiWrapper.hpp | 73 ++++++++++++++++++- .../format/table/TableMpiComponents.cpp | 4 +- 3 files changed, 86 insertions(+), 33 deletions(-) diff --git a/src/coreComponents/common/MpiWrapper.cpp b/src/coreComponents/common/MpiWrapper.cpp index 9e7c6fd66ce..0443e8f4f58 100644 --- a/src/coreComponents/common/MpiWrapper.cpp +++ b/src/coreComponents/common/MpiWrapper.cpp @@ -519,38 +519,22 @@ template<> MPI_Datatype getMpiPairType< double, double >() } /* namespace internal */ template<> -void MpiWrapper::gatherString< std::function< void(string_view) > > - ( string const & rankStr, std::function< void(string_view) > && func ) -{ - integer const ranksCount = MpiWrapper::commSize(); - integer const currRank = MpiWrapper::commRank(); - // all other ranks than rank 0 render their output in a string and comunicate its size - std::vector< integer > ranksStrsSizes = std::vector( ranksCount, 0 ); - - integer const rankStrSize = rankStr.size(); - MpiWrapper::gather( &rankStrSize, 1, ranksStrsSizes.data(), 1, 0 ); - - // we compute the memory layout of the ranks strings - std::vector< integer > ranksStrsOffsets = std::vector( ranksCount, 0 ); - integer ranksStrsTotalSize = 0; - for( integer rankId = 0; rankId < ranksCount; ++rankId ) - { - ranksStrsOffsets[rankId] = ranksStrsTotalSize; - ranksStrsTotalSize += ranksStrsSizes[rankId]; - } - - // finally, we can send all text data to rank 0, then we output it in the output stream. - string ranksStrs = string( ranksStrsTotalSize, '\0' ); - MpiWrapper::gatherv( rankStr.data(), rankStrSize, - ranksStrs.data(), ranksStrsSizes.data(), ranksStrsOffsets.data(), - 0, MPI_COMM_GEOS ); - if( currRank == 0 ) +void MpiWrapper::gatherStringOnRank0< std::function< void(string_view) > > + ( string_view rankStr, std::function< void(string_view) > && func ) +{ + std::vector< buffer_unit_type > localbuffer; + localbuffer.reserve( rankStr.size()); + localbuffer.insert( localbuffer.end(), rankStr.begin(), rankStr.end()); + auto [globalLogRecords, counts, offsets] = + MpiWrapper::gatherBufferRank0< std::vector< buffer_unit_type > >( localbuffer ); + if( MpiWrapper::commRank() == 0 ) { - for( integer rankId = 0; rankId < ranksCount; ++rankId ) + for( integer rankId = 0; rankId < MpiWrapper::commSize(); ++rankId ) { - if( ranksStrsSizes[rankId] > 0 ) + if( counts[rankId] > 0 ) { - func( string_view( ranksStrs.data() + ranksStrsOffsets[rankId], ranksStrsSizes[rankId] ) ); + func( string( globalLogRecords.begin() + offsets[rankId], + globalLogRecords.begin() + offsets[rankId]+ counts[rankId] ) ); } } } diff --git a/src/coreComponents/common/MpiWrapper.hpp b/src/coreComponents/common/MpiWrapper.hpp index 2377e023d71..1246e06f4c9 100644 --- a/src/coreComponents/common/MpiWrapper.hpp +++ b/src/coreComponents/common/MpiWrapper.hpp @@ -332,9 +332,78 @@ struct MpiWrapper */ static int nodeCommSize(); + /** + * @brief Structure holding the result from all the gather operation + * @tparam CONTAINER The container type holding the data. + */ + template< typename CONTAINER > + struct GatherResult + { + CONTAINER data; // Collected data + stdVector< integer > counts; // Number of elements per row + stdVector< integer > offsets; // Starting index for each row in 'data' + }; + +/** + * @brief Gather buffers of varying sizes from all ranks to rank 0. + * @tparam CONTAINER The container type holding the data. + * @tparam VALUE_T The trivially copyable underlying data type (deduced automatically). + * @param localBuffer The local buffer to be gathered on rank 0. + * @return A struct containing: + * - 'data': all the gathered data on rank 0 + * - 'counts': number of elements for each rank + * - 'offsets': starting index for each rank in 'data' + */ + template< + typename CONTAINER, + typename VALUE_T = typename CONTAINER::value_type, + typename = std::enable_if_t< + std::is_trivially_copyable_v< VALUE_T > && + std::is_same_v< decltype(std::declval< CONTAINER >().data()), VALUE_T * > && + std::is_same_v< decltype(std::declval< CONTAINER >().size()), std::size_t > + > + > + static GatherResult< CONTAINER > + gatherBufferRank0( CONTAINER const & localBuffer ) + { + integer const numRanks = MpiWrapper::commSize(); + integer const numValues = static_cast< integer >(localBuffer.size()); + + GatherResult< CONTAINER > gatherResult; + + if( MpiWrapper::commRank() == 0 ) + { + gatherResult.counts.resize( numRanks ); + gatherResult.offsets.resize( numRanks ); + } + + + MpiWrapper::gather( &numValues, 1, gatherResult.counts.data(), 1, 0 ); + + if( MpiWrapper::commRank() == 0 ) + { + integer totalSize = 0; + for( integer i = 0; i < numRanks; ++i ) + { + gatherResult.offsets[i] = totalSize; + totalSize += gatherResult.counts[i]; + } + gatherResult.data.resize( totalSize ); + } + + MpiWrapper::gatherv( localBuffer.data(), + numValues, + gatherResult.data.data(), + gatherResult.counts.data(), + gatherResult.offsets.data(), + 0 ); + + return gatherResult; +} + template< typename FUNC > - static void gatherString( string const & str, - FUNC && func ); + static void gatherStringOnRank0( string const & str, + FUNC && func ); /** * @brief Strongly typed wrapper around MPI_Allgather. diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index 14f845701e1..ad5650a0ff9 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -160,7 +160,7 @@ void TableTextMpiOutput::gatherAndSortRowsAcrossRanks ( TableData & reconstructe for( string & row : rowsAsString ) { - MpiWrapper::gatherString( row, std::function< void(string_view) >( [&]( string_view str ){ + MpiWrapper::gatherStringOnRank0( row, std::function< void(string_view) >( [&]( string_view str ){ status.m_hasContent = true; reconstructTableData( str, reconstructedTableData ); } )); @@ -209,7 +209,7 @@ void TableTextMpiOutput::gatherAndOutputInRankOrder( std::ostream & tableOutput, string const rankStr = !status.m_isMasterRank && status.m_isContributing ? localStringStream.str() : ""; stdVector< string > strsAccrossRanks; - MpiWrapper::gatherString( rankStr, std::function< void(string_view) >( [&]( string_view str ){ + MpiWrapper::gatherStringOnRank0( rankStr, std::function< void(string_view) >( [&]( string_view str ){ status.m_hasContent = true; strsAccrossRanks.emplace_back( str ); } ));; From 86e5cd735a077165c4810e6ec1b300de89f65423 Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 13 Mar 2026 17:13:11 +0100 Subject: [PATCH 19/70] fix test --- .../format/table/unitTests/testMpiTable.cpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp index f0134435de0..cc64f1116ae 100644 --- a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp +++ b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp @@ -217,8 +217,8 @@ TEST( testMpiTables, testCompPositiveValueTable ) { EXPECT_FALSE ( tabledatasorting::positiveNumberStringComp( "123", "45" )); EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "45", "123" )); - EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "42", "42" )); - EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "0", "0" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "42", "42" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "0", "0" )); EXPECT_FALSE ( tabledatasorting::positiveNumberStringComp( "9", "1" )); EXPECT_FALSE ( tabledatasorting::positiveNumberStringComp( "10000000", "9999999" )); EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "9999999", "10000000" )); @@ -232,20 +232,20 @@ TEST( testMpiTables, testCompPositiveValueTable ) EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "1.2", "1.9" )); EXPECT_FALSE ( tabledatasorting::positiveNumberStringComp( "1.9", "1.2" )); - EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "1.5", "1.50" )); - EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "1.50", "1.5" )); - EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "1.500", "1.5" )); - EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "1.5", "1.500" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1.5", "1.50" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1.50", "1.5" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1.500", "1.5" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1.5", "1.500" )); - EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "1.51", "1.510" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1.51", "1.510" )); EXPECT_FALSE ( tabledatasorting::positiveNumberStringComp( "1.51", "1.509" )); - EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "3.14", "3.14" )); - EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "0.001", "0.001" )); - EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "100.0", "100.0" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "3.14", "3.14" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "0.001", "0.001" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "100.0", "100.0" )); - EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "5", "5.0" )); - EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "5.0", "5" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "5", "5.0" )); + EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "5.0", "5" )); EXPECT_FALSE ( tabledatasorting::positiveNumberStringComp( "5595", "5155" )); EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "5155", "5595" )); From 6d1a91869f87a7d8a82674aded74a76a4f0ce980 Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 13 Mar 2026 17:13:30 +0100 Subject: [PATCH 20/70] fix typo remove unused header --- src/coreComponents/common/format/table/TableData.cpp | 3 +-- src/coreComponents/common/format/table/TableData.hpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp index 8e0d11bea81..edd7924e4c9 100644 --- a/src/coreComponents/common/format/table/TableData.cpp +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -18,7 +18,6 @@ */ #include "TableData.hpp" -#include "common/DataTypes.hpp" #include "common/logger/Logger.hpp" namespace geos @@ -167,7 +166,7 @@ TableData2D::TableDataHolder TableData2D::buildTableData( string_view targetUnit std::set< real64 >::const_iterator columnIt = m_columnValues.begin(); for( auto const & [columnValue, cellValue] : rowMap ) { - // if s1 column value(s) is/are missing, insert empty entry(ies) + // if a column value(s) is/are missing, insert empty entry(ies) while( columnValue > *( columnIt++ ) && columnIt != m_columnValues.end() ) { currentRowValues.push_back( {CellType::Value, ""} ); diff --git a/src/coreComponents/common/format/table/TableData.hpp b/src/coreComponents/common/format/table/TableData.hpp index 60f20781615..64bedb96305 100644 --- a/src/coreComponents/common/format/table/TableData.hpp +++ b/src/coreComponents/common/format/table/TableData.hpp @@ -306,7 +306,7 @@ void TableData2D::addCell( real64 const rowValue, real64 const columnValue, T co namespace tabledatasorting { /** - * @brief Compare two number string by in ascending numerical order. + * @brief Compare two string number string by in ascending numerical order. * @param a The string to compare * @param b The string to compare * @return True if a is greater than b From 9c9fdd16a03fcb753679a7b4c48bc1dc0cf4a306 Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 13 Mar 2026 17:14:10 +0100 Subject: [PATCH 21/70] minor clean --- src/coreComponents/common/MpiWrapper.hpp | 2 +- .../common/format/table/TableFormatter.cpp | 4 ++-- .../common/format/table/TableFormatter.hpp | 10 ++++++++-- .../kernels/compositional/SolutionCheckKernel.hpp | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/coreComponents/common/MpiWrapper.hpp b/src/coreComponents/common/MpiWrapper.hpp index 1246e06f4c9..0739d1c7c06 100644 --- a/src/coreComponents/common/MpiWrapper.hpp +++ b/src/coreComponents/common/MpiWrapper.hpp @@ -402,7 +402,7 @@ struct MpiWrapper } template< typename FUNC > - static void gatherStringOnRank0( string const & str, + static void gatherStringOnRank0( string_view str, FUNC && func ); /** diff --git a/src/coreComponents/common/format/table/TableFormatter.cpp b/src/coreComponents/common/format/table/TableFormatter.cpp index 9012a5cd36c..b04cd73e174 100644 --- a/src/coreComponents/common/format/table/TableFormatter.cpp +++ b/src/coreComponents/common/format/table/TableFormatter.cpp @@ -315,14 +315,14 @@ void TableTextFormatter::populateTitleCellsLayout( PreparedTableLayout const & t // the title row consists in a row of cells merging with the last cell containing the title text headerCellsLayout.emplace_back() = { stdVector< TableLayout::CellLayout >( nbVisibleColumns, - TableLayout::CellLayout( CellType::MergeNext ) ), // cells + TableLayout::CellLayout( CellType::MergeNext ) ), // cells titleInput.getHeight(), // sublinesCount }; headerCellsLayout.back().cells.back() = titleInput; headerCellsLayout.emplace_back() = { stdVector< TableLayout::CellLayout >( nbVisibleColumns, - TableLayout::CellLayout( CellType::Separator ) ), // cells + TableLayout::CellLayout( CellType::Separator ) ), // cells 1, // sublinesCount }; } diff --git a/src/coreComponents/common/format/table/TableFormatter.hpp b/src/coreComponents/common/format/table/TableFormatter.hpp index ca337f487d1..4c974391b22 100644 --- a/src/coreComponents/common/format/table/TableFormatter.hpp +++ b/src/coreComponents/common/format/table/TableFormatter.hpp @@ -308,14 +308,20 @@ class TableTextFormatter : public TableFormatter string_view separatorLine, bool hasData ) const; + /** + * @brief Outputs the formatted table line to the output stream. + * @param tableLayout The layout of the table + * @param rows The data rows in a grid layout + * @param row Represent a row of the Table (header or values) to output + * @param tableOutput A reference to an `std::ostream` where the formatted table will be written. + * @param idxRow the row index to output + */ void outputLine( PreparedTableLayout const & tableLayout, CellLayoutRows const & rows, CellLayoutRow const & row, std::ostream & tableOutput, size_t const idxRow ) const; - - private: /** diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp index 3d2452b0afb..639decdb418 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp @@ -166,7 +166,7 @@ class SolutionCheckKernel : public SolutionScalingAndCheckingKernelBase< integer return; } - StackVariables stack{}; + StackVariables stack; kernelComponent.setup( ei, stack ); kernelComponent.compute( ei, stack ); From 805c7b1b29649282700388543db6d1d80ace59fe Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 13 Mar 2026 17:14:47 +0100 Subject: [PATCH 22/70] ranaming, reorg variable first step --- .../format/table/TableMpiComponents.cpp | 173 +++++++++--------- .../format/table/TableMpiComponents.hpp | 9 +- 2 files changed, 89 insertions(+), 93 deletions(-) diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index ad5650a0ff9..095b13b6ffa 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -35,58 +35,6 @@ TableTextMpiOutput::TableTextMpiOutput( TableLayout const & tableLayout, m_mpiLayout( mpiLayout ) {} -template<> -void TableTextMpiOutput::toStream< TableData >( std::ostream & tableOutput, - TableData const & tableData ) const -{ - TableTextMpiOutput::Status status { - // m_isMasterRank (only the master rank does the output of the header && bottom of the table) - MpiWrapper::commRank() == 0, - // m_isContributing (some ranks does not have any output to produce) - !tableData.getCellsData().empty(), - // m_hasContent - false, - // m_sepLine - "" - }; - - CellLayoutRows headerCellsLayout; - CellLayoutRows dataCellsLayout; - CellLayoutRows errorCellsLayout; - size_t tableTotalWidth = 0; - - { - ColumnWidthModifier const columnWidthModifier = [this, status]( stdVector< size_t > & columnsWidth ) { - stretchColumnsByRanks( columnsWidth, status ); - }; - initalizeTableGrids( m_tableLayout, tableData, - headerCellsLayout, dataCellsLayout, errorCellsLayout, - tableTotalWidth, columnWidthModifier ); - status.m_sepLine = string( tableTotalWidth, m_horizontalLine ); - } - - if( m_sortingFunctor ) - { - gatherSortAndOutput( tableOutput, dataCellsLayout, status ); - } - else - { - if( status.m_isMasterRank ) - { - outputTableHeader( tableOutput, m_tableLayout, headerCellsLayout, status.m_sepLine ); - tableOutput.flush(); - } - gatherAndOutputInRankOrder( tableOutput, dataCellsLayout, m_tableLayout, status ); - if( status.m_isMasterRank ) - { - outputTableFooter( tableOutput, m_tableLayout, errorCellsLayout, - status.m_sepLine, status.m_hasContent ); - tableOutput.flush(); - } - - } -} - void TableTextMpiOutput::stretchColumnsByRanks( stdVector< size_t > & columnsWidth, TableTextMpiOutput::Status const & status ) const { @@ -109,89 +57,86 @@ void TableTextMpiOutput::stretchColumnsByRanks( stdVector< size_t > & columnsWid MpiWrapper::allReduce( columnsWidth, columnsWidth, MpiWrapper::Reduction::Max ); } -void TableTextMpiOutput::convertDataCellRowsToString( CellLayoutRows const & dataCellsLayout, - stdVector< string > & rowsConvertedInString ) const +void TableTextMpiOutput::convertRowsToString( CellLayoutRows const & rows, + stdVector< string > & rowsConvertedInString ) const { std::ostringstream rowStringStream; size_t rowIndex = 0; - for( CellLayoutRow const & row : dataCellsLayout ) + for( CellLayoutRow const & row : rows ) { - outputLine( m_tableLayout, dataCellsLayout, row, rowStringStream, rowIndex ); + outputLine( m_tableLayout, rows, row, rowStringStream, rowIndex ); rowIndex++; rowsConvertedInString.emplace_back( rowStringStream.str()); rowStringStream.str( "" ); } } -void TableTextMpiOutput::reconstructTableData( string_view str, - TableData & reconstructedTableData ) const +stdVector< TableData::CellData > TableTextMpiOutput::reconstructRow( string_view str ) const { if( str.size() < 1 ) - return; + return stdVector< TableData::CellData >{}; - string row( str.substr( 1 )); + string_view rowContent( str.substr( 1 )); // skip leading '|' string cell; stdVector< TableData::CellData > reconstructedRow; std::string::size_type start = 0; std::string::size_type end = 0; - while( (end = row.find( m_verticalLine, start )) != string::npos ) + while( (end = rowContent.find( m_verticalLine, start )) != string_view::npos ) { - cell =std::string( stringutilities::trimSpaces( row.substr( start, end ))); + cell =std::string( stringutilities::trimSpaces( rowContent.substr( start, end ))); reconstructedRow.emplace_back( TableData::CellData( {CellType::Value, cell} )); - row =row.substr( end + 1, row.size()); + rowContent =rowContent.substr( end + 1, rowContent.size()); } - reconstructedTableData.addRow( reconstructedRow ); + return reconstructedRow; } -void TableTextMpiOutput::gatherAndSortRowsAcrossRanks ( TableData & reconstructedTableData, - stdVector< string > & rowsAsString, - TableTextMpiOutput::Status & status ) const +void TableTextMpiOutput::gatherAndSortTableDataAcrossRanks ( TableData & gatheredTableData, + stdVector< string > & rowsAsString, + TableTextMpiOutput::Status & status ) const { - array1d< int > rowsSizeAcrossAllRank( MpiWrapper::commSize()); - MpiWrapper::allGather( LvArray::integerConversion< int >( rowsAsString.size()), + array1d< integer > rowsSizeAcrossAllRank( MpiWrapper::commSize()); + MpiWrapper::allGather( LvArray::integerConversion< integer >( rowsAsString.size()), rowsSizeAcrossAllRank ); - int const maxRowAcrossAllRanks = *std::max_element( rowsSizeAcrossAllRank.begin(), - rowsSizeAcrossAllRank.end()); + integer const maxRowAcrossAllRanks = *std::max_element( rowsSizeAcrossAllRank.begin(), + rowsSizeAcrossAllRank.end()); rowsAsString.resize( maxRowAcrossAllRanks, "" ); - for( string & row : rowsAsString ) { MpiWrapper::gatherStringOnRank0( row, std::function< void(string_view) >( [&]( string_view str ){ status.m_hasContent = true; - reconstructTableData( str, reconstructedTableData ); + gatheredTableData.addRow( reconstructRow( str )); } )); } - std::sort( reconstructedTableData.getCellsData().begin(), - reconstructedTableData.getCellsData().end(), + std::sort( gatheredTableData.getCellsData().begin(), + gatheredTableData.getCellsData().end(), *m_sortingFunctor ); } - void TableTextMpiOutput::gatherSortAndOutput( std::ostream & tableOutput, - CellLayoutRows const & dataCellsLayout, + CellLayoutRows const & rows, TableTextMpiOutput::Status & status ) const { stdVector< string > rowsAsString; - convertDataCellRowsToString( dataCellsLayout, rowsAsString ); + convertRowsToString( rows, rowsAsString ); - TableData reconstructedTableData; - gatherAndSortRowsAcrossRanks ( reconstructedTableData, rowsAsString, status ); + TableData gatheredTableData; + gatherAndSortTableDataAcrossRanks( gatheredTableData, rowsAsString, status ); if( status.m_isMasterRank && status.m_hasContent ) { - tableOutput << toString( reconstructedTableData ); + tableOutput << toString( gatheredTableData ); } } -void TableTextMpiOutput::gatherAndOutputInRankOrder( std::ostream & tableOutput, - CellLayoutRows const & dataCellsLayout, - PreparedTableLayout const & tableLayout, - TableTextMpiOutput::Status & status ) const +void TableTextMpiOutput::gatherAndOutputTableDataInRankOrder( std::ostream & tableOutput, + CellLayoutRows const & rows, + PreparedTableLayout const & tableLayout, + TableTextMpiOutput::Status & status ) const { // master rank does the output directly to the output, other ranks will have to send it through a string. std::ostringstream localStringStream; @@ -204,7 +149,7 @@ void TableTextMpiOutput::gatherAndOutputInRankOrder( std::ostream & tableOutput, string const rankSepLine = GEOS_FMT( "{:-^{}}", m_mpiLayout.m_rankTitle, status.m_sepLine.size() - 2 ); rankOutput << tableLayout.getIndentationStr() << m_verticalLine << rankSepLine << m_verticalLine << '\n'; } - outputTableData( rankOutput, tableLayout, dataCellsLayout ); + outputTableData( rankOutput, tableLayout, rows ); } string const rankStr = !status.m_isMasterRank && status.m_isContributing ? localStringStream.str() : ""; stdVector< string > strsAccrossRanks; @@ -212,13 +157,65 @@ void TableTextMpiOutput::gatherAndOutputInRankOrder( std::ostream & tableOutput, MpiWrapper::gatherStringOnRank0( rankStr, std::function< void(string_view) >( [&]( string_view str ){ status.m_hasContent = true; strsAccrossRanks.emplace_back( str ); - } ));; + } )); if( status.m_isMasterRank && status.m_hasContent ) { - for( auto const & str : strsAccrossRanks ) + for( string_view str : strsAccrossRanks ) tableOutput << str; } } +template<> +void TableTextMpiOutput::toStream< TableData >( std::ostream & tableOutput, + TableData const & tableData ) const +{ + TableTextMpiOutput::Status status { + // m_isMasterRank (only the master rank does the output of the header && bottom of the table) + MpiWrapper::commRank() == 0, + // m_isContributing (some ranks does not have any output to produce) + !tableData.getCellsData().empty(), + // m_hasContent + false, + // m_sepLine + "" + }; + + CellLayoutRows headerCellsLayout; + CellLayoutRows dataRows; + CellLayoutRows errorRows; + size_t tableTotalWidth = 0; + + { + ColumnWidthModifier const columnWidthModifier = [this, status]( stdVector< size_t > & columnsWidth ) { + stretchColumnsByRanks( columnsWidth, status ); + }; + initalizeTableGrids( m_tableLayout, tableData, + headerCellsLayout, dataRows, errorRows, + tableTotalWidth, columnWidthModifier ); + status.m_sepLine = string( tableTotalWidth, m_horizontalLine ); + } + + if( m_sortingFunctor ) + { + gatherSortAndOutput( tableOutput, dataRows, status ); + } + else + { + if( status.m_isMasterRank ) + { + outputTableHeader( tableOutput, m_tableLayout, headerCellsLayout, status.m_sepLine ); + tableOutput.flush(); + } + gatherAndOutputTableDataInRankOrder( tableOutput, dataRows, m_tableLayout, status ); + if( status.m_isMasterRank ) + { + outputTableFooter( tableOutput, m_tableLayout, errorRows, + status.m_sepLine, status.m_hasContent ); + tableOutput.flush(); + } + + } +} + } /* namespace geos */ diff --git a/src/coreComponents/common/format/table/TableMpiComponents.hpp b/src/coreComponents/common/format/table/TableMpiComponents.hpp index fd8e42bc6ca..ffa7faa04a2 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.hpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.hpp @@ -112,7 +112,7 @@ class TableTextMpiOutput : public TableTextFormatter * @param dataCellsLayout The target CellLayoutRows to convert * @param rowsAsString The result vector of the convertion */ - void convertDataCellRowsToString( CellLayoutRows const & dataCellsLayout, + void convertRowsToString( CellLayoutRows const & dataCellsLayout, stdVector< string > & rowsAsString ) const; /** @@ -120,8 +120,7 @@ class TableTextMpiOutput : public TableTextFormatter * @param str The serialized row string to parse. * @param reconstructedTableData The TableData being reconstructed */ - void reconstructTableData( string_view str, - TableData & reconstructedTableData ) const; + stdVector< TableData::CellData > reconstructRow( string_view str ) const; /** * @brief Gather serialized rows across all ranks, Reconstruct a TableData, @@ -130,7 +129,7 @@ class TableTextMpiOutput : public TableTextFormatter * @param rowsAsString Serialized rows by the current rank. * @param status Updated with content availability. */ - void gatherAndSortRowsAcrossRanks ( TableData & reconstructedTableData, + void gatherAndSortTableDataAcrossRanks ( TableData & reconstructedTableData, stdVector< string > & rowsAsString, TableTextMpiOutput::Status & status ) const; /** @@ -152,7 +151,7 @@ class TableTextMpiOutput : public TableTextFormatter * @param tableLayout The layout of the table * @param status The TableMpi status for the current rank */ - void gatherAndOutputInRankOrder( std::ostream & tableOutput, + void gatherAndOutputTableDataInRankOrder( std::ostream & tableOutput, CellLayoutRows const & dataCellsLayout, PreparedTableLayout const & tableLayout, TableTextMpiOutput::Status & status )const; From 740092207c4c6a14d2eda3b20d4407eb5a15b085 Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 13 Mar 2026 17:22:21 +0100 Subject: [PATCH 23/70] some cleanup --- src/coreComponents/common/format/table/TableMpiComponents.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index 095b13b6ffa..541f350574c 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -88,7 +88,7 @@ stdVector< TableData::CellData > TableTextMpiOutput::reconstructRow( string_view { cell =std::string( stringutilities::trimSpaces( rowContent.substr( start, end ))); reconstructedRow.emplace_back( TableData::CellData( {CellType::Value, cell} )); - rowContent =rowContent.substr( end + 1, rowContent.size()); + rowContent.remove_prefix( end + 1 ); } return reconstructedRow; } @@ -102,7 +102,7 @@ void TableTextMpiOutput::gatherAndSortTableDataAcrossRanks ( TableData & gathere rowsSizeAcrossAllRank ); integer const maxRowAcrossAllRanks = *std::max_element( rowsSizeAcrossAllRank.begin(), rowsSizeAcrossAllRank.end()); - rowsAsString.resize( maxRowAcrossAllRanks, "" ); + rowsAsString.resize( maxRowAcrossAllRanks ); for( string & row : rowsAsString ) { From d2925fbd776350e2a5207b3cc838c22e5126fe8e Mon Sep 17 00:00:00 2001 From: arng40 Date: Mon, 16 Mar 2026 10:54:11 +0100 Subject: [PATCH 24/70] doxygen --- src/coreComponents/common/MpiWrapper.hpp | 59 ++++++++-------- .../format/table/TableMpiComponents.hpp | 67 ++++++++----------- 2 files changed, 61 insertions(+), 65 deletions(-) diff --git a/src/coreComponents/common/MpiWrapper.hpp b/src/coreComponents/common/MpiWrapper.hpp index 0739d1c7c06..1278e90c0c2 100644 --- a/src/coreComponents/common/MpiWrapper.hpp +++ b/src/coreComponents/common/MpiWrapper.hpp @@ -22,7 +22,6 @@ #include "common/DataTypes.hpp" #include "common/Span.hpp" -#include "common/StdContainerWrappers.hpp" #include "common/TypesHelpers.hpp" #include @@ -339,7 +338,7 @@ struct MpiWrapper template< typename CONTAINER > struct GatherResult { - CONTAINER data; // Collected data + CONTAINER data; // Collected data stdVector< integer > counts; // Number of elements per row stdVector< integer > offsets; // Starting index for each row in 'data' }; @@ -366,41 +365,47 @@ struct MpiWrapper static GatherResult< CONTAINER > gatherBufferRank0( CONTAINER const & localBuffer ) { - integer const numRanks = MpiWrapper::commSize(); - integer const numValues = static_cast< integer >(localBuffer.size()); + integer const numRanks = MpiWrapper::commSize(); + integer const numValues = static_cast< integer >(localBuffer.size()); - GatherResult< CONTAINER > gatherResult; + GatherResult< CONTAINER > gatherResult; - if( MpiWrapper::commRank() == 0 ) - { - gatherResult.counts.resize( numRanks ); - gatherResult.offsets.resize( numRanks ); - } + if( MpiWrapper::commRank() == 0 ) + { + gatherResult.counts.resize( numRanks ); + gatherResult.offsets.resize( numRanks ); + } - MpiWrapper::gather( &numValues, 1, gatherResult.counts.data(), 1, 0 ); + MpiWrapper::gather( &numValues, 1, gatherResult.counts.data(), 1, 0 ); - if( MpiWrapper::commRank() == 0 ) - { - integer totalSize = 0; - for( integer i = 0; i < numRanks; ++i ) + if( MpiWrapper::commRank() == 0 ) { - gatherResult.offsets[i] = totalSize; - totalSize += gatherResult.counts[i]; + integer totalSize = 0; + for( integer i = 0; i < numRanks; ++i ) + { + gatherResult.offsets[i] = totalSize; + totalSize += gatherResult.counts[i]; + } + gatherResult.data.resize( totalSize ); } - gatherResult.data.resize( totalSize ); - } - MpiWrapper::gatherv( localBuffer.data(), - numValues, - gatherResult.data.data(), - gatherResult.counts.data(), - gatherResult.offsets.data(), - 0 ); + MpiWrapper::gatherv( localBuffer.data(), + numValues, + gatherResult.data.data(), + gatherResult.counts.data(), + gatherResult.offsets.data(), + 0 ); - return gatherResult; -} + return gatherResult; + } + /** + * @brief Gather srting from all ranks to rank 0 + * @tparam FUNC Callable type invoked as void(string_view) for each non-empty rank string. + * @param str The local string to send from the calling rank. + * @param func Callback invoked on rank 0 for each non-empty received string. + */ template< typename FUNC > static void gatherStringOnRank0( string_view str, FUNC && func ); diff --git a/src/coreComponents/common/format/table/TableMpiComponents.hpp b/src/coreComponents/common/format/table/TableMpiComponents.hpp index ffa7faa04a2..c693419538c 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.hpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.hpp @@ -22,7 +22,6 @@ #define GEOS_COMMON_FORMAT_TABLE_TABLEMPICOMPONENTS_HPP #include "TableFormatter.hpp" -#include "common/format/table/TableData.hpp" namespace geos { @@ -48,6 +47,7 @@ class TableTextMpiOutput : public TableTextFormatter public: /// base class using Base = TableTextFormatter; + /// Callable comparison function object used for std::sort for a TableData using SortingFunc = std::function< bool (stdVector< TableData::CellData >, stdVector< TableData::CellData >) >; /** * @brief Construct a default Table Formatter without layout specification (to only insert data in it, @@ -75,6 +75,10 @@ class TableTextMpiOutput : public TableTextFormatter template< typename DATASOURCE > void toStream( std::ostream & outputStream, DATASOURCE const & tableData ) const; + /** + * @brief Set the Sorting Func object + * @param func The callable comparison function object + */ void setSortingFunc( SortingFunc && func ) { m_sortingFunctor = std::make_unique< SortingFunc >( std::move( func )); } @@ -108,65 +112,52 @@ class TableTextMpiOutput : public TableTextFormatter /** - * @brief Convert each row to a string and stored as a single entry; - * @param dataCellsLayout The target CellLayoutRows to convert - * @param rowsAsString The result vector of the convertion + * @brief Parse each row of a CellLayoutRows into its string representation. + * @param cellLayoutRows The target CellLayoutRows to parse + * @param rowsAsString The result vector of strings */ - void convertRowsToString( CellLayoutRows const & dataCellsLayout, - stdVector< string > & rowsAsString ) const; + void parseCellLayoutRows( CellLayoutRows const & cellLayoutRows, + stdVector< string > & rowsAsString ) const; /** - * @brief Parse a serialized row string and append the resulting row to a TableData. - * @param str The serialized row string to parse. - * @param reconstructedTableData The TableData being reconstructed + * @brief Parse a string row to a TablaData cells. + * @param rowString The string row string to parse. + * @return The parsed row as a vector of CellData. */ - stdVector< TableData::CellData > reconstructRow( string_view str ) const; + stdVector< TableData::CellData > parseStringRow( string_view rowString ) const; /** - * @brief Gather serialized rows across all ranks, Reconstruct a TableData, + * @brief Gather string rows across all ranks, construct a TableData, * and sort the TableData by the desired sorting functor - * @param reconstructedTableData The table data being reconstructed and sorted. - * @param rowsAsString Serialized rows by the current rank. - * @param status Updated with content availability. + * @param gatheredTableData The output TableData object populated with gathered cells. + * @param rowsAsString Serialized rows string provided by the current rank. + * @param status Updated to indicate if any content was actually gathered. */ - void gatherAndSortTableDataAcrossRanks ( TableData & reconstructedTableData, - stdVector< string > & rowsAsString, - TableTextMpiOutput::Status & status ) const; + void gatherAndSortTableDataAcrossRanks ( TableData & gatheredTableData, + stdVector< string > & rowsAsString, + TableTextMpiOutput::Status & status ) const; /** - * @brief Serializes data cell rows, gathers and sorts them across all MPI ranks, + * @brief Parse CellLayoutRows, gathers and sorts them across all MPI ranks, * and outputs the result to rank 0. - * @param tableOutput The output stream to display the table - * @param dataCellsLayout The layout for the data cells + * @param tableOutput The output stream where the formatted table is written. + * @param cellLayoutRows The layout for the data cells * @param status The TableMpi status for the current rank */ void gatherSortAndOutput( std::ostream & tableOutput, - CellLayoutRows const & dataCellsLayout, + CellLayoutRows const & cellLayoutRows, TableTextMpiOutput::Status & status )const; /** - * @brief Serializes data cell rows, gathers them across all MPI ranks, - * and outputs the result to rank 0. + * @brief Gather data cell rows across all MPI ranks and output them to rank 0 in rank order. * @param tableOutput The output stream to display the resulting table * @param dataCellsLayout The layout for the data cells * @param tableLayout The layout of the table * @param status The TableMpi status for the current rank */ void gatherAndOutputTableDataInRankOrder( std::ostream & tableOutput, - CellLayoutRows const & dataCellsLayout, - PreparedTableLayout const & tableLayout, - TableTextMpiOutput::Status & status )const; - /** - * @brief Select the output method and display the result to rank 0; - * @param tableOutput The output stream to display the resulting table - * @param tableLayout The layout of the table - * @param dataCellsLayout The layout for the data cells - * @param status The TableMpi status for the current rank - */ - void gatherAndOutputTableDataRank0( std::ostream & tableOutput, - PreparedTableLayout const & tableLayout, - CellLayoutRows const & dataCellsLayout, - Status & status ) const; - + CellLayoutRows const & dataCellsLayout, + PreparedTableLayout const & tableLayout, + TableTextMpiOutput::Status & status )const; }; } From ebdadd80fec60d3c17112b8dd8283056c6761fd2 Mon Sep 17 00:00:00 2001 From: arng40 Date: Mon, 16 Mar 2026 10:55:09 +0100 Subject: [PATCH 25/70] =?UTF-8?q?Improve=20structure=20=F0=9F=8E=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/format/table/TableFormatter.cpp | 4 +-- .../format/table/TableMpiComponents.cpp | 36 ++++++++++--------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/coreComponents/common/format/table/TableFormatter.cpp b/src/coreComponents/common/format/table/TableFormatter.cpp index b04cd73e174..65f609bd3e1 100644 --- a/src/coreComponents/common/format/table/TableFormatter.cpp +++ b/src/coreComponents/common/format/table/TableFormatter.cpp @@ -844,7 +844,7 @@ void TableTextFormatter::outputLine( PreparedTableLayout const & tableLayout, formatCell( tableOutput, cell, idxSubLine ); if( !isRightBorderCell ) - { // right side of a cell that have a neightboor + { // right side of a cell that have a neightboor bool const isNextSeparator = row.cells[idxColumn + 1].m_cellType == CellType::Separator; bool const upMerged = idxRow > 0 && rows[idxRow - 1].cells[idxColumn].m_cellType == CellType::MergeNext; bool const downMerged = idxRow < nbRows - 1 && rows[idxRow + 1].cells[idxColumn].m_cellType == CellType::MergeNext; @@ -853,7 +853,7 @@ void TableTextFormatter::outputLine( PreparedTableLayout const & tableLayout, m_horizontalLine : m_verticalLine ); } else - { // right table border + { // right table border tableOutput << string( nbBorderSpaces, cellSpaceChar ) << m_verticalLine << "\n"; } } diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index 541f350574c..d9d04bdb023 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -57,8 +57,8 @@ void TableTextMpiOutput::stretchColumnsByRanks( stdVector< size_t > & columnsWid MpiWrapper::allReduce( columnsWidth, columnsWidth, MpiWrapper::Reduction::Max ); } -void TableTextMpiOutput::convertRowsToString( CellLayoutRows const & rows, - stdVector< string > & rowsConvertedInString ) const +void TableTextMpiOutput::parseCellLayoutRows( CellLayoutRows const & rows, + stdVector< string > & rowsAsString ) const { std::ostringstream rowStringStream; size_t rowIndex = 0; @@ -67,30 +67,31 @@ void TableTextMpiOutput::convertRowsToString( CellLayoutRows const & rows, { outputLine( m_tableLayout, rows, row, rowStringStream, rowIndex ); rowIndex++; - rowsConvertedInString.emplace_back( rowStringStream.str()); + rowsAsString.emplace_back( rowStringStream.str()); rowStringStream.str( "" ); } } -stdVector< TableData::CellData > TableTextMpiOutput::reconstructRow( string_view str ) const +stdVector< TableData::CellData > TableTextMpiOutput::parseStringRow( string_view rowString ) const { - if( str.size() < 1 ) + if( rowString.empty() ) return stdVector< TableData::CellData >{}; - string_view rowContent( str.substr( 1 )); // skip leading '|' + if( rowString.front() == '|' ) + rowString.remove_prefix( 1 ); + string_view rowContent =rowString; string cell; - stdVector< TableData::CellData > reconstructedRow; + stdVector< TableData::CellData > dataRow; - std::string::size_type start = 0; std::string::size_type end = 0; - while( (end = rowContent.find( m_verticalLine, start )) != string_view::npos ) + while( (end = rowContent.find( m_verticalLine )) != string_view::npos ) { - cell =std::string( stringutilities::trimSpaces( rowContent.substr( start, end ))); - reconstructedRow.emplace_back( TableData::CellData( {CellType::Value, cell} )); + cell =std::string( stringutilities::trimSpaces( rowContent.substr( 0, end ))); + dataRow.emplace_back( TableData::CellData( {CellType::Value, cell} )); rowContent.remove_prefix( end + 1 ); } - return reconstructedRow; + return dataRow; } void TableTextMpiOutput::gatherAndSortTableDataAcrossRanks ( TableData & gatheredTableData, @@ -108,7 +109,7 @@ void TableTextMpiOutput::gatherAndSortTableDataAcrossRanks ( TableData & gathere { MpiWrapper::gatherStringOnRank0( row, std::function< void(string_view) >( [&]( string_view str ){ status.m_hasContent = true; - gatheredTableData.addRow( reconstructRow( str )); + gatheredTableData.addRow( parseStringRow( str )); } )); } @@ -122,7 +123,7 @@ void TableTextMpiOutput::gatherSortAndOutput( std::ostream & tableOutput, TableTextMpiOutput::Status & status ) const { stdVector< string > rowsAsString; - convertRowsToString( rows, rowsAsString ); + parseCellLayoutRows( rows, rowsAsString ); TableData gatheredTableData; gatherAndSortTableDataAcrossRanks( gatheredTableData, rowsAsString, status ); @@ -146,7 +147,8 @@ void TableTextMpiOutput::gatherAndOutputTableDataInRankOrder( std::ostream & tab { if( m_mpiLayout.m_separatorBetweenRanks ) { - string const rankSepLine = GEOS_FMT( "{:-^{}}", m_mpiLayout.m_rankTitle, status.m_sepLine.size() - 2 ); + size_t const sepWidth = status.m_sepLine.size() > 2 ? status.m_sepLine.size() - 2 : 0; + string const rankSepLine = GEOS_FMT( "{:-^{}}", m_mpiLayout.m_rankTitle, sepWidth ); rankOutput << tableLayout.getIndentationStr() << m_verticalLine << rankSepLine << m_verticalLine << '\n'; } outputTableData( rankOutput, tableLayout, rows ); @@ -154,10 +156,10 @@ void TableTextMpiOutput::gatherAndOutputTableDataInRankOrder( std::ostream & tab string const rankStr = !status.m_isMasterRank && status.m_isContributing ? localStringStream.str() : ""; stdVector< string > strsAccrossRanks; - MpiWrapper::gatherStringOnRank0( rankStr, std::function< void(string_view) >( [&]( string_view str ){ + MpiWrapper::gatherStringOnRank0( rankStr, [&]( string_view str ){ status.m_hasContent = true; strsAccrossRanks.emplace_back( str ); - } )); + } ); if( status.m_isMasterRank && status.m_hasContent ) { From b0eb0f6734b48d7985feb8834e3f8cee6a51f470 Mon Sep 17 00:00:00 2001 From: arng40 Date: Mon, 16 Mar 2026 11:02:45 +0100 Subject: [PATCH 26/70] Remove code :fire: --- src/coreComponents/mesh/ElementRegionManager.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index 7a2e21a5978..e79affceab2 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -30,8 +30,6 @@ #include "schema/schemaUtilities.hpp" #include "mesh/generators/LineBlockABC.hpp" #include "mesh/CellElementRegionSelector.hpp" -#include "dataRepository/BufferOps.hpp" -#include "dataRepository/BufferOps_inline.hpp" namespace geos From 57d5802c12075dc8b8d0bf03739d2a944c0ca8ec Mon Sep 17 00:00:00 2001 From: arng40 Date: Mon, 16 Mar 2026 11:03:01 +0100 Subject: [PATCH 27/70] Fix a bug. :bug: --- src/coreComponents/common/format/table/TableMpiComponents.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index d9d04bdb023..34e6bad858a 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -156,10 +156,10 @@ void TableTextMpiOutput::gatherAndOutputTableDataInRankOrder( std::ostream & tab string const rankStr = !status.m_isMasterRank && status.m_isContributing ? localStringStream.str() : ""; stdVector< string > strsAccrossRanks; - MpiWrapper::gatherStringOnRank0( rankStr, [&]( string_view str ){ + MpiWrapper::gatherStringOnRank0( rankStr, std::function< void(string_view) >( [&]( string_view str ){ status.m_hasContent = true; strsAccrossRanks.emplace_back( str ); - } ); + } ) ); if( status.m_isMasterRank && status.m_hasContent ) { From 763103a73cfa1dd02065e30897155388c0470d2e Mon Sep 17 00:00:00 2001 From: arng40 Date: Tue, 17 Mar 2026 14:53:35 +0100 Subject: [PATCH 28/70] :green_heart: uncrustify --- .../common/format/table/TableData.cpp | 60 +++++++++---------- .../common/format/table/TableFormatter.cpp | 22 +++---- .../format/table/unitTests/testMpiTable.cpp | 2 +- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp index edd7924e4c9..1b49679f123 100644 --- a/src/coreComponents/common/format/table/TableData.cpp +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -183,40 +183,40 @@ TableData2D::TableDataHolder TableData2D::buildTableData( string_view targetUnit bool tabledatasorting::positiveNumberStringComp( string_view s1, string_view s2 ) { - auto split = [](string_view s, string & intPart, string & decPart) + auto split = []( string_view s, string & intPart, string & decPart ) + { + size_t dotPos = s.find( '.' ); + if( dotPos == string::npos ) { - size_t dotPos = s.find('.'); - if(dotPos == string::npos) - { - intPart = s; - decPart = ""; - } - else - { - intPart = s.substr(0, dotPos); - decPart = s.substr(dotPos + 1); - } - }; - - string s1Int, s1Dec, s2Int, s2Dec; - split(s1, s1Int, s1Dec); - split(s2, s2Int, s2Dec); - - if(s1Int.length() != s2Int.length()) - return s1Int.length() < s2Int.length(); - - if(s1Int != s2Int) - return s1Int < s2Int; - - size_t minLen = std::min(s1Dec.length(), s2Dec.length()); - for(size_t i = 0; i < minLen; ++i) + intPart = s; + decPart = ""; + } + else { - if(s1Dec[i] != s2Dec[i]) - return s1Dec[i] < s2Dec[i]; + intPart = s.substr( 0, dotPos ); + decPart = s.substr( dotPos + 1 ); } + }; + + string s1Int, s1Dec, s2Int, s2Dec; + split( s1, s1Int, s1Dec ); + split( s2, s2Int, s2Dec ); + + if( s1Int.length() != s2Int.length()) + return s1Int.length() < s2Int.length(); + + if( s1Int != s2Int ) + return s1Int < s2Int; + + size_t minLen = std::min( s1Dec.length(), s2Dec.length()); + for( size_t i = 0; i < minLen; ++i ) + { + if( s1Dec[i] != s2Dec[i] ) + return s1Dec[i] < s2Dec[i]; + } + - - return false; + return false; } } diff --git a/src/coreComponents/common/format/table/TableFormatter.cpp b/src/coreComponents/common/format/table/TableFormatter.cpp index 65f609bd3e1..0fceb06ce82 100644 --- a/src/coreComponents/common/format/table/TableFormatter.cpp +++ b/src/coreComponents/common/format/table/TableFormatter.cpp @@ -813,7 +813,7 @@ void TableTextFormatter::outputLine( PreparedTableLayout const & tableLayout, { size_t const nbRows = rows.size(); size_t const nbColumns = !rows.empty() ? rows.front().cells.size() : 0; - + size_t const nbBorderSpaces = tableLayout.getBorderMargin(); size_t const nbColumnSpaces = ( tableLayout.getColumnMargin() - 1 ) / 2; for( size_t idxSubLine = 0; idxSubLine < row.sublinesCount; idxSubLine++ ) @@ -829,16 +829,16 @@ void TableTextFormatter::outputLine( PreparedTableLayout const & tableLayout, bool const isSeparator = cell.m_cellType == CellType::Separator; char const cellSpaceChar = isSeparator ? m_horizontalLine : ' '; - if( isLeftBorderCell ) - { // left table border - isLeftBorderCell=false; - tableOutput << tableLayout.getIndentationStr(); - tableOutput << m_verticalLine << string( nbBorderSpaces, cellSpaceChar ); - } - else - { // left side of a cell that have a neightboor - tableOutput << string( nbColumnSpaces, cellSpaceChar ); - } + if( isLeftBorderCell ) + { // left table border + isLeftBorderCell=false; + tableOutput << tableLayout.getIndentationStr(); + tableOutput << m_verticalLine << string( nbBorderSpaces, cellSpaceChar ); + } + else + { // left side of a cell that have a neightboor + tableOutput << string( nbColumnSpaces, cellSpaceChar ); + } // cell content / fill formatCell( tableOutput, cell, idxSubLine ); diff --git a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp index cc64f1116ae..97b1d7dc1ed 100644 --- a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp +++ b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp @@ -205,7 +205,7 @@ TEST( testMpiTables, testSortingMethod ) formatter.toStream( oss, data ); if( rankId == 0 ) { - std::cout << "ma boula """<< oss.str()< Date: Wed, 18 Mar 2026 10:32:17 +0100 Subject: [PATCH 29/70] :lipstick: set rank column to the right --- src/coreComponents/mesh/ElementRegionManager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index e79affceab2..68882f956c2 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -237,8 +237,8 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM TableLayout const layoutPerforation ( GEOS_FMT( "Well '{}' Perforation Table", wellRegion.getWellGeneratorName()), { - "Rank", "Perforation", "Well element", "Coordinates", - "Cell region", "Cell sub-region", "Cell ID" + "Perforation", "Well element", "Coordinates", + "Cell region", "Cell sub-region", "Cell ID", "Rank" } ); PerforationData const * wellSubRegionPerforationData= wellSubRegion.getPerforationData(); @@ -265,8 +265,8 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM localCoords.emplace_back( wsrPerfLocation[iperfLocal][0] ); localCoords.emplace_back( wsrPerfLocation[iperfLocal][1] ); localCoords.emplace_back( wsrPerfLocation[iperfLocal][2] ); - localPerfoData.addRow( rankId, globalIperf[iperfLocal], localWellElemIndices, localCoords, - region.getName(), subRegion.getName(), cellId ); + localPerfoData.addRow( globalIperf[iperfLocal], localWellElemIndices, localCoords, + region.getName(), subRegion.getName(), cellId, rankId ); } } From d15042d5031666f96098b0678afe91e74a207266 Mon Sep 17 00:00:00 2001 From: arng40 Date: Thu, 19 Mar 2026 17:34:48 +0100 Subject: [PATCH 30/70] :label: renaming & cde style --- src/coreComponents/common/MpiWrapper.hpp | 16 +++--- .../common/format/table/TableFormatter.cpp | 48 +++++++++--------- .../format/table/TableMpiComponents.cpp | 50 +++++++++---------- .../format/table/TableMpiComponents.hpp | 14 +++--- .../format/table/unitTests/testMpiTable.cpp | 4 +- .../mesh/ElementRegionManager.cpp | 10 ++-- .../fluidFlow/SolutionCheckHelpers.cpp | 2 +- 7 files changed, 74 insertions(+), 70 deletions(-) diff --git a/src/coreComponents/common/MpiWrapper.hpp b/src/coreComponents/common/MpiWrapper.hpp index 1278e90c0c2..0c669849a66 100644 --- a/src/coreComponents/common/MpiWrapper.hpp +++ b/src/coreComponents/common/MpiWrapper.hpp @@ -334,13 +334,17 @@ struct MpiWrapper /** * @brief Structure holding the result from all the gather operation * @tparam CONTAINER The container type holding the data. + * The underlying storage in CONTAINER must be contiguous */ template< typename CONTAINER > struct GatherResult { - CONTAINER data; // Collected data - stdVector< integer > counts; // Number of elements per row - stdVector< integer > offsets; // Starting index for each row in 'data' + // Collected data who must be trivially copyable + CONTAINER data; + // Number of elements per row + stdVector< integer > counts; + // Starting index for each row in 'data' + stdVector< integer > offsets; }; /** @@ -366,7 +370,7 @@ struct MpiWrapper gatherBufferRank0( CONTAINER const & localBuffer ) { integer const numRanks = MpiWrapper::commSize(); - integer const numValues = static_cast< integer >(localBuffer.size()); + integer const numLocalValues = static_cast< integer >(localBuffer.size()); GatherResult< CONTAINER > gatherResult; @@ -377,7 +381,7 @@ struct MpiWrapper } - MpiWrapper::gather( &numValues, 1, gatherResult.counts.data(), 1, 0 ); + MpiWrapper::gather( &numLocalValues , 1, gatherResult.counts.data(), 1, 0 ); if( MpiWrapper::commRank() == 0 ) { @@ -391,7 +395,7 @@ struct MpiWrapper } MpiWrapper::gatherv( localBuffer.data(), - numValues, + numLocalValues , gatherResult.data.data(), gatherResult.counts.data(), gatherResult.offsets.data(), diff --git a/src/coreComponents/common/format/table/TableFormatter.cpp b/src/coreComponents/common/format/table/TableFormatter.cpp index 0fceb06ce82..81df90d8e6a 100644 --- a/src/coreComponents/common/format/table/TableFormatter.cpp +++ b/src/coreComponents/common/format/table/TableFormatter.cpp @@ -227,28 +227,28 @@ template<> string TableTextFormatter::toString< TableData >( TableData const & tableData ) const { std::ostringstream tableOutput; - CellLayoutRows headerCellsLayout; - CellLayoutRows dataCellsLayout; - CellLayoutRows errorCellsLayout; + CellLayoutRows headerRows; + CellLayoutRows dataRows; + CellLayoutRows errorRows; size_t tableTotalWidth = 0; initalizeTableGrids( m_tableLayout, tableData, - headerCellsLayout, dataCellsLayout, errorCellsLayout, + headerRows, dataRows, errorRows, tableTotalWidth, nullptr ); string const sepLine = string( tableTotalWidth, m_horizontalLine ); - outputTableHeader( tableOutput, m_tableLayout, headerCellsLayout, sepLine ); - outputTableData( tableOutput, m_tableLayout, dataCellsLayout ); - outputTableFooter( tableOutput, m_tableLayout, errorCellsLayout, sepLine, !dataCellsLayout.empty() ); + outputTableHeader( tableOutput, m_tableLayout, headerRows, sepLine ); + outputTableData( tableOutput, m_tableLayout, dataRows ); + outputTableFooter( tableOutput, m_tableLayout, errorRows, sepLine, !dataRows.empty() ); return tableOutput.str(); } void TableTextFormatter::initalizeTableGrids( PreparedTableLayout const & tableLayout, TableData const & tableInputData, - CellLayoutRows & headerCellsLayout, - CellLayoutRows & dataCellsLayout, - CellLayoutRows & errorCellsLayout, + CellLayoutRows & headerRows, + CellLayoutRows & dataRows, + CellLayoutRows & errorRows, size_t & tableTotalWidth, ColumnWidthModifier columnWidthModifier ) const { @@ -261,30 +261,30 @@ void TableTextFormatter::initalizeTableGrids( PreparedTableLayout const & tableL // this array will store the displayed width of all columns (it will be scaled by data & headers width) stdVector< size_t > columnsWidth = stdVector< size_t >( nbVisibleColumns, 0 ); - populateTitleCellsLayout( tableLayout, headerCellsLayout, nbVisibleColumns ); + populateTitleCellsLayout( tableLayout, headerRows, nbVisibleColumns ); if( hasColumnLayout ) { - populateHeaderCellsLayout( tableLayout, headerCellsLayout, nbVisibleColumns ); - populateDataCellsLayout( tableLayout, dataCellsLayout, inputDataValues, nbVisibleColumns ); + populateHeaderCellsLayout( tableLayout, headerRows, nbVisibleColumns ); + populateDataCellsLayout( tableLayout, dataRows, inputDataValues, nbVisibleColumns ); } else { - populateDataCellsLayout( tableLayout, dataCellsLayout, inputDataValues ); + populateDataCellsLayout( tableLayout, dataRows, inputDataValues ); } if( getErrorsList().hasErrors() || tableInputData.getErrorsList().hasErrors()) { - populateErrorCellsLayout( tableLayout, errorCellsLayout, tableInputData.getErrorsList() ); + populateErrorCellsLayout( tableLayout, errorRows, tableInputData.getErrorsList() ); } - stretchColumnsByCellsWidth( columnsWidth, headerCellsLayout ); - stretchColumnsByCellsWidth( columnsWidth, dataCellsLayout ); - stretchColumnsByCellsWidth( columnsWidth, errorCellsLayout ); + stretchColumnsByCellsWidth( columnsWidth, headerRows ); + stretchColumnsByCellsWidth( columnsWidth, dataRows ); + stretchColumnsByCellsWidth( columnsWidth, errorRows ); // only after all cells that are not merge, we can process the merged cells. - stretchColumnsByMergedCellsWidth( columnsWidth, headerCellsLayout, tableLayout, false ); - stretchColumnsByMergedCellsWidth( columnsWidth, dataCellsLayout, tableLayout, true ); - stretchColumnsByMergedCellsWidth( columnsWidth, errorCellsLayout, tableLayout, true ); + stretchColumnsByMergedCellsWidth( columnsWidth, headerRows, tableLayout, false ); + stretchColumnsByMergedCellsWidth( columnsWidth, dataRows, tableLayout, true ); + stretchColumnsByMergedCellsWidth( columnsWidth, errorRows, tableLayout, true ); if( columnWidthModifier ) columnWidthModifier( columnsWidth ); @@ -298,9 +298,9 @@ void TableTextFormatter::initalizeTableGrids( PreparedTableLayout const & tableL } // we can now propagate the columns width width to all cells - applyColumnsWidth( columnsWidth, headerCellsLayout, tableLayout ); - applyColumnsWidth( columnsWidth, dataCellsLayout, tableLayout ); - applyColumnsWidth( columnsWidth, errorCellsLayout, tableLayout ); + applyColumnsWidth( columnsWidth, headerRows, tableLayout ); + applyColumnsWidth( columnsWidth, dataRows, tableLayout ); + applyColumnsWidth( columnsWidth, errorRows, tableLayout ); } void TableTextFormatter::populateTitleCellsLayout( PreparedTableLayout const & tableLayout, diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index 34e6bad858a..dc50560a570 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -24,19 +24,19 @@ namespace geos { -TableTextMpiOutput::TableTextMpiOutput( TableMpiLayout mpiLayout ): +TableTextMpiFormatter::TableTextMpiFormatter( TableMpiLayout mpiLayout ): TableTextFormatter(), m_mpiLayout( mpiLayout ) {} -TableTextMpiOutput::TableTextMpiOutput( TableLayout const & tableLayout, - TableMpiLayout mpiLayout ): +TableTextMpiFormatter::TableTextMpiFormatter( TableLayout const & tableLayout, + TableMpiLayout mpiLayout ): TableTextFormatter( tableLayout ), m_mpiLayout( mpiLayout ) {} -void TableTextMpiOutput::stretchColumnsByRanks( stdVector< size_t > & columnsWidth, - TableTextMpiOutput::Status const & status ) const +void TableTextMpiFormatter::stretchColumnsByRanks( stdVector< size_t > & columnsWidth, + TableTextMpiFormatter::Status const & status ) const { { // we ensure we have the correct amount of columns on all ranks (for correct MPI reduction operation) size_t const rankColumnsCount = columnsWidth.size(); @@ -57,8 +57,8 @@ void TableTextMpiOutput::stretchColumnsByRanks( stdVector< size_t > & columnsWid MpiWrapper::allReduce( columnsWidth, columnsWidth, MpiWrapper::Reduction::Max ); } -void TableTextMpiOutput::parseCellLayoutRows( CellLayoutRows const & rows, - stdVector< string > & rowsAsString ) const +void TableTextMpiFormatter::cellRowsToStrings( CellLayoutRows const & rows, + stdVector< string > & rowsAsString ) const { std::ostringstream rowStringStream; size_t rowIndex = 0; @@ -72,7 +72,7 @@ void TableTextMpiOutput::parseCellLayoutRows( CellLayoutRows const & rows, } } -stdVector< TableData::CellData > TableTextMpiOutput::parseStringRow( string_view rowString ) const +stdVector< TableData::CellData > TableTextMpiFormatter::parseStringRow( string_view rowString ) const { if( rowString.empty() ) return stdVector< TableData::CellData >{}; @@ -94,9 +94,9 @@ stdVector< TableData::CellData > TableTextMpiOutput::parseStringRow( string_view return dataRow; } -void TableTextMpiOutput::gatherAndSortTableDataAcrossRanks ( TableData & gatheredTableData, - stdVector< string > & rowsAsString, - TableTextMpiOutput::Status & status ) const +void TableTextMpiFormatter::gatherAndSortTableDataAcrossRanks ( TableData & gatheredTableData, + stdVector< string > & rowsAsString, + TableTextMpiFormatter::Status & status ) const { array1d< integer > rowsSizeAcrossAllRank( MpiWrapper::commSize()); MpiWrapper::allGather( LvArray::integerConversion< integer >( rowsAsString.size()), @@ -118,12 +118,12 @@ void TableTextMpiOutput::gatherAndSortTableDataAcrossRanks ( TableData & gathere *m_sortingFunctor ); } -void TableTextMpiOutput::gatherSortAndOutput( std::ostream & tableOutput, - CellLayoutRows const & rows, - TableTextMpiOutput::Status & status ) const +void TableTextMpiFormatter::gatherSortAndOutput( std::ostream & tableOutput, + CellLayoutRows const & rows, + TableTextMpiFormatter::Status & status ) const { stdVector< string > rowsAsString; - parseCellLayoutRows( rows, rowsAsString ); + cellRowsToStrings( rows, rowsAsString ); TableData gatheredTableData; gatherAndSortTableDataAcrossRanks( gatheredTableData, rowsAsString, status ); @@ -134,10 +134,10 @@ void TableTextMpiOutput::gatherSortAndOutput( std::ostream & tableOutput, } } -void TableTextMpiOutput::gatherAndOutputTableDataInRankOrder( std::ostream & tableOutput, - CellLayoutRows const & rows, - PreparedTableLayout const & tableLayout, - TableTextMpiOutput::Status & status ) const +void TableTextMpiFormatter::gatherAndOutputTableDataInRankOrder( std::ostream & tableOutput, + CellLayoutRows const & rows, + PreparedTableLayout const & tableLayout, + TableTextMpiFormatter::Status & status ) const { // master rank does the output directly to the output, other ranks will have to send it through a string. std::ostringstream localStringStream; @@ -169,10 +169,10 @@ void TableTextMpiOutput::gatherAndOutputTableDataInRankOrder( std::ostream & tab } template<> -void TableTextMpiOutput::toStream< TableData >( std::ostream & tableOutput, - TableData const & tableData ) const +void TableTextMpiFormatter::toStream< TableData >( std::ostream & tableOutput, + TableData const & tableData ) const { - TableTextMpiOutput::Status status { + TableTextMpiFormatter::Status status { // m_isMasterRank (only the master rank does the output of the header && bottom of the table) MpiWrapper::commRank() == 0, // m_isContributing (some ranks does not have any output to produce) @@ -183,7 +183,7 @@ void TableTextMpiOutput::toStream< TableData >( std::ostream & tableOutput, "" }; - CellLayoutRows headerCellsLayout; + CellLayoutRows headerRows; CellLayoutRows dataRows; CellLayoutRows errorRows; size_t tableTotalWidth = 0; @@ -193,7 +193,7 @@ void TableTextMpiOutput::toStream< TableData >( std::ostream & tableOutput, stretchColumnsByRanks( columnsWidth, status ); }; initalizeTableGrids( m_tableLayout, tableData, - headerCellsLayout, dataRows, errorRows, + headerRows, dataRows, errorRows, tableTotalWidth, columnWidthModifier ); status.m_sepLine = string( tableTotalWidth, m_horizontalLine ); } @@ -206,7 +206,7 @@ void TableTextMpiOutput::toStream< TableData >( std::ostream & tableOutput, { if( status.m_isMasterRank ) { - outputTableHeader( tableOutput, m_tableLayout, headerCellsLayout, status.m_sepLine ); + outputTableHeader( tableOutput, m_tableLayout, headerRows, status.m_sepLine ); tableOutput.flush(); } gatherAndOutputTableDataInRankOrder( tableOutput, dataRows, m_tableLayout, status ); diff --git a/src/coreComponents/common/format/table/TableMpiComponents.hpp b/src/coreComponents/common/format/table/TableMpiComponents.hpp index c693419538c..f1fe55426d2 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.hpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.hpp @@ -42,7 +42,7 @@ struct TableMpiLayout * @brief class to format data in a formatted text format, allowing contributions from multiple * MPI ranks. */ -class TableTextMpiOutput : public TableTextFormatter +class TableTextMpiFormatter : public TableTextFormatter { public: /// base class @@ -54,14 +54,14 @@ class TableTextMpiOutput : public TableTextFormatter * without any column / title). Feature is not tested. * @param mpiLayout MPI-specific layout information (default is having contiguous ranks data). */ - TableTextMpiOutput( TableMpiLayout mpiLayout = TableMpiLayout() ); + TableTextMpiFormatter( TableMpiLayout mpiLayout = TableMpiLayout() ); /** * @brief Construct a new TableTextMpiOutput from a tableLayout * @param tableLayout Contain all tableColumnData names and optionnaly the table title * @param mpiLayout MPI-specific layout information (default is having contiguous ranks data). */ - TableTextMpiOutput( TableLayout const & tableLayout, + TableTextMpiFormatter( TableLayout const & tableLayout, TableMpiLayout mpiLayout = TableMpiLayout() ); /** @@ -116,7 +116,7 @@ class TableTextMpiOutput : public TableTextFormatter * @param cellLayoutRows The target CellLayoutRows to parse * @param rowsAsString The result vector of strings */ - void parseCellLayoutRows( CellLayoutRows const & cellLayoutRows, + void cellRowsToStrings( CellLayoutRows const & cellLayoutRows, stdVector< string > & rowsAsString ) const; /** @@ -135,7 +135,7 @@ class TableTextMpiOutput : public TableTextFormatter */ void gatherAndSortTableDataAcrossRanks ( TableData & gatheredTableData, stdVector< string > & rowsAsString, - TableTextMpiOutput::Status & status ) const; + TableTextMpiFormatter::Status & status ) const; /** * @brief Parse CellLayoutRows, gathers and sorts them across all MPI ranks, * and outputs the result to rank 0. @@ -145,7 +145,7 @@ class TableTextMpiOutput : public TableTextFormatter */ void gatherSortAndOutput( std::ostream & tableOutput, CellLayoutRows const & cellLayoutRows, - TableTextMpiOutput::Status & status )const; + TableTextMpiFormatter::Status & status )const; /** * @brief Gather data cell rows across all MPI ranks and output them to rank 0 in rank order. @@ -157,7 +157,7 @@ class TableTextMpiOutput : public TableTextFormatter void gatherAndOutputTableDataInRankOrder( std::ostream & tableOutput, CellLayoutRows const & dataCellsLayout, PreparedTableLayout const & tableLayout, - TableTextMpiOutput::Status & status )const; + TableTextMpiFormatter::Status & status )const; }; } diff --git a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp index 97b1d7dc1ed..11a251c8c5c 100644 --- a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp +++ b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp @@ -127,7 +127,7 @@ TEST( testMpiTables, testDifferentRankData ) } } - TableTextMpiOutput const formatter = TableTextMpiOutput( layout, mpiLayout ); + TableTextMpiFormatter const formatter = TableTextMpiFormatter( layout, mpiLayout ); std::ostringstream oss; formatter.toStream( oss, data ); if( rankId == 0 ) @@ -195,7 +195,7 @@ TEST( testMpiTables, testSortingMethod ) } } - TableTextMpiOutput formatter = TableTextMpiOutput( layout, mpiLayout ); + TableTextMpiFormatter formatter = TableTextMpiFormatter( layout, mpiLayout ); formatter.setSortingFunc( []( std::vector< TableData::CellData > const & row1, std::vector< TableData::CellData > const & row2 ) { return tabledatasorting::positiveNumberStringComp( row1[0].value, row2[0].value ); diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index 68882f956c2..e1828b5fe00 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -21,6 +21,7 @@ #include "common/DataLayouts.hpp" #include "common/TimingMacros.hpp" #include "common/format/table/TableMpiComponents.hpp" +#include "mesh/WellElementSubRegion.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "SurfaceElementRegion.hpp" #include "constitutive/ConstitutiveManager.hpp" @@ -232,8 +233,7 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM forElementRegions< WellElementRegion >( [&]( WellElementRegion const & wellRegion ){ WellElementSubRegion const & - wellSubRegion = wellRegion.getGroup( ElementRegionBase::viewKeyStruct::elementSubRegions() ) - .getGroup< WellElementSubRegion >( wellRegion.getSubRegionName() ); + wellSubRegion = wellRegion.getSubRegion< WellElementSubRegion >( wellRegion.getSubRegionName() ); TableLayout const layoutPerforation ( GEOS_FMT( "Well '{}' Perforation Table", wellRegion.getWellGeneratorName()), { @@ -261,17 +261,17 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM meshLevel.getElemManager().getRegion< ElementRegionBase >( targetRegionIndex ); ElementSubRegionBase const & subRegion = region.getSubRegion< ElementSubRegionBase >( targetSubRegionIndex ); - integer const localWellElemIndices = wellSubRegion.getGlobalWellElementIndex()[iperfLocal]; + integer const globalWellElemIndices = wellSubRegion.getGlobalWellElementIndex()[iperfLocal]; localCoords.emplace_back( wsrPerfLocation[iperfLocal][0] ); localCoords.emplace_back( wsrPerfLocation[iperfLocal][1] ); localCoords.emplace_back( wsrPerfLocation[iperfLocal][2] ); - localPerfoData.addRow( globalIperf[iperfLocal], localWellElemIndices, localCoords, + localPerfoData.addRow( globalIperf[iperfLocal], globalWellElemIndices, localCoords, region.getName(), subRegion.getName(), cellId, rankId ); } } TableMpiLayout mpiLayout; - TableTextMpiOutput formatter = TableTextMpiOutput( layoutPerforation, mpiLayout ); + TableTextMpiFormatter formatter = TableTextMpiFormatter( layoutPerforation, mpiLayout ); formatter.setSortingFunc( []( std::vector< TableData::CellData > const & row1, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SolutionCheckHelpers.cpp b/src/coreComponents/physicsSolvers/fluidFlow/SolutionCheckHelpers.cpp index 3d9366ef3b7..d1cd87b1976 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SolutionCheckHelpers.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/SolutionCheckHelpers.cpp @@ -102,7 +102,7 @@ void ElementsReporterOutput::outputTooLowValues( string_view linesPrefix, } } - TableTextMpiOutput const formatter = TableTextMpiOutput( layout, mpiLayout ); + TableTextMpiFormatter const formatter = TableTextMpiFormatter( layout, mpiLayout ); formatter.toStream( std::cout, data ); GEOS_LOG_RANK_0( '\n' ); } From 44ac609121b1eea54263dde283542b379f7abe9a Mon Sep 17 00:00:00 2001 From: arng40 Date: Thu, 19 Mar 2026 17:37:17 +0100 Subject: [PATCH 31/70] Squashed commit of the following: commit 85f63a96e155dc599e21e69f58490dcb3c7f82c4 Author: arng40 Date: Thu Mar 19 15:07:51 2026 +0100 :recycle: gathering method for tableData --- .../common/format/table/TableData.cpp | 22 ++++- .../common/format/table/TableData.hpp | 37 ++++---- .../format/table/TableMpiComponents.cpp | 91 ++++--------------- .../format/table/TableMpiComponents.hpp | 29 ------ 4 files changed, 57 insertions(+), 122 deletions(-) diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp index 1b49679f123..72c3908a82f 100644 --- a/src/coreComponents/common/format/table/TableData.cpp +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -59,7 +59,27 @@ TableData & TableData::operator=( TableData const & other ) bool TableData::operator<( TableData const & other ) const { - return m_rows < other.m_rows; + if( other.getCellsData().size()!= getCellsData().size()) + return false; + + for( size_t i = 0; i < getCellsData().size(); i++ ) + { + if( getCellsData()[i].data()->value > other.getCellsData()[i].data()->value ) + return false; + } + return true; +} + +bool TableData::operator==( TableData const & comparingTable ) const +{ + if( comparingTable.getCellsData().size()!= getCellsData().size()) + return false; + for( size_t i = 0; i < getCellsData().size(); i++ ) + { + if( getCellsData()[i].data()->value != comparingTable.getCellsData()[i].data()->value ) + return false; + } + return true; } diff --git a/src/coreComponents/common/format/table/TableData.hpp b/src/coreComponents/common/format/table/TableData.hpp index 64bedb96305..254aeb883d7 100644 --- a/src/coreComponents/common/format/table/TableData.hpp +++ b/src/coreComponents/common/format/table/TableData.hpp @@ -24,6 +24,7 @@ #include "common/DataTypes.hpp" #include "common/format/Format.hpp" #include "TableTypes.hpp" +#include namespace geos { @@ -54,6 +55,13 @@ class TableData */ bool operator<( TableData const & other ) const; + /** + * @brief Comparison operator for data rows + * @param comparingTable The tableData values to compare + * @return The comparison result + */ + bool operator==( TableData const & comparingTable ) const; + /** * @brief Representing a data in TableData */ @@ -63,20 +71,7 @@ class TableData CellType type; /// The cell value string value; - - /// @cond DO_NOT_DOCUMENT - bool operator==( CellData const & other ) const - { - return value == other.value; - } - - bool operator<( CellData const & other ) const - { - return value < other.value; - } - ///@endcond }; - /// Alias for table data rows with cells values using DataRows = stdVector< stdVector< CellData > >; @@ -129,14 +124,6 @@ class TableData DataRows & getCellsData() { return m_rows; } - /** - * @brief Comparison operator for data rows - * @param comparingTable The tableData values to compare - * @return The comparison result - */ - inline bool operator==( TableData const & comparingTable ) const - { return getCellsData() == comparingTable.getCellsData(); } - /** * @brief Get all error messages * @return The list of error messages @@ -148,8 +135,16 @@ class TableData * @brief Get all error messages * @return The list of error messages */ + TableErrorListing & getErrorsList() { return *m_errors; } + + /** + * @brief Gather all the TableData rows to the rank 0 + * @param func The callable comparison function object to sort TableData rows, by default none + */ + template< typename SortingFunc = std::nullptr_t > + void gatherRowsRank0( SortingFunc && func ); private: /// @brief vector containing all rows with cell values diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index dc50560a570..650b2f3ef62 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -57,21 +57,6 @@ void TableTextMpiFormatter::stretchColumnsByRanks( stdVector< size_t > & columns MpiWrapper::allReduce( columnsWidth, columnsWidth, MpiWrapper::Reduction::Max ); } -void TableTextMpiFormatter::cellRowsToStrings( CellLayoutRows const & rows, - stdVector< string > & rowsAsString ) const -{ - std::ostringstream rowStringStream; - size_t rowIndex = 0; - - for( CellLayoutRow const & row : rows ) - { - outputLine( m_tableLayout, rows, row, rowStringStream, rowIndex ); - rowIndex++; - rowsAsString.emplace_back( rowStringStream.str()); - rowStringStream.str( "" ); - } -} - stdVector< TableData::CellData > TableTextMpiFormatter::parseStringRow( string_view rowString ) const { if( rowString.empty() ) @@ -94,46 +79,6 @@ stdVector< TableData::CellData > TableTextMpiFormatter::parseStringRow( string_v return dataRow; } -void TableTextMpiFormatter::gatherAndSortTableDataAcrossRanks ( TableData & gatheredTableData, - stdVector< string > & rowsAsString, - TableTextMpiFormatter::Status & status ) const -{ - array1d< integer > rowsSizeAcrossAllRank( MpiWrapper::commSize()); - MpiWrapper::allGather( LvArray::integerConversion< integer >( rowsAsString.size()), - rowsSizeAcrossAllRank ); - integer const maxRowAcrossAllRanks = *std::max_element( rowsSizeAcrossAllRank.begin(), - rowsSizeAcrossAllRank.end()); - rowsAsString.resize( maxRowAcrossAllRanks ); - - for( string & row : rowsAsString ) - { - MpiWrapper::gatherStringOnRank0( row, std::function< void(string_view) >( [&]( string_view str ){ - status.m_hasContent = true; - gatheredTableData.addRow( parseStringRow( str )); - } )); - } - - std::sort( gatheredTableData.getCellsData().begin(), - gatheredTableData.getCellsData().end(), - *m_sortingFunctor ); -} - -void TableTextMpiFormatter::gatherSortAndOutput( std::ostream & tableOutput, - CellLayoutRows const & rows, - TableTextMpiFormatter::Status & status ) const -{ - stdVector< string > rowsAsString; - cellRowsToStrings( rows, rowsAsString ); - - TableData gatheredTableData; - gatherAndSortTableDataAcrossRanks( gatheredTableData, rowsAsString, status ); - - if( status.m_isMasterRank && status.m_hasContent ) - { - tableOutput << toString( gatheredTableData ); - } -} - void TableTextMpiFormatter::gatherAndOutputTableDataInRankOrder( std::ostream & tableOutput, CellLayoutRows const & rows, PreparedTableLayout const & tableLayout, @@ -183,27 +128,31 @@ void TableTextMpiFormatter::toStream< TableData >( std::ostream & tableOutput, "" }; - CellLayoutRows headerRows; - CellLayoutRows dataRows; - CellLayoutRows errorRows; - size_t tableTotalWidth = 0; - - { - ColumnWidthModifier const columnWidthModifier = [this, status]( stdVector< size_t > & columnsWidth ) { - stretchColumnsByRanks( columnsWidth, status ); - }; - initalizeTableGrids( m_tableLayout, tableData, - headerRows, dataRows, errorRows, - tableTotalWidth, columnWidthModifier ); - status.m_sepLine = string( tableTotalWidth, m_horizontalLine ); - } - if( m_sortingFunctor ) { - gatherSortAndOutput( tableOutput, dataRows, status ); + tableData.gatherRowsRank0( m_sortingFunctor ); + if( status.m_isMasterRank ) + { + toString( tableData ); + } } else { + CellLayoutRows headerCellsLayout; + CellLayoutRows dataRows; + CellLayoutRows errorRows; + size_t tableTotalWidth = 0; + + { + ColumnWidthModifier const columnWidthModifier = [this, status]( stdVector< size_t > & columnsWidth ) { + stretchColumnsByRanks( columnsWidth, status ); + }; + initalizeTableGrids( m_tableLayout, tableData, + headerCellsLayout, dataRows, errorRows, + tableTotalWidth, columnWidthModifier ); + status.m_sepLine = string( tableTotalWidth, m_horizontalLine ); + } + if( status.m_isMasterRank ) { outputTableHeader( tableOutput, m_tableLayout, headerRows, status.m_sepLine ); diff --git a/src/coreComponents/common/format/table/TableMpiComponents.hpp b/src/coreComponents/common/format/table/TableMpiComponents.hpp index f1fe55426d2..5a8b26d770b 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.hpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.hpp @@ -110,15 +110,6 @@ class TableTextMpiFormatter : public TableTextFormatter void stretchColumnsByRanks( stdVector< size_t > & columnsWidth, Status const & status ) const; - - /** - * @brief Parse each row of a CellLayoutRows into its string representation. - * @param cellLayoutRows The target CellLayoutRows to parse - * @param rowsAsString The result vector of strings - */ - void cellRowsToStrings( CellLayoutRows const & cellLayoutRows, - stdVector< string > & rowsAsString ) const; - /** * @brief Parse a string row to a TablaData cells. * @param rowString The string row string to parse. @@ -126,26 +117,6 @@ class TableTextMpiFormatter : public TableTextFormatter */ stdVector< TableData::CellData > parseStringRow( string_view rowString ) const; - /** - * @brief Gather string rows across all ranks, construct a TableData, - * and sort the TableData by the desired sorting functor - * @param gatheredTableData The output TableData object populated with gathered cells. - * @param rowsAsString Serialized rows string provided by the current rank. - * @param status Updated to indicate if any content was actually gathered. - */ - void gatherAndSortTableDataAcrossRanks ( TableData & gatheredTableData, - stdVector< string > & rowsAsString, - TableTextMpiFormatter::Status & status ) const; - /** - * @brief Parse CellLayoutRows, gathers and sorts them across all MPI ranks, - * and outputs the result to rank 0. - * @param tableOutput The output stream where the formatted table is written. - * @param cellLayoutRows The layout for the data cells - * @param status The TableMpi status for the current rank - */ - void gatherSortAndOutput( std::ostream & tableOutput, - CellLayoutRows const & cellLayoutRows, - TableTextMpiFormatter::Status & status )const; /** * @brief Gather data cell rows across all MPI ranks and output them to rank 0 in rank order. From 824deb6a692ff97af00c89a452b0d98345f6e9bb Mon Sep 17 00:00:00 2001 From: arng40 Date: Thu, 19 Mar 2026 17:45:25 +0100 Subject: [PATCH 32/70] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 1583882e2988399b9fc38878bddbb5b483052bc6 Author: MelReyCG Date: Thu Mar 19 17:22:57 2026 +0100 ๐Ÿšง wipwipwip commit 85f63a96e155dc599e21e69f58490dcb3c7f82c4 Author: arng40 Date: Thu Mar 19 15:07:51 2026 +0100 :recycle: gathering method for tableData --- .../format/table/TableMpiComponents.cpp | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index 650b2f3ef62..fbf188e1095 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -57,7 +57,7 @@ void TableTextMpiFormatter::stretchColumnsByRanks( stdVector< size_t > & columns MpiWrapper::allReduce( columnsWidth, columnsWidth, MpiWrapper::Reduction::Max ); } -stdVector< TableData::CellData > TableTextMpiFormatter::parseStringRow( string_view rowString ) const +stdVector< TableData::CellData > TableTextMpiOutput::parseStringRow( string_view rowString ) const { if( rowString.empty() ) return stdVector< TableData::CellData >{}; @@ -79,10 +79,10 @@ stdVector< TableData::CellData > TableTextMpiFormatter::parseStringRow( string_v return dataRow; } -void TableTextMpiFormatter::gatherAndOutputTableDataInRankOrder( std::ostream & tableOutput, - CellLayoutRows const & rows, - PreparedTableLayout const & tableLayout, - TableTextMpiFormatter::Status & status ) const +void TableTextMpiOutput::gatherAndOutputTableDataInRankOrder( std::ostream & tableOutput, + CellLayoutRows const & rows, + PreparedTableLayout const & tableLayout, + TableTextMpiOutput::Status & status ) const { // master rank does the output directly to the output, other ranks will have to send it through a string. std::ostringstream localStringStream; @@ -123,30 +123,32 @@ void TableTextMpiFormatter::toStream< TableData >( std::ostream & tableOutput, // m_isContributing (some ranks does not have any output to produce) !tableData.getCellsData().empty(), // m_hasContent - false, + false, // m_sepLine "" }; if( m_sortingFunctor ) { - tableData.gatherRowsRank0( m_sortingFunctor ); + tableData.serialize( X ); + gatherTableDataOnRank0( tableData, X ); + if( status.m_isMasterRank ) { - toString( tableData ); + tableData.sort( m_sortingFunctor ); + TableTextFormatter::toStream( tableOutput, tableData ); } } else - { + { // this version is faster (MPI cooperation) but can only be ordered by rank id CellLayoutRows headerCellsLayout; CellLayoutRows dataRows; CellLayoutRows errorRows; size_t tableTotalWidth = 0; - - { + { // compute layout ColumnWidthModifier const columnWidthModifier = [this, status]( stdVector< size_t > & columnsWidth ) { - stretchColumnsByRanks( columnsWidth, status ); - }; + stretchColumnsByRanks( columnsWidth, status ); + }; initalizeTableGrids( m_tableLayout, tableData, headerCellsLayout, dataRows, errorRows, tableTotalWidth, columnWidthModifier ); @@ -165,7 +167,6 @@ void TableTextMpiFormatter::toStream< TableData >( std::ostream & tableOutput, status.m_sepLine, status.m_hasContent ); tableOutput.flush(); } - } } From d340530e4e71ce3b857d75a00b9932d4c3293e61 Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 20 Mar 2026 16:23:18 +0100 Subject: [PATCH 33/70] :construction: serialization/deserialisation cellData --- .../common/format/table/TableData.cpp | 66 +++++++++++++++++++ .../common/format/table/TableData.hpp | 6 +- .../format/table/TableMpiComponents.cpp | 63 ++++++++++++++---- 3 files changed, 120 insertions(+), 15 deletions(-) diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp index 72c3908a82f..c9c9e7298de 100644 --- a/src/coreComponents/common/format/table/TableData.cpp +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -18,7 +18,9 @@ */ #include "TableData.hpp" +#include "common/DataTypes.hpp" #include "common/logger/Logger.hpp" +#include "dataRepository/BufferOps.hpp" namespace geos { @@ -82,6 +84,70 @@ bool TableData::operator==( TableData const & comparingTable ) const return true; } +size_t TableData::CellData::serializeTo( buffer_unit_type * buffer ) const +{ + buffer_unit_type * dummy = nullptr; + size_t sizeOftype = bufferOps::Pack< false >( dummy, type ); + string::size_type sizeOfString = bufferOps::Pack< false >( dummy, value ); + + if( buffer ) + { + auto it = buffer; + bufferOps::Pack< true >( buffer, sizeOftype ); + bufferOps::Pack< true >( buffer, type ); + bufferOps::Pack< true >( buffer, value ); + return buffer - it; + } + else + { + return sizeof(size_t) + sizeOftype + sizeOfString; + } +} + +stdVector< buffer_unit_type > TableData::serialize() const +{ + if( m_rows.empty()) + return {}; + + size_t totalSize = 0; + + // pre-calculate total size + totalSize += sizeof(size_t); + for( auto & row : m_rows ) + { + size_t rowSize = 0; + for( auto & cell : row ) + { + rowSize += sizeof(size_t) + cell.serializeTo( nullptr ); + } + totalSize += sizeof(size_t) + rowSize; + } + + stdVector< buffer_unit_type > rowsPacked; + rowsPacked.resize( totalSize ); + buffer_unit_type * itRowsPacked = rowsPacked.data(); + bufferOps::Pack< true >( itRowsPacked, totalSize ); + for( auto & row : m_rows ) + { + size_t rowSize = 0; + // pack row size; + for( auto const & cell : row ) + rowSize += sizeof(size_t) + cell.serializeTo( nullptr ); + bufferOps::Pack< true >( itRowsPacked, rowSize ); + + // pack cells + for( auto const & cell : row ) + { + size_t cellSize = cell.serializeTo( nullptr ); + bufferOps::Pack< true >( itRowsPacked, cellSize ); + cell.serializeTo( itRowsPacked ); + itRowsPacked += cellSize; + } + } + + return rowsPacked; +} + void TableData::addRow( stdVector< TableData::CellData > const & row ) diff --git a/src/coreComponents/common/format/table/TableData.hpp b/src/coreComponents/common/format/table/TableData.hpp index 254aeb883d7..1f74c0abe5b 100644 --- a/src/coreComponents/common/format/table/TableData.hpp +++ b/src/coreComponents/common/format/table/TableData.hpp @@ -71,10 +71,14 @@ class TableData CellType type; /// The cell value string value; + + size_t serializeTo( buffer_unit_type * buffer ) const; }; /// Alias for table data rows with cells values using DataRows = stdVector< stdVector< CellData > >; + stdVector< buffer_unit_type > serialize() const; + /** * @brief Add a row to the table. * The values passed to addRow (can be any type). @@ -138,7 +142,7 @@ class TableData TableErrorListing & getErrorsList() { return *m_errors; } - + /** * @brief Gather all the TableData rows to the rank 0 * @param func The callable comparison function object to sort TableData rows, by default none diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index fbf188e1095..34e6d1b7836 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -20,6 +20,8 @@ #include "TableMpiComponents.hpp" #include "common/MpiWrapper.hpp" +#include "dataRepository/BufferOps.hpp" + namespace geos { @@ -57,7 +59,7 @@ void TableTextMpiFormatter::stretchColumnsByRanks( stdVector< size_t > & columns MpiWrapper::allReduce( columnsWidth, columnsWidth, MpiWrapper::Reduction::Max ); } -stdVector< TableData::CellData > TableTextMpiOutput::parseStringRow( string_view rowString ) const +stdVector< TableData::CellData > TableTextMpiFormatter::parseStringRow( string_view rowString ) const { if( rowString.empty() ) return stdVector< TableData::CellData >{}; @@ -79,10 +81,10 @@ stdVector< TableData::CellData > TableTextMpiOutput::parseStringRow( string_view return dataRow; } -void TableTextMpiOutput::gatherAndOutputTableDataInRankOrder( std::ostream & tableOutput, - CellLayoutRows const & rows, - PreparedTableLayout const & tableLayout, - TableTextMpiOutput::Status & status ) const +void TableTextMpiFormatter::gatherAndOutputTableDataInRankOrder( std::ostream & tableOutput, + TableFormatter::CellLayoutRows const & rows, + PreparedTableLayout const & tableLayout, + TableTextMpiFormatter::Status & status ) const { // master rank does the output directly to the output, other ranks will have to send it through a string. std::ostringstream localStringStream; @@ -123,34 +125,67 @@ void TableTextMpiFormatter::toStream< TableData >( std::ostream & tableOutput, // m_isContributing (some ranks does not have any output to produce) !tableData.getCellsData().empty(), // m_hasContent - false, + false, // m_sepLine "" }; - if( m_sortingFunctor ) + if( true ) { - tableData.serialize( X ); - gatherTableDataOnRank0( tableData, X ); + stdVector< buffer_unit_type > buff = tableData.serialize(); + if( buff.empty()) + { + return; + } + { // Unpacking + buffer_unit_type const * startBuff = buff.data(); + size_t totalSize = 0; + bufferOps::Unpack( startBuff, totalSize ); + buffer_unit_type const * endRowsBuff = startBuff + totalSize - sizeof(size_t); + while( startBuff < endRowsBuff ) + { + size_t byteFromThisRow = 0; + bufferOps::Unpack( startBuff, byteFromThisRow ); + buffer_unit_type const * endRowBuff= startBuff + byteFromThisRow; + stdVector< TableData::CellData > row; + while( startBuff < endRowBuff ) + { + size_t cellSize = 0; + bufferOps::Unpack( startBuff, cellSize ); + + size_t cellFirstArgSize = 0; + bufferOps::Unpack( startBuff, cellFirstArgSize); + CellType cellType; + bufferOps::Unpack( startBuff, cellType ); + + string cellValue; + bufferOps::Unpack( startBuff, cellValue ); + row.push_back( {cellType, cellValue} ); + } + + } + + } + // gatherTableDataOnRank0( tableData, X ); if( status.m_isMasterRank ) { - tableData.sort( m_sortingFunctor ); + // tableData.sort( m_sortingFunctor ); TableTextFormatter::toStream( tableOutput, tableData ); } } else { // this version is faster (MPI cooperation) but can only be ordered by rank id - CellLayoutRows headerCellsLayout; + CellLayoutRows headerRows; CellLayoutRows dataRows; CellLayoutRows errorRows; size_t tableTotalWidth = 0; { // compute layout ColumnWidthModifier const columnWidthModifier = [this, status]( stdVector< size_t > & columnsWidth ) { - stretchColumnsByRanks( columnsWidth, status ); - }; + stretchColumnsByRanks( columnsWidth, status ); + }; initalizeTableGrids( m_tableLayout, tableData, - headerCellsLayout, dataRows, errorRows, + headerRows, dataRows, errorRows, tableTotalWidth, columnWidthModifier ); status.m_sepLine = string( tableTotalWidth, m_horizontalLine ); } From 78db217fde58b52eae58978c4b01f4dcac978e7d Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 20 Mar 2026 17:44:43 +0100 Subject: [PATCH 34/70] :construction: remove packing function and set custom function --- .../common/format/table/TableData.cpp | 49 +++++-------- .../common/format/table/TableData.hpp | 67 +++++++++++++++++- .../format/table/TableMpiComponents.cpp | 68 +++++++++++-------- 3 files changed, 121 insertions(+), 63 deletions(-) diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp index c9c9e7298de..a8a705ab430 100644 --- a/src/coreComponents/common/format/table/TableData.cpp +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -84,30 +84,22 @@ bool TableData::operator==( TableData const & comparingTable ) const return true; } -size_t TableData::CellData::serializeTo( buffer_unit_type * buffer ) const +void TableData::CellData::serialize( stdVector< buffer_unit_type > & out ) const { - buffer_unit_type * dummy = nullptr; - size_t sizeOftype = bufferOps::Pack< false >( dummy, type ); - string::size_type sizeOfString = bufferOps::Pack< false >( dummy, value ); + serializePrimitive( type, out ); + serializeString( value, out ); +} - if( buffer ) - { - auto it = buffer; - bufferOps::Pack< true >( buffer, sizeOftype ); - bufferOps::Pack< true >( buffer, type ); - bufferOps::Pack< true >( buffer, value ); - return buffer - it; - } - else - { - return sizeof(size_t) + sizeOftype + sizeOfString; - } + +size_t TableData::CellData::getSerializedSize() const +{ + return sizeOfField( type ) + sizeOfField( value ); } -stdVector< buffer_unit_type > TableData::serialize() const +void TableData::serialize( stdVector< buffer_unit_type > localTableData ) const { if( m_rows.empty()) - return {}; + return; size_t totalSize = 0; @@ -118,34 +110,29 @@ stdVector< buffer_unit_type > TableData::serialize() const size_t rowSize = 0; for( auto & cell : row ) { - rowSize += sizeof(size_t) + cell.serializeTo( nullptr ); + rowSize += sizeof(size_t) + cell.getSerializedSize(); } totalSize += sizeof(size_t) + rowSize; } - stdVector< buffer_unit_type > rowsPacked; - rowsPacked.resize( totalSize ); - buffer_unit_type * itRowsPacked = rowsPacked.data(); - bufferOps::Pack< true >( itRowsPacked, totalSize ); + localTableData.resize( totalSize ); + serializePrimitive( totalSize, localTableData ); for( auto & row : m_rows ) { size_t rowSize = 0; // pack row size; for( auto const & cell : row ) - rowSize += sizeof(size_t) + cell.serializeTo( nullptr ); - bufferOps::Pack< true >( itRowsPacked, rowSize ); + rowSize += sizeof(size_t) + cell.getSerializedSize(); + serializePrimitive( rowSize, localTableData ); // pack cells for( auto const & cell : row ) { - size_t cellSize = cell.serializeTo( nullptr ); - bufferOps::Pack< true >( itRowsPacked, cellSize ); - cell.serializeTo( itRowsPacked ); - itRowsPacked += cellSize; + size_t cellSize = cell.getSerializedSize(); + serializePrimitive( cellSize, localTableData ); + cell.serialize( localTableData ); } } - - return rowsPacked; } diff --git a/src/coreComponents/common/format/table/TableData.hpp b/src/coreComponents/common/format/table/TableData.hpp index 1f74c0abe5b..0f238305eef 100644 --- a/src/coreComponents/common/format/table/TableData.hpp +++ b/src/coreComponents/common/format/table/TableData.hpp @@ -20,6 +20,7 @@ #ifndef GEOS_COMMON_FORMAT_TABLE_TABLEDATA_HPP #define GEOS_COMMON_FORMAT_TABLE_TABLEDATA_HPP +#include "common/StdContainerWrappers.hpp" #include "common/Units.hpp" #include "common/DataTypes.hpp" #include "common/format/Format.hpp" @@ -72,12 +73,74 @@ class TableData /// The cell value string value; - size_t serializeTo( buffer_unit_type * buffer ) const; + size_t getSerializedSize() const; + + void serialize( stdVector< buffer_unit_type > & out ) const; + }; + + /** + * @tparam T The trivial type + * @return Returns the size occupied by a trivial type in memory. + */ + template< typename T > + static unsigned long sizeOfField( T ) + { return sizeof(T); } + + /** + * @brief Returns the size of a string (header size + content). + * @param str The target string + * @return Size in bytes. + */ + static unsigned long sizeOfField( string_view str ) + { return sizeof(string::size_type) + str.size(); } + + template< typename T > + static void serializePrimitive ( T const data, stdVector< buffer_unit_type > & out ) + { + buffer_unit_type const * begin = reinterpret_cast< buffer_unit_type const * >( &data ); + buffer_unit_type const * end = begin + sizeof(data); + out.insert( out.end(), begin, end ); }; + + static void serializeString ( string const & data, stdVector< buffer_unit_type > & out ) + { + serializePrimitive( data.size(), out ); + auto * begin = data.data(); + auto * end = begin + data.size(); + out.insert( out.end(), begin, end ); + }; + + template< typename T > + static void deserializeField( T & data, buffer_unit_type const * & ptr, buffer_unit_type const * end ) + { + static_assert( std::is_trivially_copyable_v< T > ); + if( ptr + sizeof(T)> end ) throw std::runtime_error( "Buffer truncated" ); + memcpy( &data, ptr, sizeof(T) ); + ptr += sizeof(T); + } + + /** @brief Reads a string value from the buffer and advances the pointer. + * @param data Destination variable. + * @param ptr Current read pointer (advanced by sizeof(string)). + * @param end Safety: maximum buffer limit. + */ + static void deserializeField( string & str, buffer_unit_type const * & ptr, buffer_unit_type const * end ) + { + string::size_type strSize = 0; + deserializeField( strSize, ptr, end ); + if( std::distance( ptr, end ) < (long) strSize ) + { + throw std::runtime_error( "Buffer truncated reading string" ); + } + str.assign( ptr, ptr + strSize ); + ptr += str.size(); + } + + /// Alias for table data rows with cells values using DataRows = stdVector< stdVector< CellData > >; - stdVector< buffer_unit_type > serialize() const; + void serialize( stdVector< buffer_unit_type > localTableData ) const; /** * @brief Add a row to the table. diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index 34e6d1b7836..eed3eb1c230 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -132,41 +132,49 @@ void TableTextMpiFormatter::toStream< TableData >( std::ostream & tableOutput, if( true ) { - stdVector< buffer_unit_type > buff = tableData.serialize(); - if( buff.empty()) - { - return; - } - { // Unpacking - buffer_unit_type const * startBuff = buff.data(); - size_t totalSize = 0; - bufferOps::Unpack( startBuff, totalSize ); - buffer_unit_type const * endRowsBuff = startBuff + totalSize - sizeof(size_t); - while( startBuff < endRowsBuff ) - { - size_t byteFromThisRow = 0; - bufferOps::Unpack( startBuff, byteFromThisRow ); - buffer_unit_type const * endRowBuff= startBuff + byteFromThisRow; - stdVector< TableData::CellData > row; - while( startBuff < endRowBuff ) - { - size_t cellSize = 0; - bufferOps::Unpack( startBuff, cellSize ); + stdVector< buffer_unit_type > localTableData( 0 ); + tableData.serialize( localTableData ); - size_t cellFirstArgSize = 0; - bufferOps::Unpack( startBuff, cellFirstArgSize); - CellType cellType; - bufferOps::Unpack( startBuff, cellType ); + auto [globalLogRecords, counts, offsets] = + gatherTableDataOnRank0( tableData, X ); - string cellValue; - bufferOps::Unpack( startBuff, cellValue ); - row.push_back( {cellType, cellValue} ); + { //Deserialisation + if( !localTableData.empty()) + { + for( size_t idxRank = 0; idxRank < (size_t)MpiWrapper::commSize(); ++idxRank ) + { + buffer_unit_type const * startBuff = localTableData.data(); + integer byteFromThisRank = counts[idxRank]; + buffer_unit_type const * endBuff= startBuff + byteFromThisRank; + + TableData::deserializeField( startBuff, startBuff, endBuff ); + buffer_unit_type const * endRowsBuff = startBuff + byteFromThisRank - sizeof(size_t); + while( startBuff < endRowsBuff ) + { + size_t byteFromThisRow = 0; + TableData::deserializeField( startBuff, byteFromThisRow, endBuff ); + buffer_unit_type const * endRowBuff= startBuff + byteFromThisRow; + stdVector< TableData::CellData > row; + while( startBuff < endRowBuff ) + { + size_t cellSize = 0; + TableData::deserializeField( startBuff, cellSize, endBuff ); + + size_t cellFirstArgSize = 0; + TableData::deserializeField( startBuff, cellFirstArgSize, endBuff ); + CellType cellType; + TableData::deserializeField( startBuff, cellType, endBuff ); + + string cellValue; + TableData::deserializeField( startBuff, cellValue, endBuff ); + row.push_back( {cellType, cellValue} ); + } + } } - } - } - // gatherTableDataOnRank0( tableData, X ); + + if( status.m_isMasterRank ) { From 6f3c1996c0ed5521e7dc6e6eaf50feab03b6f3cc Mon Sep 17 00:00:00 2001 From: arng40 Date: Wed, 25 Mar 2026 16:16:19 +0100 Subject: [PATCH 35/70] :art: add tableData serialization --- .../common/format/table/TableData.cpp | 45 ++++++++++--------- .../common/format/table/TableData.hpp | 10 +++-- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp index a8a705ab430..5311822def2 100644 --- a/src/coreComponents/common/format/table/TableData.cpp +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -96,41 +96,46 @@ size_t TableData::CellData::getSerializedSize() const return sizeOfField( type ) + sizeOfField( value ); } -void TableData::serialize( stdVector< buffer_unit_type > localTableData ) const +size_t TableData::getSerializedSize() const { - if( m_rows.empty()) - return; + size_t totalSize =0; - size_t totalSize = 0; + if( m_rows.empty()) + return totalSize; - // pre-calculate total size - totalSize += sizeof(size_t); for( auto & row : m_rows ) { size_t rowSize = 0; for( auto & cell : row ) { - rowSize += sizeof(size_t) + cell.getSerializedSize(); + rowSize += cell.getSerializedSize(); } totalSize += sizeof(size_t) + rowSize; } + return totalSize; +} + +void TableData::serialize( stdVector< buffer_unit_type > & serializedTableData ) const +{ + if( m_rows.empty()) + return; - localTableData.resize( totalSize ); - serializePrimitive( totalSize, localTableData ); for( auto & row : m_rows ) { - size_t rowSize = 0; - // pack row size; - for( auto const & cell : row ) - rowSize += sizeof(size_t) + cell.getSerializedSize(); - serializePrimitive( rowSize, localTableData ); + { // pack row size; + size_t rowSize = 0; + for( auto const & cell : row ) + rowSize += cell.getSerializedSize(); + serializePrimitive( rowSize, serializedTableData ); + } - // pack cells - for( auto const & cell : row ) - { - size_t cellSize = cell.getSerializedSize(); - serializePrimitive( cellSize, localTableData ); - cell.serialize( localTableData ); + { // pack cells + for( auto const & cell : row ) + { + // size_t cellSize = cell.getSerializedSize(); + // serializePrimitive( cellSize, serializedTableData ); + cell.serialize( serializedTableData ); + } } } } diff --git a/src/coreComponents/common/format/table/TableData.hpp b/src/coreComponents/common/format/table/TableData.hpp index 0f238305eef..2b262a6c3e5 100644 --- a/src/coreComponents/common/format/table/TableData.hpp +++ b/src/coreComponents/common/format/table/TableData.hpp @@ -78,6 +78,8 @@ class TableData void serialize( stdVector< buffer_unit_type > & out ) const; }; + size_t getSerializedSize() const; + /** * @tparam T The trivial type * @return Returns the size occupied by a trivial type in memory. @@ -91,7 +93,7 @@ class TableData * @param str The target string * @return Size in bytes. */ - static unsigned long sizeOfField( string_view str ) + static unsigned long sizeOfField( string const & str ) { return sizeof(string::size_type) + str.size(); } template< typename T > @@ -100,7 +102,7 @@ class TableData buffer_unit_type const * begin = reinterpret_cast< buffer_unit_type const * >( &data ); buffer_unit_type const * end = begin + sizeof(data); out.insert( out.end(), begin, end ); - }; + } static void serializeString ( string const & data, stdVector< buffer_unit_type > & out ) { @@ -108,7 +110,7 @@ class TableData auto * begin = data.data(); auto * end = begin + data.size(); out.insert( out.end(), begin, end ); - }; + } template< typename T > static void deserializeField( T & data, buffer_unit_type const * & ptr, buffer_unit_type const * end ) @@ -140,7 +142,7 @@ class TableData /// Alias for table data rows with cells values using DataRows = stdVector< stdVector< CellData > >; - void serialize( stdVector< buffer_unit_type > localTableData ) const; + void serialize( stdVector< buffer_unit_type > & serializedTableData ) const; /** * @brief Add a row to the table. From bd75852fe2f1ffbe0cfe90b9282c93f08fc9a31a Mon Sep 17 00:00:00 2001 From: arng40 Date: Wed, 25 Mar 2026 16:17:08 +0100 Subject: [PATCH 36/70] :hammer: update tableData gathering --- .../format/table/TableMpiComponents.cpp | 98 ++++++++++--------- .../format/table/TableMpiComponents.hpp | 8 +- 2 files changed, 61 insertions(+), 45 deletions(-) diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index eed3eb1c230..47d15c835b8 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -115,6 +115,58 @@ void TableTextMpiFormatter::gatherAndOutputTableDataInRankOrder( std::ostream & } } +TableData TableTextMpiFormatter::gatherTableDataRank0( TableData const & localTableData ) const +{ + stdVector< buffer_unit_type > serializedTableData( 0 ); + size_t totalSize = 0; + + { // allocation + totalSize = localTableData.getSerializedSize(); + serializedTableData.reserve( totalSize ); + } + + { // Packing + if( totalSize > 0 ) + { + // std::cout << "Rank["<< MpiWrapper::commRank()<<"] total size "<< totalSize << std::endl; + localTableData.serialize( serializedTableData ); + } + } + auto [globalLogRecords, counts, offsets] = + MpiWrapper::gatherBufferRank0< stdVector< buffer_unit_type > >( serializedTableData ); + + + { // Unpacking + TableData tableDataGathered; + if( MpiWrapper::commRank() == 0 ) + { + buffer_unit_type const * startBuff = globalLogRecords.data(); + for( size_t idxRank = 0; idxRank < (size_t)MpiWrapper::commSize(); ++idxRank ) + { + integer byteFromThisRank = counts[idxRank]; + buffer_unit_type const * endRowsBuff = startBuff + byteFromThisRank; + while( startBuff < endRowsBuff ) + { + size_t byteFromThisRow = 0; + TableData::deserializeField( byteFromThisRow, startBuff, endRowsBuff ); + buffer_unit_type const * endRowBuff= startBuff + byteFromThisRow; + stdVector< TableData::CellData > row; + while( startBuff < endRowBuff ) + { + CellType cellType; + TableData::deserializeField( cellType, startBuff, endRowBuff ); + string cellValue; + TableData::deserializeField( cellValue, startBuff, endRowBuff ); + row.push_back( {cellType, cellValue} ); + } + tableDataGathered.addRow( row ); + } + } + } + return tableDataGathered; + } +} + template<> void TableTextMpiFormatter::toStream< TableData >( std::ostream & tableOutput, TableData const & tableData ) const @@ -132,54 +184,12 @@ void TableTextMpiFormatter::toStream< TableData >( std::ostream & tableOutput, if( true ) { - stdVector< buffer_unit_type > localTableData( 0 ); - tableData.serialize( localTableData ); - - auto [globalLogRecords, counts, offsets] = - gatherTableDataOnRank0( tableData, X ); - - { //Deserialisation - if( !localTableData.empty()) - { - for( size_t idxRank = 0; idxRank < (size_t)MpiWrapper::commSize(); ++idxRank ) - { - buffer_unit_type const * startBuff = localTableData.data(); - integer byteFromThisRank = counts[idxRank]; - buffer_unit_type const * endBuff= startBuff + byteFromThisRank; - - TableData::deserializeField( startBuff, startBuff, endBuff ); - buffer_unit_type const * endRowsBuff = startBuff + byteFromThisRank - sizeof(size_t); - while( startBuff < endRowsBuff ) - { - size_t byteFromThisRow = 0; - TableData::deserializeField( startBuff, byteFromThisRow, endBuff ); - buffer_unit_type const * endRowBuff= startBuff + byteFromThisRow; - stdVector< TableData::CellData > row; - while( startBuff < endRowBuff ) - { - size_t cellSize = 0; - TableData::deserializeField( startBuff, cellSize, endBuff ); - - size_t cellFirstArgSize = 0; - TableData::deserializeField( startBuff, cellFirstArgSize, endBuff ); - CellType cellType; - TableData::deserializeField( startBuff, cellType, endBuff ); - - string cellValue; - TableData::deserializeField( startBuff, cellValue, endBuff ); - row.push_back( {cellType, cellValue} ); - } - } - } - } - } - - + TableData tableDataGathered = gatherTableDataRank0( tableData ); if( status.m_isMasterRank ) { // tableData.sort( m_sortingFunctor ); - TableTextFormatter::toStream( tableOutput, tableData ); + TableTextFormatter::toStream( tableOutput, tableDataGathered ); } } else diff --git a/src/coreComponents/common/format/table/TableMpiComponents.hpp b/src/coreComponents/common/format/table/TableMpiComponents.hpp index 5a8b26d770b..09a9fca8701 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.hpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.hpp @@ -62,7 +62,7 @@ class TableTextMpiFormatter : public TableTextFormatter * @param mpiLayout MPI-specific layout information (default is having contiguous ranks data). */ TableTextMpiFormatter( TableLayout const & tableLayout, - TableMpiLayout mpiLayout = TableMpiLayout() ); + TableMpiLayout mpiLayout = TableMpiLayout() ); /** * @brief Convert a data source to a table string. @@ -117,6 +117,12 @@ class TableTextMpiFormatter : public TableTextFormatter */ stdVector< TableData::CellData > parseStringRow( string_view rowString ) const; + /** + * @brief + * @param localTableData + */ + TableData gatherTableDataRank0( TableData const & localTableData ) const; + /** * @brief Gather data cell rows across all MPI ranks and output them to rank 0 in rank order. From d47c1870f3df9ef4a9f67ed992d50b1b485cac83 Mon Sep 17 00:00:00 2001 From: arng40 Date: Wed, 25 Mar 2026 16:18:08 +0100 Subject: [PATCH 37/70] :hammer: update reservoirElementGlobalIndex default value --- src/coreComponents/mesh/ElementRegionManager.cpp | 3 +-- src/coreComponents/mesh/PerforationFields.hpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index e1828b5fe00..cdc2344f32e 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -250,10 +250,9 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM arrayView1d< globalIndex const > const globalIperf = wellSubRegionPerforationData->localToGlobalMap(); array1d< integer > localCoords; - if( cellId != 0 ) + if( cellId != -1 ) { auto const & meshElems = wellSubRegionPerforationData->getMeshElements(); - localIndex const targetRegionIndex = meshElems.m_toElementRegion[iperfLocal]; localIndex const targetSubRegionIndex = meshElems.m_toElementSubRegion[iperfLocal]; diff --git a/src/coreComponents/mesh/PerforationFields.hpp b/src/coreComponents/mesh/PerforationFields.hpp index d2490470bbc..b13297d6fa1 100644 --- a/src/coreComponents/mesh/PerforationFields.hpp +++ b/src/coreComponents/mesh/PerforationFields.hpp @@ -61,7 +61,7 @@ DECLARE_FIELD( reservoirElementIndex, DECLARE_FIELD( reservoirElementGlobalIndex, "reservoirElementGlobalIndex", array1d< globalIndex >, - 0, + -1, NOPLOT, WRITE_AND_READ, "For each perforation, global element index of the perforated element" ); From 642c3b54ca17f190de27f0620d0cc6580e058abf Mon Sep 17 00:00:00 2001 From: arng40 Date: Wed, 25 Mar 2026 16:19:05 +0100 Subject: [PATCH 38/70] :fire: remove log --- .../common/format/table/unitTests/testMpiTable.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp index 11a251c8c5c..2ff782c8203 100644 --- a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp +++ b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp @@ -205,7 +205,6 @@ TEST( testMpiTables, testSortingMethod ) formatter.toStream( oss, data ); if( rankId == 0 ) { - std::cout << "ma boula " ""<< oss.str()< Date: Wed, 25 Mar 2026 17:01:56 +0100 Subject: [PATCH 39/70] :sparkles: add sorted function to tableData --- .../common/format/table/TableData.cpp | 2 +- .../common/format/table/TableData.hpp | 13 ++++++------- .../common/format/table/TableMpiComponents.cpp | 3 +-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp index 5311822def2..7ae3c28f787 100644 --- a/src/coreComponents/common/format/table/TableData.cpp +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -259,7 +259,7 @@ TableData2D::TableDataHolder TableData2D::buildTableData( string_view targetUnit return tableData1D; } -bool tabledatasorting::positiveNumberStringComp( string_view s1, string_view s2 ) +bool tableDataSorting::positiveNumberStringComp( string_view s1, string_view s2 ) { auto split = []( string_view s, string & intPart, string & decPart ) { diff --git a/src/coreComponents/common/format/table/TableData.hpp b/src/coreComponents/common/format/table/TableData.hpp index 2b262a6c3e5..eae7c841336 100644 --- a/src/coreComponents/common/format/table/TableData.hpp +++ b/src/coreComponents/common/format/table/TableData.hpp @@ -208,12 +208,11 @@ class TableData TableErrorListing & getErrorsList() { return *m_errors; } - /** - * @brief Gather all the TableData rows to the rank 0 - * @param func The callable comparison function object to sort TableData rows, by default none - */ - template< typename SortingFunc = std::nullptr_t > - void gatherRowsRank0( SortingFunc && func ); + template< typename SortingFunc > + void sort( SortingFunc sortingFunctor ) + { + std::sort( m_rows.begin(), m_rows.end(), sortingFunctor ); + } private: /// @brief vector containing all rows with cell values @@ -367,7 +366,7 @@ void TableData2D::addCell( real64 const rowValue, real64 const columnValue, T co } // Custom Comp function; -namespace tabledatasorting +namespace tableDataSorting { /** * @brief Compare two string number string by in ascending numerical order. diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index 47d15c835b8..0b20d7f9569 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -128,7 +128,6 @@ TableData TableTextMpiFormatter::gatherTableDataRank0( TableData const & localTa { // Packing if( totalSize > 0 ) { - // std::cout << "Rank["<< MpiWrapper::commRank()<<"] total size "<< totalSize << std::endl; localTableData.serialize( serializedTableData ); } } @@ -188,7 +187,7 @@ void TableTextMpiFormatter::toStream< TableData >( std::ostream & tableOutput, if( status.m_isMasterRank ) { - // tableData.sort( m_sortingFunctor ); + tableDataGathered.sort( *m_sortingFunctor ); TableTextFormatter::toStream( tableOutput, tableDataGathered ); } } From 341ad11fd05efc63d24c59a076de1f68a532cf51 Mon Sep 17 00:00:00 2001 From: arng40 Date: Wed, 25 Mar 2026 17:02:27 +0100 Subject: [PATCH 40/70] :label: namespace renaming --- .../format/table/unitTests/testMpiTable.cpp | 54 +++++++++---------- .../mesh/ElementRegionManager.cpp | 2 +- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp index 2ff782c8203..76a1109d7c8 100644 --- a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp +++ b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp @@ -198,7 +198,7 @@ TEST( testMpiTables, testSortingMethod ) TableTextMpiFormatter formatter = TableTextMpiFormatter( layout, mpiLayout ); formatter.setSortingFunc( []( std::vector< TableData::CellData > const & row1, std::vector< TableData::CellData > const & row2 ) { - return tabledatasorting::positiveNumberStringComp( row1[0].value, row2[0].value ); + return tableDataSorting::positiveNumberStringComp( row1[0].value, row2[0].value ); } ); std::ostringstream oss; @@ -214,40 +214,40 @@ TEST( testMpiTables, testSortingMethod ) TEST( testMpiTables, testCompPositiveValueTable ) { - EXPECT_FALSE ( tabledatasorting::positiveNumberStringComp( "123", "45" )); - EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "45", "123" )); - EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "42", "42" )); - EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "0", "0" )); - EXPECT_FALSE ( tabledatasorting::positiveNumberStringComp( "9", "1" )); - EXPECT_FALSE ( tabledatasorting::positiveNumberStringComp( "10000000", "9999999" )); - EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "9999999", "10000000" )); + EXPECT_FALSE ( tableDataSorting::positiveNumberStringComp( "123", "45" )); + EXPECT_TRUE( tableDataSorting::positiveNumberStringComp( "45", "123" )); + EXPECT_FALSE( tableDataSorting::positiveNumberStringComp( "42", "42" )); + EXPECT_FALSE( tableDataSorting::positiveNumberStringComp( "0", "0" )); + EXPECT_FALSE ( tableDataSorting::positiveNumberStringComp( "9", "1" )); + EXPECT_FALSE ( tableDataSorting::positiveNumberStringComp( "10000000", "9999999" )); + EXPECT_TRUE( tableDataSorting::positiveNumberStringComp( "9999999", "10000000" )); - EXPECT_FALSE ( tabledatasorting::positiveNumberStringComp( "10.5", "9.99" )); - EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "9.99", "10.5" )); + EXPECT_FALSE ( tableDataSorting::positiveNumberStringComp( "10.5", "9.99" )); + EXPECT_TRUE( tableDataSorting::positiveNumberStringComp( "9.99", "10.5" )); - EXPECT_FALSE ( tabledatasorting::positiveNumberStringComp( "10", "9.999" )); - EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "9.999", "10" )); + EXPECT_FALSE ( tableDataSorting::positiveNumberStringComp( "10", "9.999" )); + EXPECT_TRUE( tableDataSorting::positiveNumberStringComp( "9.999", "10" )); - EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "1.2", "1.9" )); - EXPECT_FALSE ( tabledatasorting::positiveNumberStringComp( "1.9", "1.2" )); + EXPECT_TRUE( tableDataSorting::positiveNumberStringComp( "1.2", "1.9" )); + EXPECT_FALSE ( tableDataSorting::positiveNumberStringComp( "1.9", "1.2" )); - EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1.5", "1.50" )); - EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1.50", "1.5" )); - EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1.500", "1.5" )); - EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1.5", "1.500" )); + EXPECT_FALSE( tableDataSorting::positiveNumberStringComp( "1.5", "1.50" )); + EXPECT_FALSE( tableDataSorting::positiveNumberStringComp( "1.50", "1.5" )); + EXPECT_FALSE( tableDataSorting::positiveNumberStringComp( "1.500", "1.5" )); + EXPECT_FALSE( tableDataSorting::positiveNumberStringComp( "1.5", "1.500" )); - EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "1.51", "1.510" )); - EXPECT_FALSE ( tabledatasorting::positiveNumberStringComp( "1.51", "1.509" )); + EXPECT_FALSE( tableDataSorting::positiveNumberStringComp( "1.51", "1.510" )); + EXPECT_FALSE ( tableDataSorting::positiveNumberStringComp( "1.51", "1.509" )); - EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "3.14", "3.14" )); - EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "0.001", "0.001" )); - EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "100.0", "100.0" )); + EXPECT_FALSE( tableDataSorting::positiveNumberStringComp( "3.14", "3.14" )); + EXPECT_FALSE( tableDataSorting::positiveNumberStringComp( "0.001", "0.001" )); + EXPECT_FALSE( tableDataSorting::positiveNumberStringComp( "100.0", "100.0" )); - EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "5", "5.0" )); - EXPECT_FALSE( tabledatasorting::positiveNumberStringComp( "5.0", "5" )); + EXPECT_FALSE( tableDataSorting::positiveNumberStringComp( "5", "5.0" )); + EXPECT_FALSE( tableDataSorting::positiveNumberStringComp( "5.0", "5" )); - EXPECT_FALSE ( tabledatasorting::positiveNumberStringComp( "5595", "5155" )); - EXPECT_TRUE( tabledatasorting::positiveNumberStringComp( "5155", "5595" )); + EXPECT_FALSE ( tableDataSorting::positiveNumberStringComp( "5595", "5155" )); + EXPECT_TRUE( tableDataSorting::positiveNumberStringComp( "5155", "5595" )); } diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index cdc2344f32e..b56acff916e 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -275,7 +275,7 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM formatter.setSortingFunc( []( std::vector< TableData::CellData > const & row1, std::vector< TableData::CellData > const & row2 ) { - return tabledatasorting::positiveNumberStringComp( row1[1].value, row2[1].value ); + return tableDataSorting::positiveNumberStringComp( row1[1].value, row2[1].value ); } ); std::ostringstream outputStream; From ff68563a92b519b937fdbab1d3096e6250415f39 Mon Sep 17 00:00:00 2001 From: arng40 Date: Thu, 26 Mar 2026 10:18:39 +0100 Subject: [PATCH 41/70] :lock: add control for table --- .../mesh/ElementRegionManager.cpp | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index b56acff916e..d92cae74cdb 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -234,12 +234,6 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM forElementRegions< WellElementRegion >( [&]( WellElementRegion const & wellRegion ){ WellElementSubRegion const & wellSubRegion = wellRegion.getSubRegion< WellElementSubRegion >( wellRegion.getSubRegionName() ); - TableLayout const layoutPerforation ( GEOS_FMT( "Well '{}' Perforation Table", - wellRegion.getWellGeneratorName()), - { - "Perforation", "Well element", "Coordinates", - "Cell region", "Cell sub-region", "Cell ID", "Rank" - } ); PerforationData const * wellSubRegionPerforationData= wellSubRegion.getPerforationData(); arrayView2d< const real64 > wsrPerfLocation = wellSubRegionPerforationData->getLocation(); @@ -268,23 +262,32 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM region.getName(), subRegion.getName(), cellId, rankId ); } } + if( !localPerfoData.getCellsData().empty()) + { + TableLayout const layoutPerforation ( GEOS_FMT( "Well '{}' Perforation Table", + wellRegion.getWellGeneratorName()), + { + "Perforation", "Well element", "Coordinates", + "Cell region", "Cell sub-region", "Cell ID", "Rank" + } ); - TableMpiLayout mpiLayout; - TableTextMpiFormatter formatter = TableTextMpiFormatter( layoutPerforation, mpiLayout ); + TableMpiLayout mpiLayout; + TableTextMpiFormatter formatter = TableTextMpiFormatter( layoutPerforation, mpiLayout ); - formatter.setSortingFunc( - []( std::vector< TableData::CellData > const & row1, - std::vector< TableData::CellData > const & row2 ) { - return tableDataSorting::positiveNumberStringComp( row1[1].value, row2[1].value ); - } ); + formatter.setSortingFunc( + []( std::vector< TableData::CellData > const & row1, + std::vector< TableData::CellData > const & row2 ) { + return tableDataSorting::positiveNumberStringComp( row1[1].value, row2[1].value ); + } ); - std::ostringstream outputStream; - formatter.toStream( outputStream, localPerfoData ); + std::ostringstream outputStream; + formatter.toStream( outputStream, localPerfoData ); - if( rankId == 0 ) - { - TableTextFormatter const globalFormatter( layoutPerforation ); - GEOS_LOG( outputStream.str()); + if( rankId == 0 ) + { + TableTextFormatter const globalFormatter( layoutPerforation ); + GEOS_LOG( outputStream.str()); + } } } ); From ccfbccf927ed34312f2611e96346aee1a300ebe6 Mon Sep 17 00:00:00 2001 From: arng40 Date: Thu, 26 Mar 2026 10:20:07 +0100 Subject: [PATCH 42/70] :hammer: fix testMPI after merge conflict --- .../format/table/TableMpiComponents.cpp | 2 +- .../format/table/unitTests/testMpiTable.cpp | 110 +++++++++--------- 2 files changed, 55 insertions(+), 57 deletions(-) diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index 0b20d7f9569..66aa63f6e79 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -181,7 +181,7 @@ void TableTextMpiFormatter::toStream< TableData >( std::ostream & tableOutput, "" }; - if( true ) + if( m_sortingFunctor ) { TableData tableDataGathered = gatherTableDataRank0( tableData ); diff --git a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp index 76a1109d7c8..8b252abdc89 100644 --- a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp +++ b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp @@ -104,39 +104,38 @@ TEST( testMpiTables, testDifferentRankData ) { int const rankId = MpiWrapper::commRank(); int const nbRanks = MpiWrapper::commSize(); - if( nbRanks > 1 ) - { - ASSERT_EQ( nbRanks, 4 ); + ASSERT_EQ( nbRanks, 4 ) << "This unit test cases are designed for exactly 4 ranks to check row ordering consistency."; - TableLayout const layout = TableLayout(). - setTitle( "Summary of negative pressure elements" ). - addColumns( { "Global Id", "pressure [Pa]" } ). - setDefaultHeaderAlignment( TableLayout::Alignment::left ); - TableData data; - auto const & rankTestData = testCase.m_ranksValues[rankId]; - TableMpiLayout mpiLayout; - mpiLayout.m_separatorBetweenRanks = true; - if( !rankTestData.empty() ) - { - mpiLayout.m_rankTitle = GEOS_FMT( "Rank {}, {} values", rankId, rankTestData.size() ); - for( auto const & [id, value] : rankTestData ) - { - data.addRow( id, value ); - } - } + TableLayout const layout = TableLayout(). + setTitle( "Summary of negative pressure elements" ). + addColumns( { "Global Id", "pressure [Pa]" } ). + setDefaultHeaderAlignment( TableLayout::Alignment::left ); + TableData data; + auto const & rankTestData = testCase.m_ranksValues[rankId]; - TableTextMpiFormatter const formatter = TableTextMpiFormatter( layout, mpiLayout ); - std::ostringstream oss; - formatter.toStream( oss, data ); - if( rankId == 0 ) + TableMpiLayout mpiLayout; + mpiLayout.m_separatorBetweenRanks = true; + + if( !rankTestData.empty() ) + { + mpiLayout.m_rankTitle = GEOS_FMT( "Rank {}, {} values", rankId, rankTestData.size() ); + for( auto const & [id, value] : rankTestData ) { - EXPECT_STREQ( testCase.m_expectedResult.data(), - oss.str().data() ); + data.addRow( id, value ); } } + TableTextMpiFormatter const formatter = TableTextMpiFormatter( layout, mpiLayout ); + std::ostringstream oss; + formatter.toStream( oss, data ); + if( rankId == 0 ) + { + EXPECT_STREQ( testCase.m_expectedResult.data(), + oss.str().data() ); + } } + } TEST( testMpiTables, testSortingMethod ) @@ -150,10 +149,10 @@ TEST( testMpiTables, testSortingMethod ) TestCase const testCase = { { // m_ranksValues: in this test, rank 2 has no value - { {1, 0.502} }, { {2, 0.624}, {3, 0.791} }, - {}, + { {1, 0.502} }, { {4, 0.243}, {5, 0.804}, {6, 0.302} }, + {}, }, "\n" // m_expectedResult "-------------------------------------------\n" @@ -172,44 +171,43 @@ TEST( testMpiTables, testSortingMethod ) int const rankId = MpiWrapper::commRank(); int const nbRanks = MpiWrapper::commSize(); - if( nbRanks > 1 ) - { - ASSERT_EQ( nbRanks, 4 ); + ASSERT_EQ( nbRanks, 4 ) << "This unit test cases are designed for exactly 4 ranks to check row ordering consistency."; - TableLayout const layout = TableLayout(). - setTitle( "Summary of negative pressure elements" ). - addColumns( { "Global Id", "pressure [Pa]" } ). - setDefaultHeaderAlignment( TableLayout::Alignment::left ); - TableData data; - auto const & rankTestData = testCase.m_ranksValues[rankId]; - TableMpiLayout mpiLayout; - mpiLayout.m_separatorBetweenRanks = true; + TableLayout const layout = TableLayout(). + setTitle( "Summary of negative pressure elements" ). + addColumns( { "Global Id", "pressure [Pa]" } ). + setDefaultHeaderAlignment( TableLayout::Alignment::left ); + TableData data; + auto const & rankTestData = testCase.m_ranksValues[rankId]; - if( !rankTestData.empty() ) + TableMpiLayout mpiLayout; + mpiLayout.m_separatorBetweenRanks = true; + + if( !rankTestData.empty() ) + { + mpiLayout.m_rankTitle = GEOS_FMT( "Rank {}, {} values", rankId, rankTestData.size() ); + for( auto const & [id, value] : rankTestData ) { - mpiLayout.m_rankTitle = GEOS_FMT( "Rank {}, {} values", rankId, rankTestData.size() ); - for( auto const & [id, value] : rankTestData ) - { - data.addRow( id, value ); - } + data.addRow( id, value ); } + } - TableTextMpiFormatter formatter = TableTextMpiFormatter( layout, mpiLayout ); - formatter.setSortingFunc( []( std::vector< TableData::CellData > const & row1, - std::vector< TableData::CellData > const & row2 ) { - return tableDataSorting::positiveNumberStringComp( row1[0].value, row2[0].value ); - } ); + TableTextMpiFormatter formatter = TableTextMpiFormatter( layout, mpiLayout ); + formatter.setSortingFunc( []( std::vector< TableData::CellData > const & row1, + std::vector< TableData::CellData > const & row2 ) { + return tableDataSorting::positiveNumberStringComp( row1[0].value, row2[0].value ); + } ); - std::ostringstream oss; - formatter.toStream( oss, data ); - if( rankId == 0 ) - { - EXPECT_STREQ( testCase.m_expectedResult.data(), - oss.str().data() ); - } + std::ostringstream oss; + formatter.toStream( oss, data ); + if( rankId == 0 ) + { + EXPECT_STREQ( testCase.m_expectedResult.data(), + oss.str().data() ); } + } TEST( testMpiTables, testCompPositiveValueTable ) From 52cc123770b51b41317efe9bb56996ec8e2110d6 Mon Sep 17 00:00:00 2001 From: arng40 Date: Thu, 26 Mar 2026 11:18:37 +0100 Subject: [PATCH 43/70] :bug: Use MPI for tableData control --- .../mesh/ElementRegionManager.cpp | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index d92cae74cdb..ed6984a3008 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -13,12 +13,14 @@ * ------------------------------------------------------------------------------------------------------------ */ +#include #include #include #include "ElementRegionManager.hpp" #include "common/DataLayouts.hpp" +#include "common/MpiWrapper.hpp" #include "common/TimingMacros.hpp" #include "common/format/table/TableMpiComponents.hpp" #include "mesh/WellElementSubRegion.hpp" @@ -181,6 +183,35 @@ void ElementRegionManager::generateMesh( CellBlockManagerABC const & cellBlockMa } ); } +integer detectPerforationsAcrossRanks( TableData const & localPerfoData ) +{ + stdVector< integer > counts; + integer const numRanks = MpiWrapper::commSize(); + integer const numLocalValues = static_cast< integer >(localPerfoData.getCellsData().size()); + + if( MpiWrapper::commRank() == 0 ) + { + counts.resize( numRanks ); + } + + MpiWrapper::gather( &numLocalValues, 1, counts.data(), 1, 0 ); + + auto it = std::find_if( counts.begin(), counts.end(), []( integer const & rankCount ) + { + return rankCount != 0; + } ); + + integer perfoDetected = false; + if( MpiWrapper::commRank() == 0 && it != counts.end()) + { + perfoDetected = true; + } + + MpiWrapper::bcast( &perfoDetected, 1, 0 ); + + return perfoDetected; +} + void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockManager, MeshLevel & meshLevel ) { @@ -262,7 +293,10 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM region.getName(), subRegion.getName(), cellId, rankId ); } } - if( !localPerfoData.getCellsData().empty()) + + integer perfoDetected = detectPerforationsAcrossRanks( localPerfoData ); + + if( perfoDetected ) { TableLayout const layoutPerforation ( GEOS_FMT( "Well '{}' Perforation Table", wellRegion.getWellGeneratorName()), From 1eb61c0dcdde49c540022041a092a57c8573ad1c Mon Sep 17 00:00:00 2001 From: arng40 Date: Thu, 26 Mar 2026 11:19:22 +0100 Subject: [PATCH 44/70] :rewind: revert outputLines --- .../common/format/table/TableFormatter.cpp | 97 ++++++++----------- .../common/format/table/TableFormatter.hpp | 14 --- 2 files changed, 43 insertions(+), 68 deletions(-) diff --git a/src/coreComponents/common/format/table/TableFormatter.cpp b/src/coreComponents/common/format/table/TableFormatter.cpp index 81df90d8e6a..7b198202fd9 100644 --- a/src/coreComponents/common/format/table/TableFormatter.cpp +++ b/src/coreComponents/common/format/table/TableFormatter.cpp @@ -805,72 +805,61 @@ void TableTextFormatter::formatCell( std::ostream & tableOutput, } } -void TableTextFormatter::outputLine( PreparedTableLayout const & tableLayout, - CellLayoutRows const & rows, - CellLayoutRow const & row, - std::ostream & tableOutput, - size_t const idxRow ) const +void TableTextFormatter::outputLines( PreparedTableLayout const & tableLayout, + CellLayoutRows const & rows, + std::ostream & tableOutput ) const { size_t const nbRows = rows.size(); size_t const nbColumns = !rows.empty() ? rows.front().cells.size() : 0; - size_t const nbBorderSpaces = tableLayout.getBorderMargin(); size_t const nbColumnSpaces = ( tableLayout.getColumnMargin() - 1 ) / 2; - for( size_t idxSubLine = 0; idxSubLine < row.sublinesCount; idxSubLine++ ) - { - bool isLeftBorderCell = true; - for( size_t idxColumn = 0; idxColumn < nbColumns; ++idxColumn ) + size_t idxRow = 0; + for( CellLayoutRow const & row : rows ) + { + for( size_t idxSubLine = 0; idxSubLine < row.sublinesCount; idxSubLine++ ) { - auto & cell = row.cells[idxColumn]; - bool const isRightBorderCell = idxColumn == nbColumns - 1; - if( cell.m_cellType != CellType::MergeNext || isRightBorderCell ) + bool isLeftBorderCell = true; + + for( size_t idxColumn = 0; idxColumn < nbColumns; ++idxColumn ) { - bool const isSeparator = cell.m_cellType == CellType::Separator; - char const cellSpaceChar = isSeparator ? m_horizontalLine : ' '; - - if( isLeftBorderCell ) - { // left table border - isLeftBorderCell=false; - tableOutput << tableLayout.getIndentationStr(); - tableOutput << m_verticalLine << string( nbBorderSpaces, cellSpaceChar ); - } - else - { // left side of a cell that have a neightboor - tableOutput << string( nbColumnSpaces, cellSpaceChar ); - } + auto & cell = row.cells[idxColumn]; + bool const isRightBorderCell = idxColumn == nbColumns - 1; + if( cell.m_cellType != CellType::MergeNext || isRightBorderCell ) + { + bool const isSeparator = cell.m_cellType == CellType::Separator; + char const cellSpaceChar = isSeparator ? m_horizontalLine : ' '; + + if( isLeftBorderCell ) + { // left table border + isLeftBorderCell=false; + tableOutput << tableLayout.getIndentationStr(); + tableOutput << m_verticalLine << string( nbBorderSpaces, cellSpaceChar ); + } + else + { // left side of a cell that have a neightboor + tableOutput << string( nbColumnSpaces, cellSpaceChar ); + } - // cell content / fill - formatCell( tableOutput, cell, idxSubLine ); - - if( !isRightBorderCell ) - { // right side of a cell that have a neightboor - bool const isNextSeparator = row.cells[idxColumn + 1].m_cellType == CellType::Separator; - bool const upMerged = idxRow > 0 && rows[idxRow - 1].cells[idxColumn].m_cellType == CellType::MergeNext; - bool const downMerged = idxRow < nbRows - 1 && rows[idxRow + 1].cells[idxColumn].m_cellType == CellType::MergeNext; - tableOutput << string( nbColumnSpaces, cellSpaceChar ); - tableOutput << ( isSeparator && isNextSeparator && (upMerged || downMerged) ? - m_horizontalLine : m_verticalLine ); - } - else - { // right table border - tableOutput << string( nbBorderSpaces, cellSpaceChar ) << m_verticalLine << "\n"; + // cell content / fill + formatCell( tableOutput, cell, idxSubLine ); + + if( !isRightBorderCell ) + { // right side of a cell that have a neightboor + bool const isNextSeparator = row.cells[idxColumn + 1].m_cellType == CellType::Separator; + bool const upMerged = idxRow > 0 && rows[idxRow - 1].cells[idxColumn].m_cellType == CellType::MergeNext; + bool const downMerged = idxRow < nbRows - 1 && rows[idxRow + 1].cells[idxColumn].m_cellType == CellType::MergeNext; + tableOutput << string( nbColumnSpaces, cellSpaceChar ); + tableOutput << ( isSeparator && isNextSeparator && (upMerged || downMerged) ? + m_horizontalLine : m_verticalLine ); + } + else + { // right table border + tableOutput << string( nbBorderSpaces, cellSpaceChar ) << m_verticalLine << "\n"; + } } } } - } - -} - -void TableTextFormatter::outputLines( PreparedTableLayout const & tableLayout, - CellLayoutRows const & rows, - std::ostream & tableOutput ) const -{ - - size_t idxRow=0; - for( CellLayoutRow const & row : rows ) - { - outputLine( tableLayout, rows, row, tableOutput, idxRow ); idxRow++; } } diff --git a/src/coreComponents/common/format/table/TableFormatter.hpp b/src/coreComponents/common/format/table/TableFormatter.hpp index 4c974391b22..eed907975c2 100644 --- a/src/coreComponents/common/format/table/TableFormatter.hpp +++ b/src/coreComponents/common/format/table/TableFormatter.hpp @@ -308,20 +308,6 @@ class TableTextFormatter : public TableFormatter string_view separatorLine, bool hasData ) const; - /** - * @brief Outputs the formatted table line to the output stream. - * @param tableLayout The layout of the table - * @param rows The data rows in a grid layout - * @param row Represent a row of the Table (header or values) to output - * @param tableOutput A reference to an `std::ostream` where the formatted table will be written. - * @param idxRow the row index to output - */ - void outputLine( PreparedTableLayout const & tableLayout, - CellLayoutRows const & rows, - CellLayoutRow const & row, - std::ostream & tableOutput, - size_t const idxRow ) const; - private: /** From d79852f4b31bf37be6134bcd994921c0646d5adb Mon Sep 17 00:00:00 2001 From: arng40 Date: Thu, 26 Mar 2026 11:20:01 +0100 Subject: [PATCH 45/70] :green_heart: uncrustfy --- src/coreComponents/common/MpiWrapper.hpp | 4 ++-- src/coreComponents/common/format/table/TableMpiComponents.cpp | 2 +- src/coreComponents/common/format/table/TableMpiComponents.hpp | 4 ++-- .../common/format/table/unitTests/testMpiTable.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/coreComponents/common/MpiWrapper.hpp b/src/coreComponents/common/MpiWrapper.hpp index 0c669849a66..f5fe14dc5b0 100644 --- a/src/coreComponents/common/MpiWrapper.hpp +++ b/src/coreComponents/common/MpiWrapper.hpp @@ -381,7 +381,7 @@ struct MpiWrapper } - MpiWrapper::gather( &numLocalValues , 1, gatherResult.counts.data(), 1, 0 ); + MpiWrapper::gather( &numLocalValues, 1, gatherResult.counts.data(), 1, 0 ); if( MpiWrapper::commRank() == 0 ) { @@ -395,7 +395,7 @@ struct MpiWrapper } MpiWrapper::gatherv( localBuffer.data(), - numLocalValues , + numLocalValues, gatherResult.data.data(), gatherResult.counts.data(), gatherResult.offsets.data(), diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index 66aa63f6e79..e078bafdd89 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -187,7 +187,7 @@ void TableTextMpiFormatter::toStream< TableData >( std::ostream & tableOutput, if( status.m_isMasterRank ) { - tableDataGathered.sort( *m_sortingFunctor ); + tableDataGathered.sort( *m_sortingFunctor ); TableTextFormatter::toStream( tableOutput, tableDataGathered ); } } diff --git a/src/coreComponents/common/format/table/TableMpiComponents.hpp b/src/coreComponents/common/format/table/TableMpiComponents.hpp index 09a9fca8701..f4f3876489b 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.hpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.hpp @@ -118,8 +118,8 @@ class TableTextMpiFormatter : public TableTextFormatter stdVector< TableData::CellData > parseStringRow( string_view rowString ) const; /** - * @brief - * @param localTableData + * @brief Gather all the TableData to the rank 0. + * @param localTableData The local TableData to send to rank 0; */ TableData gatherTableDataRank0( TableData const & localTableData ) const; diff --git a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp index 8b252abdc89..4625cc0993f 100644 --- a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp +++ b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp @@ -135,7 +135,7 @@ TEST( testMpiTables, testDifferentRankData ) oss.str().data() ); } } - + } TEST( testMpiTables, testSortingMethod ) From b045e5055bdd323c7d140f2e3a67c17067d01365 Mon Sep 17 00:00:00 2001 From: arng40 Date: Thu, 26 Mar 2026 11:37:37 +0100 Subject: [PATCH 46/70] :art: move gatherString to hpp --- src/coreComponents/common/MpiWrapper.cpp | 21 ------------------ src/coreComponents/common/MpiWrapper.hpp | 28 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/coreComponents/common/MpiWrapper.cpp b/src/coreComponents/common/MpiWrapper.cpp index 0443e8f4f58..81212fa60a7 100644 --- a/src/coreComponents/common/MpiWrapper.cpp +++ b/src/coreComponents/common/MpiWrapper.cpp @@ -518,27 +518,6 @@ template<> MPI_Datatype getMpiPairType< double, double >() } /* namespace internal */ -template<> -void MpiWrapper::gatherStringOnRank0< std::function< void(string_view) > > - ( string_view rankStr, std::function< void(string_view) > && func ) -{ - std::vector< buffer_unit_type > localbuffer; - localbuffer.reserve( rankStr.size()); - localbuffer.insert( localbuffer.end(), rankStr.begin(), rankStr.end()); - auto [globalLogRecords, counts, offsets] = - MpiWrapper::gatherBufferRank0< std::vector< buffer_unit_type > >( localbuffer ); - if( MpiWrapper::commRank() == 0 ) - { - for( integer rankId = 0; rankId < MpiWrapper::commSize(); ++rankId ) - { - if( counts[rankId] > 0 ) - { - func( string( globalLogRecords.begin() + offsets[rankId], - globalLogRecords.begin() + offsets[rankId]+ counts[rankId] ) ); - } - } - } -} } /* namespace geos */ diff --git a/src/coreComponents/common/MpiWrapper.hpp b/src/coreComponents/common/MpiWrapper.hpp index f5fe14dc5b0..8dcdbcaf47a 100644 --- a/src/coreComponents/common/MpiWrapper.hpp +++ b/src/coreComponents/common/MpiWrapper.hpp @@ -1696,6 +1696,34 @@ template< typename FIRST, typename SECOND, typename CONTAINER > MpiWrapper::PairType< FIRST, SECOND > MpiWrapper::max( CONTAINER const & pairs, MPI_Comm comm ) { return allReduce< FIRST, SECOND, CONTAINER, PairReduction::Max >( pairs, comm ); } +/** + * @brief Specialization of gatherStringOnRank0 for std::function< void(string_view) > callbacks. + * @tparam std::function< void(string_view) > callable invoked on rank 0 for each non-empty rank string. + * @param rankStr The local string to send from the calling rank. + * @param func Callback invoked on rank 0 for each non-empty received string, passed as a string_view. + */ +template<> +inline void MpiWrapper::gatherStringOnRank0< std::function< void(string_view) > > + ( string_view rankStr, std::function< void(string_view) > && func ) +{ + std::vector< buffer_unit_type > localbuffer; + localbuffer.reserve( rankStr.size()); + localbuffer.insert( localbuffer.end(), rankStr.begin(), rankStr.end()); + auto [globalLogRecords, counts, offsets] = + MpiWrapper::gatherBufferRank0< std::vector< buffer_unit_type > >( localbuffer ); + if( MpiWrapper::commRank() == 0 ) + { + for( integer rankId = 0; rankId < MpiWrapper::commSize(); ++rankId ) + { + if( counts[rankId] > 0 ) + { + func( string( globalLogRecords.begin() + offsets[rankId], + globalLogRecords.begin() + offsets[rankId]+ counts[rankId] ) ); + } + } + } +} + } /* namespace geos */ #endif /* GEOS_COMMON_MPIWRAPPER_HPP_ */ From 552229b3ebb8e5f5226a7b3fdfce25365a92b8a3 Mon Sep 17 00:00:00 2001 From: arng40 Date: Thu, 26 Mar 2026 11:39:21 +0100 Subject: [PATCH 47/70] :coffin: include --- src/coreComponents/common/format/table/TableData.hpp | 2 -- src/coreComponents/mesh/ElementRegionManager.cpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/coreComponents/common/format/table/TableData.hpp b/src/coreComponents/common/format/table/TableData.hpp index eae7c841336..14afcaa8021 100644 --- a/src/coreComponents/common/format/table/TableData.hpp +++ b/src/coreComponents/common/format/table/TableData.hpp @@ -20,12 +20,10 @@ #ifndef GEOS_COMMON_FORMAT_TABLE_TABLEDATA_HPP #define GEOS_COMMON_FORMAT_TABLE_TABLEDATA_HPP -#include "common/StdContainerWrappers.hpp" #include "common/Units.hpp" #include "common/DataTypes.hpp" #include "common/format/Format.hpp" #include "TableTypes.hpp" -#include namespace geos { diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index ed6984a3008..ec55a907e75 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -13,14 +13,12 @@ * ------------------------------------------------------------------------------------------------------------ */ -#include #include #include #include "ElementRegionManager.hpp" #include "common/DataLayouts.hpp" -#include "common/MpiWrapper.hpp" #include "common/TimingMacros.hpp" #include "common/format/table/TableMpiComponents.hpp" #include "mesh/WellElementSubRegion.hpp" From 47013b24b1d8aef17b0a6441a3fc8c275b2adda6 Mon Sep 17 00:00:00 2001 From: arng40 Date: Thu, 26 Mar 2026 15:58:47 +0100 Subject: [PATCH 48/70] :recycle: simplify MPI guard --- .../mesh/ElementRegionManager.cpp | 31 +------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index ec55a907e75..ef633336011 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -181,35 +181,6 @@ void ElementRegionManager::generateMesh( CellBlockManagerABC const & cellBlockMa } ); } -integer detectPerforationsAcrossRanks( TableData const & localPerfoData ) -{ - stdVector< integer > counts; - integer const numRanks = MpiWrapper::commSize(); - integer const numLocalValues = static_cast< integer >(localPerfoData.getCellsData().size()); - - if( MpiWrapper::commRank() == 0 ) - { - counts.resize( numRanks ); - } - - MpiWrapper::gather( &numLocalValues, 1, counts.data(), 1, 0 ); - - auto it = std::find_if( counts.begin(), counts.end(), []( integer const & rankCount ) - { - return rankCount != 0; - } ); - - integer perfoDetected = false; - if( MpiWrapper::commRank() == 0 && it != counts.end()) - { - perfoDetected = true; - } - - MpiWrapper::bcast( &perfoDetected, 1, 0 ); - - return perfoDetected; -} - void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockManager, MeshLevel & meshLevel ) { @@ -292,7 +263,7 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM } } - integer perfoDetected = detectPerforationsAcrossRanks( localPerfoData ); + integer perfoDetected = MpiWrapper::max( localPerfoData.getCellsData().size() ) > 0; if( perfoDetected ) { From e7f14395858f7c17915e3308c1f4eabb9bd92d6a Mon Sep 17 00:00:00 2001 From: arng40 Date: Thu, 26 Mar 2026 15:59:18 +0100 Subject: [PATCH 49/70] :art: remove template --- src/coreComponents/common/MpiWrapper.cpp | 20 +++++++++++++++ src/coreComponents/common/MpiWrapper.hpp | 31 +----------------------- 2 files changed, 21 insertions(+), 30 deletions(-) diff --git a/src/coreComponents/common/MpiWrapper.cpp b/src/coreComponents/common/MpiWrapper.cpp index 81212fa60a7..0e3e3bd6288 100644 --- a/src/coreComponents/common/MpiWrapper.cpp +++ b/src/coreComponents/common/MpiWrapper.cpp @@ -462,6 +462,26 @@ int MpiWrapper::nodeCommSize() return nodeCommSize; } +void MpiWrapper::gatherStringOnRank0( string_view rankStr, std::function< void(string_view) > && func ) +{ + std::vector< buffer_unit_type > localbuffer; + localbuffer.reserve( rankStr.size()); + localbuffer.insert( localbuffer.end(), rankStr.begin(), rankStr.end()); + auto [globalLogRecords, counts, offsets] = + MpiWrapper::gatherBufferRank0< std::vector< buffer_unit_type > >( localbuffer ); + if( MpiWrapper::commRank() == 0 ) + { + for( integer rankId = 0; rankId < MpiWrapper::commSize(); ++rankId ) + { + if( counts[rankId] > 0 ) + { + func( string( globalLogRecords.begin() + offsets[rankId], + globalLogRecords.begin() + offsets[rankId]+ counts[rankId] ) ); + } + } + } +} + namespace internal { diff --git a/src/coreComponents/common/MpiWrapper.hpp b/src/coreComponents/common/MpiWrapper.hpp index 8dcdbcaf47a..35c309258e1 100644 --- a/src/coreComponents/common/MpiWrapper.hpp +++ b/src/coreComponents/common/MpiWrapper.hpp @@ -410,9 +410,8 @@ struct MpiWrapper * @param str The local string to send from the calling rank. * @param func Callback invoked on rank 0 for each non-empty received string. */ - template< typename FUNC > static void gatherStringOnRank0( string_view str, - FUNC && func ); + std::function< void(string_view) > && func ); /** * @brief Strongly typed wrapper around MPI_Allgather. @@ -1696,34 +1695,6 @@ template< typename FIRST, typename SECOND, typename CONTAINER > MpiWrapper::PairType< FIRST, SECOND > MpiWrapper::max( CONTAINER const & pairs, MPI_Comm comm ) { return allReduce< FIRST, SECOND, CONTAINER, PairReduction::Max >( pairs, comm ); } -/** - * @brief Specialization of gatherStringOnRank0 for std::function< void(string_view) > callbacks. - * @tparam std::function< void(string_view) > callable invoked on rank 0 for each non-empty rank string. - * @param rankStr The local string to send from the calling rank. - * @param func Callback invoked on rank 0 for each non-empty received string, passed as a string_view. - */ -template<> -inline void MpiWrapper::gatherStringOnRank0< std::function< void(string_view) > > - ( string_view rankStr, std::function< void(string_view) > && func ) -{ - std::vector< buffer_unit_type > localbuffer; - localbuffer.reserve( rankStr.size()); - localbuffer.insert( localbuffer.end(), rankStr.begin(), rankStr.end()); - auto [globalLogRecords, counts, offsets] = - MpiWrapper::gatherBufferRank0< std::vector< buffer_unit_type > >( localbuffer ); - if( MpiWrapper::commRank() == 0 ) - { - for( integer rankId = 0; rankId < MpiWrapper::commSize(); ++rankId ) - { - if( counts[rankId] > 0 ) - { - func( string( globalLogRecords.begin() + offsets[rankId], - globalLogRecords.begin() + offsets[rankId]+ counts[rankId] ) ); - } - } - } -} - } /* namespace geos */ #endif /* GEOS_COMMON_MPIWRAPPER_HPP_ */ From ae56cb479a5cedeac81d33fb97e9e82b390db757 Mon Sep 17 00:00:00 2001 From: arng40 Date: Thu, 26 Mar 2026 15:59:56 +0100 Subject: [PATCH 50/70] :building_construction: create namespace for serialization --- .../common/format/table/TableData.cpp | 47 ++++++++++-- .../common/format/table/TableData.hpp | 76 ++++++++++++++++++- 2 files changed, 117 insertions(+), 6 deletions(-) diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp index 7ae3c28f787..0f33a6e8aaf 100644 --- a/src/coreComponents/common/format/table/TableData.cpp +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -86,8 +86,8 @@ bool TableData::operator==( TableData const & comparingTable ) const void TableData::CellData::serialize( stdVector< buffer_unit_type > & out ) const { - serializePrimitive( type, out ); - serializeString( value, out ); + serialBuffer::serializePrimitive( type, out ); + serialBuffer::serializeString( value, out ); } @@ -126,14 +126,12 @@ void TableData::serialize( stdVector< buffer_unit_type > & serializedTableData ) size_t rowSize = 0; for( auto const & cell : row ) rowSize += cell.getSerializedSize(); - serializePrimitive( rowSize, serializedTableData ); + serialBuffer::serializePrimitive( rowSize, serializedTableData ); } { // pack cells for( auto const & cell : row ) { - // size_t cellSize = cell.getSerializedSize(); - // serializePrimitive( cellSize, serializedTableData ); cell.serialize( serializedTableData ); } } @@ -259,6 +257,45 @@ TableData2D::TableDataHolder TableData2D::buildTableData( string_view targetUnit return tableData1D; } +template< typename T > +void serialBuffer::serializePrimitive ( T const data, stdVector< buffer_unit_type > & out ) +{ + static_assert( std::is_trivially_copyable_v< T > ); + buffer_unit_type const * begin = reinterpret_cast< buffer_unit_type const * >( &data ); + buffer_unit_type const * end = begin + sizeof(data); + out.insert( out.end(), begin, end ); +} + +void serialBuffer::serializeString ( string const & data, stdVector< buffer_unit_type > & out ) +{ + serialBuffer::serializePrimitive( data.size(), out ); + auto * begin = data.data(); + auto * end = begin + data.size(); + out.insert( out.end(), begin, end ); +} + +template< typename T > +void serialBuffer::deserializePrimitive( T & data, buffer_unit_type const * & ptr, buffer_unit_type const * end ) +{ + static_assert( std::is_trivially_copyable_v< T > ); + if( ptr + sizeof(T)> end ) + throw std::runtime_error( "Buffer truncated" ); + memcpy( &data, ptr, sizeof(T) ); + ptr += sizeof(T); +} + +void serialBuffer::deserializeString( string & str, buffer_unit_type const * & ptr, buffer_unit_type const * end ) +{ + string::size_type strSize = 0; + serialBuffer::deserializePrimitive( strSize, ptr, end ); + if( std::distance( ptr, end ) < (long) strSize ) + { + throw std::runtime_error( "Buffer truncated reading string" ); + } + str.assign( ptr, ptr + strSize ); + ptr += str.size(); +} + bool tableDataSorting::positiveNumberStringComp( string_view s1, string_view s2 ) { auto split = []( string_view s, string & intPart, string & decPart ) diff --git a/src/coreComponents/common/format/table/TableData.hpp b/src/coreComponents/common/format/table/TableData.hpp index 14afcaa8021..5a8743b7006 100644 --- a/src/coreComponents/common/format/table/TableData.hpp +++ b/src/coreComponents/common/format/table/TableData.hpp @@ -94,14 +94,26 @@ class TableData static unsigned long sizeOfField( string const & str ) { return sizeof(string::size_type) + str.size(); } + /** + * @brief Write the data to the buffer. + * @tparam T The type of the data who must be trivially copiable + * @param data Destination variable. + * @param out The buffer to write in. + */ template< typename T > static void serializePrimitive ( T const data, stdVector< buffer_unit_type > & out ) { + static_assert( std::is_trivially_copyable_v< T > ); buffer_unit_type const * begin = reinterpret_cast< buffer_unit_type const * >( &data ); buffer_unit_type const * end = begin + sizeof(data); out.insert( out.end(), begin, end ); } + /** + * @brief Write a string value to the buffer. + * @param data String variable. + * @param out The buffer to write in. + */ static void serializeString ( string const & data, stdVector< buffer_unit_type > & out ) { serializePrimitive( data.size(), out ); @@ -110,6 +122,13 @@ class TableData out.insert( out.end(), begin, end ); } + /** + * @brief Reads the data from the buffer and advances the pointer. + * @tparam T The type of the data who must be trivially copiable + * @param data Destination variable. + * @param ptr Current read pointer (advanced by sizeof(string)). + * @param end Safety: maximum buffer limit. + */ template< typename T > static void deserializeField( T & data, buffer_unit_type const * & ptr, buffer_unit_type const * end ) { @@ -119,7 +138,8 @@ class TableData ptr += sizeof(T); } - /** @brief Reads a string value from the buffer and advances the pointer. + /** + * @brief Reads a string value from the buffer and advances the pointer. * @param data Destination variable. * @param ptr Current read pointer (advanced by sizeof(string)). * @param end Safety: maximum buffer limit. @@ -363,6 +383,60 @@ void TableData2D::addCell( real64 const rowValue, real64 const columnValue, T co m_data.get_inserted( rowValue ).get_inserted( columnValue ) = GEOS_FMT( "{}", value ); } +namespace serialBuffer +{ + +/** + * @tparam T The trivial type + * @return Returns the size occupied by a trivial type in memory. + */ +template< typename T > +inline unsigned long sizeOfPrimitive( T ) +{ return sizeof(T); } + +/** + * @brief Returns the size of a string (header size + content). + * @param str The target string + * @return Size in bytes. + */ +inline unsigned long sizeOfString( string const & str ) +{ return sizeof(string::size_type) + str.size(); } + +/** + * @brief Write the data to the buffer. + * @tparam T The type of the data who must be trivially copiable + * @param data Destination variable. + * @param out The buffer to write in. + */ +template< typename T > +void serializePrimitive ( T const data, stdVector< buffer_unit_type > & out ); + +/** + * @brief Write a string value to the buffer. + * @param data String variable. + * @param out The buffer to write in. + */ +void serializeString ( string const & data, stdVector< buffer_unit_type > & out ); + +/** + * @brief Reads the data from the buffer and advances the pointer. + * @tparam T The type of the data who must be trivially copiable + * @param data Destination variable. + * @param ptr Current read pointer (advanced by sizeof(string)). + * @param end Safety: maximum buffer limit. + */ +template< typename T > +void deserializePrimitive( T & data, buffer_unit_type const * & ptr, buffer_unit_type const * end ); + +/** + * @brief Reads a string value from the buffer and advances the pointer. + * @param data Destination variable. + * @param ptr Current read pointer (advanced by sizeof(string)). + * @param end Safety: maximum buffer limit. + */ +void deserializeString( string & str, buffer_unit_type const * & ptr, buffer_unit_type const * end ); +} + // Custom Comp function; namespace tableDataSorting { From 632edd7c4f4aaa19e0a9914c8d76787b2303122a Mon Sep 17 00:00:00 2001 From: arng40 Date: Thu, 26 Mar 2026 16:12:14 +0100 Subject: [PATCH 51/70] :art: Improve struct --- src/coreComponents/common/format/table/TableData.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp index 0f33a6e8aaf..392e92a8a44 100644 --- a/src/coreComponents/common/format/table/TableData.cpp +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -280,7 +280,7 @@ void serialBuffer::deserializePrimitive( T & data, buffer_unit_type const * & pt static_assert( std::is_trivially_copyable_v< T > ); if( ptr + sizeof(T)> end ) throw std::runtime_error( "Buffer truncated" ); - memcpy( &data, ptr, sizeof(T) ); + data = *reinterpret_cast< T const * >(ptr); ptr += sizeof(T); } @@ -288,7 +288,7 @@ void serialBuffer::deserializeString( string & str, buffer_unit_type const * & p { string::size_type strSize = 0; serialBuffer::deserializePrimitive( strSize, ptr, end ); - if( std::distance( ptr, end ) < (long) strSize ) + if( static_cast< long >(strSize) < std::distance( ptr, end ) ) { throw std::runtime_error( "Buffer truncated reading string" ); } From 73c7a377c7e2d4273e140fa96e95bfe09ed2f4c5 Mon Sep 17 00:00:00 2001 From: arng40 Date: Thu, 26 Mar 2026 16:14:12 +0100 Subject: [PATCH 52/70] :coffin: remove dead code --- src/coreComponents/common/MpiWrapper.cpp | 1 - src/coreComponents/common/format/table/TableData.cpp | 2 -- src/coreComponents/common/format/table/TableData.hpp | 2 +- src/coreComponents/common/format/table/TableMpiComponents.cpp | 2 -- .../common/format/table/unitTests/testMpiTable.cpp | 1 - 5 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/coreComponents/common/MpiWrapper.cpp b/src/coreComponents/common/MpiWrapper.cpp index 0e3e3bd6288..5dd157a3d53 100644 --- a/src/coreComponents/common/MpiWrapper.cpp +++ b/src/coreComponents/common/MpiWrapper.cpp @@ -538,7 +538,6 @@ template<> MPI_Datatype getMpiPairType< double, double >() } /* namespace internal */ - } /* namespace geos */ #if defined(__clang__) diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp index 392e92a8a44..c75a5a2c77a 100644 --- a/src/coreComponents/common/format/table/TableData.cpp +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -18,9 +18,7 @@ */ #include "TableData.hpp" -#include "common/DataTypes.hpp" #include "common/logger/Logger.hpp" -#include "dataRepository/BufferOps.hpp" namespace geos { diff --git a/src/coreComponents/common/format/table/TableData.hpp b/src/coreComponents/common/format/table/TableData.hpp index 5a8743b7006..3c47f39caa9 100644 --- a/src/coreComponents/common/format/table/TableData.hpp +++ b/src/coreComponents/common/format/table/TableData.hpp @@ -222,7 +222,6 @@ class TableData * @brief Get all error messages * @return The list of error messages */ - TableErrorListing & getErrorsList() { return *m_errors; } @@ -383,6 +382,7 @@ void TableData2D::addCell( real64 const rowValue, real64 const columnValue, T co m_data.get_inserted( rowValue ).get_inserted( columnValue ) = GEOS_FMT( "{}", value ); } +// Serialisation/ Deserialisation namespace serialBuffer { diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index e078bafdd89..eb1de76e032 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -20,8 +20,6 @@ #include "TableMpiComponents.hpp" #include "common/MpiWrapper.hpp" -#include "dataRepository/BufferOps.hpp" - namespace geos { diff --git a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp index 4625cc0993f..41547241b51 100644 --- a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp +++ b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp @@ -14,7 +14,6 @@ */ // Source includes -#include "common/format/table/TableData.hpp" #include "common/format/table/TableMpiComponents.hpp" #include "common/initializeEnvironment.hpp" #include "common/MpiWrapper.hpp" From 49d72e0f6c0cffdeabbb2be148e424e7259769af Mon Sep 17 00:00:00 2001 From: arng40 Date: Thu, 26 Mar 2026 16:43:14 +0100 Subject: [PATCH 53/70] :coffin: rmove serial from tableData --- .../common/format/table/TableData.cpp | 21 +-- .../common/format/table/TableData.hpp | 120 ++++++------------ .../format/table/TableMpiComponents.cpp | 7 +- 3 files changed, 45 insertions(+), 103 deletions(-) diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp index c75a5a2c77a..daf3dfe981d 100644 --- a/src/coreComponents/common/format/table/TableData.cpp +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -91,7 +91,7 @@ void TableData::CellData::serialize( stdVector< buffer_unit_type > & out ) const size_t TableData::CellData::getSerializedSize() const { - return sizeOfField( type ) + sizeOfField( value ); + return serialBuffer::sizeOfPrimitive(type) + serialBuffer::sizeOfString( value ); } size_t TableData::getSerializedSize() const @@ -255,15 +255,6 @@ TableData2D::TableDataHolder TableData2D::buildTableData( string_view targetUnit return tableData1D; } -template< typename T > -void serialBuffer::serializePrimitive ( T const data, stdVector< buffer_unit_type > & out ) -{ - static_assert( std::is_trivially_copyable_v< T > ); - buffer_unit_type const * begin = reinterpret_cast< buffer_unit_type const * >( &data ); - buffer_unit_type const * end = begin + sizeof(data); - out.insert( out.end(), begin, end ); -} - void serialBuffer::serializeString ( string const & data, stdVector< buffer_unit_type > & out ) { serialBuffer::serializePrimitive( data.size(), out ); @@ -272,16 +263,6 @@ void serialBuffer::serializeString ( string const & data, stdVector< buffer_unit out.insert( out.end(), begin, end ); } -template< typename T > -void serialBuffer::deserializePrimitive( T & data, buffer_unit_type const * & ptr, buffer_unit_type const * end ) -{ - static_assert( std::is_trivially_copyable_v< T > ); - if( ptr + sizeof(T)> end ) - throw std::runtime_error( "Buffer truncated" ); - data = *reinterpret_cast< T const * >(ptr); - ptr += sizeof(T); -} - void serialBuffer::deserializeString( string & str, buffer_unit_type const * & ptr, buffer_unit_type const * end ) { string::size_type strSize = 0; diff --git a/src/coreComponents/common/format/table/TableData.hpp b/src/coreComponents/common/format/table/TableData.hpp index 3c47f39caa9..bb58ae73403 100644 --- a/src/coreComponents/common/format/table/TableData.hpp +++ b/src/coreComponents/common/format/table/TableData.hpp @@ -62,7 +62,7 @@ class TableData bool operator==( TableData const & comparingTable ) const; /** - * @brief Representing a data in TableData + * @brief Representing a single cell's data within a TableData row. */ struct CellData { @@ -71,95 +71,31 @@ class TableData /// The cell value string value; + /** + * @return Total size in bytes required to serialize this cell. + */ size_t getSerializedSize() const; + /** + * @brief Serializes the cell type and value into the output buffer. + * @param out Buffer to append the serialized cell data to. + */ void serialize( stdVector< buffer_unit_type > & out ) const; }; - size_t getSerializedSize() const; - - /** - * @tparam T The trivial type - * @return Returns the size occupied by a trivial type in memory. - */ - template< typename T > - static unsigned long sizeOfField( T ) - { return sizeof(T); } - - /** - * @brief Returns the size of a string (header size + content). - * @param str The target string - * @return Size in bytes. - */ - static unsigned long sizeOfField( string const & str ) - { return sizeof(string::size_type) + str.size(); } - - /** - * @brief Write the data to the buffer. - * @tparam T The type of the data who must be trivially copiable - * @param data Destination variable. - * @param out The buffer to write in. - */ - template< typename T > - static void serializePrimitive ( T const data, stdVector< buffer_unit_type > & out ) - { - static_assert( std::is_trivially_copyable_v< T > ); - buffer_unit_type const * begin = reinterpret_cast< buffer_unit_type const * >( &data ); - buffer_unit_type const * end = begin + sizeof(data); - out.insert( out.end(), begin, end ); - } - - /** - * @brief Write a string value to the buffer. - * @param data String variable. - * @param out The buffer to write in. - */ - static void serializeString ( string const & data, stdVector< buffer_unit_type > & out ) - { - serializePrimitive( data.size(), out ); - auto * begin = data.data(); - auto * end = begin + data.size(); - out.insert( out.end(), begin, end ); - } - - /** - * @brief Reads the data from the buffer and advances the pointer. - * @tparam T The type of the data who must be trivially copiable - * @param data Destination variable. - * @param ptr Current read pointer (advanced by sizeof(string)). - * @param end Safety: maximum buffer limit. - */ - template< typename T > - static void deserializeField( T & data, buffer_unit_type const * & ptr, buffer_unit_type const * end ) - { - static_assert( std::is_trivially_copyable_v< T > ); - if( ptr + sizeof(T)> end ) throw std::runtime_error( "Buffer truncated" ); - memcpy( &data, ptr, sizeof(T) ); - ptr += sizeof(T); - } - /** - * @brief Reads a string value from the buffer and advances the pointer. - * @param data Destination variable. - * @param ptr Current read pointer (advanced by sizeof(string)). - * @param end Safety: maximum buffer limit. + * @brief Returns the total serialized byte size of all rows in the table. + * @return Total size in bytes required to serialize the entire TableData. */ - static void deserializeField( string & str, buffer_unit_type const * & ptr, buffer_unit_type const * end ) - { - string::size_type strSize = 0; - deserializeField( strSize, ptr, end ); - if( std::distance( ptr, end ) < (long) strSize ) - { - throw std::runtime_error( "Buffer truncated reading string" ); - } - str.assign( ptr, ptr + strSize ); - ptr += str.size(); - } - + size_t getSerializedSize() const; /// Alias for table data rows with cells values using DataRows = stdVector< stdVector< CellData > >; + /** + * @brief Serializes the tableData into the output buffer. + * @param serializedTableData Buffer to append the serialized tableData. + */ void serialize( stdVector< buffer_unit_type > & serializedTableData ) const; /** @@ -225,6 +161,11 @@ class TableData TableErrorListing & getErrorsList() { return *m_errors; } + /** + * @brief Sorts the rows using a custom comparator functor. + * @tparam SortingFunc Type of the sorting comparator functor. + * @param sortingFunctor Comparator functor used to sort the rows. + */ template< typename SortingFunc > void sort( SortingFunc sortingFunctor ) { @@ -382,7 +323,7 @@ void TableData2D::addCell( real64 const rowValue, real64 const columnValue, T co m_data.get_inserted( rowValue ).get_inserted( columnValue ) = GEOS_FMT( "{}", value ); } -// Serialisation/ Deserialisation +// Serialisation/ Deserialisation namespace serialBuffer { @@ -449,5 +390,24 @@ namespace tableDataSorting bool positiveNumberStringComp( string_view a, string_view b ); } +template< typename T > +void serialBuffer::serializePrimitive ( T const data, stdVector< buffer_unit_type > & out ) +{ + static_assert( std::is_trivially_copyable_v< T > ); + buffer_unit_type const * begin = reinterpret_cast< buffer_unit_type const * >( &data ); + buffer_unit_type const * end = begin + sizeof(data); + out.insert( out.end(), begin, end ); +} + +template< typename T > +void serialBuffer::deserializePrimitive( T & data, buffer_unit_type const * & ptr, buffer_unit_type const * end ) +{ + static_assert( std::is_trivially_copyable_v< T > ); + if( ptr + sizeof(T)> end ) + throw std::runtime_error( "Buffer truncated" ); + data = *reinterpret_cast< T const * >(ptr); + ptr += sizeof(T); +} + } #endif /* GEOS_COMMON_FORMAT_TABLE_TABLEDATA_HPP */ diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index eb1de76e032..788d29c7fd0 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -20,6 +20,7 @@ #include "TableMpiComponents.hpp" #include "common/MpiWrapper.hpp" +#include "common/format/table/TableTypes.hpp" namespace geos { @@ -145,15 +146,15 @@ TableData TableTextMpiFormatter::gatherTableDataRank0( TableData const & localTa while( startBuff < endRowsBuff ) { size_t byteFromThisRow = 0; - TableData::deserializeField( byteFromThisRow, startBuff, endRowsBuff ); + serialBuffer::deserializePrimitive( byteFromThisRow, startBuff, endRowsBuff ); buffer_unit_type const * endRowBuff= startBuff + byteFromThisRow; stdVector< TableData::CellData > row; while( startBuff < endRowBuff ) { CellType cellType; - TableData::deserializeField( cellType, startBuff, endRowBuff ); + serialBuffer::deserializePrimitive( cellType, startBuff, endRowBuff ); string cellValue; - TableData::deserializeField( cellValue, startBuff, endRowBuff ); + serialBuffer::deserializeString( cellValue, startBuff, endRowBuff ); row.push_back( {cellType, cellValue} ); } tableDataGathered.addRow( row ); From c567f231d9ec483550a740d46221adc212bd8a06 Mon Sep 17 00:00:00 2001 From: arng40 Date: Thu, 26 Mar 2026 16:49:03 +0100 Subject: [PATCH 54/70] :art: format doxy --- src/coreComponents/common/format/table/TableData.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreComponents/common/format/table/TableData.hpp b/src/coreComponents/common/format/table/TableData.hpp index bb58ae73403..8acbed9b9c1 100644 --- a/src/coreComponents/common/format/table/TableData.hpp +++ b/src/coreComponents/common/format/table/TableData.hpp @@ -323,7 +323,7 @@ void TableData2D::addCell( real64 const rowValue, real64 const columnValue, T co m_data.get_inserted( rowValue ).get_inserted( columnValue ) = GEOS_FMT( "{}", value ); } -// Serialisation/ Deserialisation +// Serialisation/ Deserialisation utils for common namespace serialBuffer { From 79c9ee20ac1f981672b3566ed3c47fa35dc80712 Mon Sep 17 00:00:00 2001 From: arng40 Date: Thu, 26 Mar 2026 17:27:40 +0100 Subject: [PATCH 55/70] :bug: fix deserialisation string bug --- src/coreComponents/common/format/table/TableData.cpp | 4 ++-- src/coreComponents/common/format/table/TableData.hpp | 2 +- src/coreComponents/common/format/table/TableMpiComponents.cpp | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp index daf3dfe981d..20ff5f86df7 100644 --- a/src/coreComponents/common/format/table/TableData.cpp +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -267,9 +267,9 @@ void serialBuffer::deserializeString( string & str, buffer_unit_type const * & p { string::size_type strSize = 0; serialBuffer::deserializePrimitive( strSize, ptr, end ); - if( static_cast< long >(strSize) < std::distance( ptr, end ) ) + if( std::distance( ptr, end ) < (long) strSize ) { - throw std::runtime_error( "Buffer truncated reading string" ); + throw std::runtime_error( "Buffer overflow reading string" ); } str.assign( ptr, ptr + strSize ); ptr += str.size(); diff --git a/src/coreComponents/common/format/table/TableData.hpp b/src/coreComponents/common/format/table/TableData.hpp index 8acbed9b9c1..07f7b9ebf47 100644 --- a/src/coreComponents/common/format/table/TableData.hpp +++ b/src/coreComponents/common/format/table/TableData.hpp @@ -404,7 +404,7 @@ void serialBuffer::deserializePrimitive( T & data, buffer_unit_type const * & pt { static_assert( std::is_trivially_copyable_v< T > ); if( ptr + sizeof(T)> end ) - throw std::runtime_error( "Buffer truncated" ); + throw std::runtime_error( "Buffer overflow" ); data = *reinterpret_cast< T const * >(ptr); ptr += sizeof(T); } diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index 788d29c7fd0..3ebf9ea5833 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -133,7 +133,6 @@ TableData TableTextMpiFormatter::gatherTableDataRank0( TableData const & localTa auto [globalLogRecords, counts, offsets] = MpiWrapper::gatherBufferRank0< stdVector< buffer_unit_type > >( serializedTableData ); - { // Unpacking TableData tableDataGathered; if( MpiWrapper::commRank() == 0 ) From ecef467a38f05877dab53fbc58245eec0311b081 Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 27 Mar 2026 11:15:41 +0100 Subject: [PATCH 56/70] :green_heart: fix CI build --- src/coreComponents/common/format/table/TableData.cpp | 6 +++--- src/coreComponents/common/format/table/TableData.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp index 20ff5f86df7..9f09406022d 100644 --- a/src/coreComponents/common/format/table/TableData.cpp +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -91,7 +91,7 @@ void TableData::CellData::serialize( stdVector< buffer_unit_type > & out ) const size_t TableData::CellData::getSerializedSize() const { - return serialBuffer::sizeOfPrimitive(type) + serialBuffer::sizeOfString( value ); + return serialBuffer::sizeOfPrimitive( type ) + serialBuffer::sizeOfString( value ); } size_t TableData::getSerializedSize() const @@ -267,9 +267,9 @@ void serialBuffer::deserializeString( string & str, buffer_unit_type const * & p { string::size_type strSize = 0; serialBuffer::deserializePrimitive( strSize, ptr, end ); - if( std::distance( ptr, end ) < (long) strSize ) + if( static_cast< long >(strSize) > std::distance( ptr, end ) ) { - throw std::runtime_error( "Buffer overflow reading string" ); + throw std::runtime_error( "buffer overflow reading string" ); } str.assign( ptr, ptr + strSize ); ptr += str.size(); diff --git a/src/coreComponents/common/format/table/TableData.hpp b/src/coreComponents/common/format/table/TableData.hpp index 07f7b9ebf47..7decd580b28 100644 --- a/src/coreComponents/common/format/table/TableData.hpp +++ b/src/coreComponents/common/format/table/TableData.hpp @@ -371,7 +371,7 @@ void deserializePrimitive( T & data, buffer_unit_type const * & ptr, buffer_unit /** * @brief Reads a string value from the buffer and advances the pointer. - * @param data Destination variable. + * @param str Destination string variable. * @param ptr Current read pointer (advanced by sizeof(string)). * @param end Safety: maximum buffer limit. */ From bdc15ec15a8de9aaca50d67de0eeda2578c26fd5 Mon Sep 17 00:00:00 2001 From: arng40 Date: Fri, 27 Mar 2026 17:12:37 +0100 Subject: [PATCH 57/70] :truck: move declaration outside hpp --- src/coreComponents/common/MpiWrapper.hpp | 76 +++++++++++++----------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/src/coreComponents/common/MpiWrapper.hpp b/src/coreComponents/common/MpiWrapper.hpp index 35c309258e1..bdbb7273459 100644 --- a/src/coreComponents/common/MpiWrapper.hpp +++ b/src/coreComponents/common/MpiWrapper.hpp @@ -367,42 +367,7 @@ struct MpiWrapper > > static GatherResult< CONTAINER > - gatherBufferRank0( CONTAINER const & localBuffer ) - { - integer const numRanks = MpiWrapper::commSize(); - integer const numLocalValues = static_cast< integer >(localBuffer.size()); - - GatherResult< CONTAINER > gatherResult; - - if( MpiWrapper::commRank() == 0 ) - { - gatherResult.counts.resize( numRanks ); - gatherResult.offsets.resize( numRanks ); - } - - - MpiWrapper::gather( &numLocalValues, 1, gatherResult.counts.data(), 1, 0 ); - - if( MpiWrapper::commRank() == 0 ) - { - integer totalSize = 0; - for( integer i = 0; i < numRanks; ++i ) - { - gatherResult.offsets[i] = totalSize; - totalSize += gatherResult.counts[i]; - } - gatherResult.data.resize( totalSize ); - } - - MpiWrapper::gatherv( localBuffer.data(), - numLocalValues, - gatherResult.data.data(), - gatherResult.counts.data(), - gatherResult.offsets.data(), - 0 ); - - return gatherResult; - } + gatherBufferRank0( CONTAINER const & localBuffer ); /** * @brief Gather srting from all ranks to rank 0 @@ -1060,6 +1025,45 @@ inline MPI_Op MpiWrapper::getMpiOp( Reduction const op ) } } +template< typename CONTAINER, typename VALUE_T, typename > +GatherResult< CONTAINER > +MpiWrapper::gatherBufferRank0( CONTAINER const & localBuffer ) +{ + integer const numRanks = MpiWrapper::commSize(); + integer const numLocalValues = static_cast< integer >(localBuffer.size()); + + GatherResult< CONTAINER > gatherResult; + + if( MpiWrapper::commRank() == 0 ) + { + gatherResult.counts.resize( numRanks ); + gatherResult.offsets.resize( numRanks ); + } + + + MpiWrapper::gather( &numLocalValues, 1, gatherResult.counts.data(), 1, 0 ); + + if( MpiWrapper::commRank() == 0 ) + { + integer totalSize = 0; + for( integer i = 0; i < numRanks; ++i ) + { + gatherResult.offsets[i] = totalSize; + totalSize += gatherResult.counts[i]; + } + gatherResult.data.resize( totalSize ); + } + + MpiWrapper::gatherv( localBuffer.data(), + numLocalValues, + gatherResult.data.data(), + gatherResult.counts.data(), + gatherResult.offsets.data(), + 0 ); + + return gatherResult; +} + template< typename T_SEND, typename T_RECV > int MpiWrapper::allgather( T_SEND const * const sendbuf, int sendcount, From 81a96b2ab91c3af1c0c69a0f742a78f976d3d9a0 Mon Sep 17 00:00:00 2001 From: arng40 Date: Mon, 30 Mar 2026 10:10:21 +0200 Subject: [PATCH 58/70] :coffin: :label: remove dead code, update types --- src/coreComponents/common/MpiWrapper.hpp | 8 ++--- .../common/format/table/TableData.cpp | 16 +++++----- .../common/format/table/TableData.hpp | 6 ++-- .../format/table/TableMpiComponents.cpp | 32 +++---------------- .../format/table/TableMpiComponents.hpp | 7 ---- 5 files changed, 20 insertions(+), 49 deletions(-) diff --git a/src/coreComponents/common/MpiWrapper.hpp b/src/coreComponents/common/MpiWrapper.hpp index bdbb7273459..0150856e365 100644 --- a/src/coreComponents/common/MpiWrapper.hpp +++ b/src/coreComponents/common/MpiWrapper.hpp @@ -339,11 +339,11 @@ struct MpiWrapper template< typename CONTAINER > struct GatherResult { - // Collected data who must be trivially copyable + // Collected data which must be trivially copyable CONTAINER data; - // Number of elements per row + // Number of elements per rank stdVector< integer > counts; - // Starting index for each row in 'data' + // Starting index for each rank in 'data' stdVector< integer > offsets; }; @@ -1026,7 +1026,7 @@ inline MPI_Op MpiWrapper::getMpiOp( Reduction const op ) } template< typename CONTAINER, typename VALUE_T, typename > -GatherResult< CONTAINER > +MpiWrapper::GatherResult< CONTAINER > MpiWrapper::gatherBufferRank0( CONTAINER const & localBuffer ) { integer const numRanks = MpiWrapper::commSize(); diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp index 9f09406022d..b04f2658caf 100644 --- a/src/coreComponents/common/format/table/TableData.cpp +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -84,14 +84,14 @@ bool TableData::operator==( TableData const & comparingTable ) const void TableData::CellData::serialize( stdVector< buffer_unit_type > & out ) const { - serialBuffer::serializePrimitive( type, out ); - serialBuffer::serializeString( value, out ); + basicSerialization::serializePrimitive( type, out ); + basicSerialization::serializeString( value, out ); } size_t TableData::CellData::getSerializedSize() const { - return serialBuffer::sizeOfPrimitive( type ) + serialBuffer::sizeOfString( value ); + return basicSerialization::sizeOfPrimitive( type ) + basicSerialization::sizeOfString( value ); } size_t TableData::getSerializedSize() const @@ -124,7 +124,7 @@ void TableData::serialize( stdVector< buffer_unit_type > & serializedTableData ) size_t rowSize = 0; for( auto const & cell : row ) rowSize += cell.getSerializedSize(); - serialBuffer::serializePrimitive( rowSize, serializedTableData ); + basicSerialization::serializePrimitive( rowSize, serializedTableData ); } { // pack cells @@ -255,18 +255,18 @@ TableData2D::TableDataHolder TableData2D::buildTableData( string_view targetUnit return tableData1D; } -void serialBuffer::serializeString ( string const & data, stdVector< buffer_unit_type > & out ) +void basicSerialization::serializeString ( string const & data, stdVector< buffer_unit_type > & out ) { - serialBuffer::serializePrimitive( data.size(), out ); + basicSerialization::serializePrimitive( data.size(), out ); auto * begin = data.data(); auto * end = begin + data.size(); out.insert( out.end(), begin, end ); } -void serialBuffer::deserializeString( string & str, buffer_unit_type const * & ptr, buffer_unit_type const * end ) +void basicSerialization::deserializeString( string & str, buffer_unit_type const * & ptr, buffer_unit_type const * end ) { string::size_type strSize = 0; - serialBuffer::deserializePrimitive( strSize, ptr, end ); + basicSerialization::deserializePrimitive( strSize, ptr, end ); if( static_cast< long >(strSize) > std::distance( ptr, end ) ) { throw std::runtime_error( "buffer overflow reading string" ); diff --git a/src/coreComponents/common/format/table/TableData.hpp b/src/coreComponents/common/format/table/TableData.hpp index 7decd580b28..f237b2ec038 100644 --- a/src/coreComponents/common/format/table/TableData.hpp +++ b/src/coreComponents/common/format/table/TableData.hpp @@ -324,7 +324,7 @@ void TableData2D::addCell( real64 const rowValue, real64 const columnValue, T co } // Serialisation/ Deserialisation utils for common -namespace serialBuffer +namespace basicSerialization { /** @@ -391,7 +391,7 @@ bool positiveNumberStringComp( string_view a, string_view b ); } template< typename T > -void serialBuffer::serializePrimitive ( T const data, stdVector< buffer_unit_type > & out ) +void basicSerialization::serializePrimitive ( T const data, stdVector< buffer_unit_type > & out ) { static_assert( std::is_trivially_copyable_v< T > ); buffer_unit_type const * begin = reinterpret_cast< buffer_unit_type const * >( &data ); @@ -400,7 +400,7 @@ void serialBuffer::serializePrimitive ( T const data, stdVector< buffer_unit_typ } template< typename T > -void serialBuffer::deserializePrimitive( T & data, buffer_unit_type const * & ptr, buffer_unit_type const * end ) +void basicSerialization::deserializePrimitive( T & data, buffer_unit_type const * & ptr, buffer_unit_type const * end ) { static_assert( std::is_trivially_copyable_v< T > ); if( ptr + sizeof(T)> end ) diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index 3ebf9ea5833..c958deb6eb4 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -58,28 +58,6 @@ void TableTextMpiFormatter::stretchColumnsByRanks( stdVector< size_t > & columns MpiWrapper::allReduce( columnsWidth, columnsWidth, MpiWrapper::Reduction::Max ); } -stdVector< TableData::CellData > TableTextMpiFormatter::parseStringRow( string_view rowString ) const -{ - if( rowString.empty() ) - return stdVector< TableData::CellData >{}; - - if( rowString.front() == '|' ) - rowString.remove_prefix( 1 ); - string_view rowContent =rowString; - string cell; - stdVector< TableData::CellData > dataRow; - - std::string::size_type end = 0; - - while( (end = rowContent.find( m_verticalLine )) != string_view::npos ) - { - cell =std::string( stringutilities::trimSpaces( rowContent.substr( 0, end ))); - dataRow.emplace_back( TableData::CellData( {CellType::Value, cell} )); - rowContent.remove_prefix( end + 1 ); - } - return dataRow; -} - void TableTextMpiFormatter::gatherAndOutputTableDataInRankOrder( std::ostream & tableOutput, TableFormatter::CellLayoutRows const & rows, PreparedTableLayout const & tableLayout, @@ -102,10 +80,10 @@ void TableTextMpiFormatter::gatherAndOutputTableDataInRankOrder( std::ostream & string const rankStr = !status.m_isMasterRank && status.m_isContributing ? localStringStream.str() : ""; stdVector< string > strsAccrossRanks; - MpiWrapper::gatherStringOnRank0( rankStr, std::function< void(string_view) >( [&]( string_view str ){ + MpiWrapper::gatherStringOnRank0( rankStr, [&]( string_view str ){ status.m_hasContent = true; strsAccrossRanks.emplace_back( str ); - } ) ); + } ); if( status.m_isMasterRank && status.m_hasContent ) { @@ -145,15 +123,15 @@ TableData TableTextMpiFormatter::gatherTableDataRank0( TableData const & localTa while( startBuff < endRowsBuff ) { size_t byteFromThisRow = 0; - serialBuffer::deserializePrimitive( byteFromThisRow, startBuff, endRowsBuff ); + basicSerialization::deserializePrimitive( byteFromThisRow, startBuff, endRowsBuff ); buffer_unit_type const * endRowBuff= startBuff + byteFromThisRow; stdVector< TableData::CellData > row; while( startBuff < endRowBuff ) { CellType cellType; - serialBuffer::deserializePrimitive( cellType, startBuff, endRowBuff ); + basicSerialization::deserializePrimitive( cellType, startBuff, endRowBuff ); string cellValue; - serialBuffer::deserializeString( cellValue, startBuff, endRowBuff ); + basicSerialization::deserializeString( cellValue, startBuff, endRowBuff ); row.push_back( {cellType, cellValue} ); } tableDataGathered.addRow( row ); diff --git a/src/coreComponents/common/format/table/TableMpiComponents.hpp b/src/coreComponents/common/format/table/TableMpiComponents.hpp index f4f3876489b..655a8a343cb 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.hpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.hpp @@ -110,13 +110,6 @@ class TableTextMpiFormatter : public TableTextFormatter void stretchColumnsByRanks( stdVector< size_t > & columnsWidth, Status const & status ) const; - /** - * @brief Parse a string row to a TablaData cells. - * @param rowString The string row string to parse. - * @return The parsed row as a vector of CellData. - */ - stdVector< TableData::CellData > parseStringRow( string_view rowString ) const; - /** * @brief Gather all the TableData to the rank 0. * @param localTableData The local TableData to send to rank 0; From 7d6249d7c2c3c4253ef04d0a076f44442ae1d3ef Mon Sep 17 00:00:00 2001 From: arng40 Date: Mon, 30 Mar 2026 10:12:03 +0200 Subject: [PATCH 59/70] :art: update perdoration sorting cond --- src/coreComponents/mesh/ElementRegionManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index ef633336011..4c8bc421ccf 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -280,7 +280,7 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM formatter.setSortingFunc( []( std::vector< TableData::CellData > const & row1, std::vector< TableData::CellData > const & row2 ) { - return tableDataSorting::positiveNumberStringComp( row1[1].value, row2[1].value ); + return tableDataSorting::positiveNumberStringComp( row1[0].value, row2[0].value ); } ); std::ostringstream outputStream; From 935d117eccad9cd741fc8bcce8cfdbb6e821cedc Mon Sep 17 00:00:00 2001 From: arng40 Date: Mon, 30 Mar 2026 10:12:28 +0200 Subject: [PATCH 60/70] :art: improve testMpiTable Cond --- .../common/format/table/unitTests/testMpiTable.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp index 41547241b51..f044dc35a70 100644 --- a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp +++ b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp @@ -99,14 +99,12 @@ TEST( testMpiTables, testDifferentRankData ) "-------------------------------------------\n" }, }; + int const rankId = MpiWrapper::commRank(); + int const nbRanks = MpiWrapper::commSize(); + ASSERT_EQ( nbRanks, 4 ) << "This unit test cases are designed for exactly 4 ranks to check row ordering consistency."; + for( TestCase const & testCase: testCases ) { - int const rankId = MpiWrapper::commRank(); - int const nbRanks = MpiWrapper::commSize(); - ASSERT_EQ( nbRanks, 4 ) << "This unit test cases are designed for exactly 4 ranks to check row ordering consistency."; - - - TableLayout const layout = TableLayout(). setTitle( "Summary of negative pressure elements" ). addColumns( { "Global Id", "pressure [Pa]" } ). @@ -148,9 +146,9 @@ TEST( testMpiTables, testSortingMethod ) TestCase const testCase = { { // m_ranksValues: in this test, rank 2 has no value - { {2, 0.624}, {3, 0.791} }, + { {3, 0.791}, {2, 0.624}}, { {1, 0.502} }, - { {4, 0.243}, {5, 0.804}, {6, 0.302} }, + { {4, 0.243}, {6, 0.302}, {5, 0.804} }, {}, }, "\n" // m_expectedResult From a3020886d0e1f9f8c525d546844792aefec981f6 Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Mon, 30 Mar 2026 11:19:58 +0200 Subject: [PATCH 61/70] =?UTF-8?q?=F0=9F=8E=A8=20spaces?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/coreComponents/common/MpiWrapper.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/coreComponents/common/MpiWrapper.hpp b/src/coreComponents/common/MpiWrapper.hpp index 0150856e365..24f94711878 100644 --- a/src/coreComponents/common/MpiWrapper.hpp +++ b/src/coreComponents/common/MpiWrapper.hpp @@ -347,16 +347,16 @@ struct MpiWrapper stdVector< integer > offsets; }; -/** - * @brief Gather buffers of varying sizes from all ranks to rank 0. - * @tparam CONTAINER The container type holding the data. - * @tparam VALUE_T The trivially copyable underlying data type (deduced automatically). - * @param localBuffer The local buffer to be gathered on rank 0. - * @return A struct containing: - * - 'data': all the gathered data on rank 0 - * - 'counts': number of elements for each rank - * - 'offsets': starting index for each rank in 'data' - */ + /** + * @brief Gather buffers of varying sizes from all ranks to rank 0. + * @tparam CONTAINER The container type holding the data. + * @tparam VALUE_T The trivially copyable underlying data type (deduced automatically). + * @param localBuffer The local buffer to be gathered on rank 0. + * @return A struct containing: + * - 'data': all the gathered data on rank 0 + * - 'counts': number of elements for each rank + * - 'offsets': starting index for each rank in 'data' + */ template< typename CONTAINER, typename VALUE_T = typename CONTAINER::value_type, From 11812533cf91e1366862e82a56005ff5eb5234ad Mon Sep 17 00:00:00 2001 From: arng40 Date: Mon, 30 Mar 2026 17:11:47 +0200 Subject: [PATCH 62/70] :art: added boolean array for perfo availibility --- .../mesh/ElementRegionManager.cpp | 17 +++++++-- src/coreComponents/mesh/PerforationFields.hpp | 2 +- .../mesh/WellElementSubRegion.cpp | 36 +++++++++++++------ .../mesh/WellElementSubRegion.hpp | 6 ++++ 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index 4c8bc421ccf..26d6bef94ec 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -240,12 +240,23 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM TableData localPerfoData; for( globalIndex iperfLocal = 0; iperfLocal < wellSubRegionPerforationData->getNumPerforationsGlobal(); ++iperfLocal ) { - integer const cellId = wellSubRegionPerforationData->getReservoirElementGlobalIndex()[iperfLocal]; arrayView1d< globalIndex const > const globalIperf = wellSubRegionPerforationData->localToGlobalMap(); array1d< integer > localCoords; - if( cellId != -1 ) + int localPerfoInRegion = + MpiWrapper::allReduce( wellSubRegion.hasLocalPerforationInRegion( iperfLocal ), + MpiWrapper::Reduction::LogicalOr ); + + if( !localPerfoInRegion ) + { + if( MpiWrapper::commRank() == 0 ) + localPerfoData.addRow( globalIperf[iperfLocal], "globalWellElemIndices", localCoords, + "NONE", "NONE", "NONE", rankId ); + } + else if( wellSubRegion.hasLocalPerforationInRegion( iperfLocal )) { + integer const globalWellElemIndices = wellSubRegion.getGlobalWellElementIndex()[iperfLocal]; + integer const cellId = wellSubRegionPerforationData->getReservoirElementGlobalIndex()[iperfLocal]; auto const & meshElems = wellSubRegionPerforationData->getMeshElements(); localIndex const targetRegionIndex = meshElems.m_toElementRegion[iperfLocal]; localIndex const targetSubRegionIndex = meshElems.m_toElementSubRegion[iperfLocal]; @@ -254,13 +265,13 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM meshLevel.getElemManager().getRegion< ElementRegionBase >( targetRegionIndex ); ElementSubRegionBase const & subRegion = region.getSubRegion< ElementSubRegionBase >( targetSubRegionIndex ); - integer const globalWellElemIndices = wellSubRegion.getGlobalWellElementIndex()[iperfLocal]; localCoords.emplace_back( wsrPerfLocation[iperfLocal][0] ); localCoords.emplace_back( wsrPerfLocation[iperfLocal][1] ); localCoords.emplace_back( wsrPerfLocation[iperfLocal][2] ); localPerfoData.addRow( globalIperf[iperfLocal], globalWellElemIndices, localCoords, region.getName(), subRegion.getName(), cellId, rankId ); } + } integer perfoDetected = MpiWrapper::max( localPerfoData.getCellsData().size() ) > 0; diff --git a/src/coreComponents/mesh/PerforationFields.hpp b/src/coreComponents/mesh/PerforationFields.hpp index b13297d6fa1..d2490470bbc 100644 --- a/src/coreComponents/mesh/PerforationFields.hpp +++ b/src/coreComponents/mesh/PerforationFields.hpp @@ -61,7 +61,7 @@ DECLARE_FIELD( reservoirElementIndex, DECLARE_FIELD( reservoirElementGlobalIndex, "reservoirElementGlobalIndex", array1d< globalIndex >, - -1, + 0, NOPLOT, WRITE_AND_READ, "For each perforation, global element index of the perforated element" ); diff --git a/src/coreComponents/mesh/WellElementSubRegion.cpp b/src/coreComponents/mesh/WellElementSubRegion.cpp index 1cacfc95d80..442e8d1f308 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.cpp +++ b/src/coreComponents/mesh/WellElementSubRegion.cpp @@ -15,6 +15,7 @@ #include "WellElementSubRegion.hpp" +#include "common/logger/Logger.hpp" #include "mesh/MeshLevel.hpp" #include "mesh/NodeManager.hpp" #include "mesh/MeshForLoopInterface.hpp" @@ -899,6 +900,7 @@ void WellElementSubRegion::connectPerforationsToMeshElements( MeshLevel & mesh, string_array const & perfName = lineBlock.getPerfName(); string_array const & perfStatusTableName = lineBlock.getPerfStatusTableName(); m_perforationData.resize( perfCoordsGlobal.size( 0 ) ); + localPerfoInRegion.resize( perfCoordsGlobal.size( 0 ) ); localIndex iperfLocal = 0; arrayView2d< real64 > const perfLocation = m_perforationData.getLocation(); @@ -908,6 +910,7 @@ void WellElementSubRegion::connectPerforationsToMeshElements( MeshLevel & mesh, // loop over all the perforations for( globalIndex iperfGlobal = 0; iperfGlobal < perfCoordsGlobal.size( 0 ); ++iperfGlobal ) { + bool perfFoundInRegion = false; real64 const location[3] = { perfCoordsGlobal[iperfGlobal][0], perfCoordsGlobal[iperfGlobal][1], perfCoordsGlobal[iperfGlobal][2] }; @@ -917,10 +920,10 @@ void WellElementSubRegion::connectPerforationsToMeshElements( MeshLevel & mesh, localIndex erStart = -1, erEnd = -1; - localIndex const targetRegionIndex = elemManager.getRegions().getIndex( perfTargetRegionGlobal[iperfGlobal] ); - if( targetRegionIndex >= 0 ) + localIndex const knownTargetRegionIndex = elemManager.getRegions().getIndex( perfTargetRegionGlobal[iperfGlobal] ); + if( knownTargetRegionIndex >= 0 ) { - erStart = targetRegionIndex; + erStart = knownTargetRegionIndex; erEnd = erStart + 1; } else // default is all regions @@ -929,8 +932,9 @@ void WellElementSubRegion::connectPerforationsToMeshElements( MeshLevel & mesh, erEnd = elemManager.numRegions(); } + localPerfoInRegion[iperfLocal] = 0; // for each perforation, we have to find the reservoir element that contains the perforation - for( localIndex er = erStart; er < erEnd; er++ ) + for( localIndex targetRegionIndex = erStart; targetRegionIndex < erEnd; targetRegionIndex++ ) { // search for the reservoir element that contains the well element localIndex esrMatched = -1; @@ -939,17 +943,19 @@ void WellElementSubRegion::connectPerforationsToMeshElements( MeshLevel & mesh, integer const resElemFound = searchLocalElements( mesh, location, m_searchDepth, - er, + targetRegionIndex, esrMatched, eiMatched, giMatched, geomTol ); - // if the element was found + // if one rank has found the element if( resElemFound ) - { + { // if the element was found + localPerfoInRegion[iperfLocal] = true; + // set the indices for the matched reservoir element - m_perforationData.getMeshElements().m_toElementRegion[iperfLocal] = er; + m_perforationData.getMeshElements().m_toElementRegion[iperfLocal] = targetRegionIndex; m_perforationData.getMeshElements().m_toElementSubRegion[iperfLocal] = esrMatched; m_perforationData.getMeshElements().m_toElementIndex[iperfLocal] = eiMatched; m_perforationData.getReservoirElementGlobalIndex()[iperfLocal] = giMatched; @@ -965,12 +971,22 @@ void WellElementSubRegion::connectPerforationsToMeshElements( MeshLevel & mesh, // increment the local to global map m_perforationData.localToGlobalMap()[iperfLocal++] = iperfGlobal; + } - // if one rank has found the element, all ranks exit the search - if( MpiWrapper::allReduce( resElemFound, MpiWrapper::Reduction::LogicalOr )) + perfFoundInRegion = MpiWrapper::allReduce( resElemFound, MpiWrapper::Reduction::LogicalOr ); + if( perfFoundInRegion ) + { + // all ranks exit the search break; + } + } + + if( !perfFoundInRegion ) + { + GEOS_WARNING( GEOS_FMT( "Perforation {} not maching any regions", iperfGlobal )); } + //set de boolean } // set the size based on the number of perforations matched with local reservoir elements diff --git a/src/coreComponents/mesh/WellElementSubRegion.hpp b/src/coreComponents/mesh/WellElementSubRegion.hpp index 26089a42838..70cfa0d3fd8 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.hpp +++ b/src/coreComponents/mesh/WellElementSubRegion.hpp @@ -383,6 +383,10 @@ class WellElementSubRegion : public ElementSubRegionBase * @return list of indicies */ array1d< globalIndex > const & getGlobalElementIndex() const { return m_globalElementIndex; } + + integer hasLocalPerforationInRegion( integer perfoLocal ) const + { return localPerfoInRegion[perfoLocal]; } + private: /** @@ -493,6 +497,8 @@ class WellElementSubRegion : public ElementSubRegionBase /// Indices of the next well element (to reconstruct connectivity after ghost exchange) array1d< localIndex > m_nextWellElementIndexGlobal; + array1d< integer > localPerfoInRegion; + /// Local index of well's top segment localIndex m_topWellElementIndex; From 17538bd31c1a156394458ffd00e0b2d61d229b71 Mon Sep 17 00:00:00 2001 From: arng40 Date: Mon, 30 Mar 2026 18:01:44 +0200 Subject: [PATCH 63/70] :recycle: relocated in perfo data + renaming --- .../mesh/ElementRegionManager.cpp | 30 ++++++----- src/coreComponents/mesh/PerforationData.hpp | 19 +++++++ .../mesh/WellElementSubRegion.cpp | 53 +++++++++---------- .../mesh/WellElementSubRegion.hpp | 5 -- 4 files changed, 61 insertions(+), 46 deletions(-) diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index 26d6bef94ec..e14c010193c 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -235,36 +235,38 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM WellElementSubRegion const & wellSubRegion = wellRegion.getSubRegion< WellElementSubRegion >( wellRegion.getSubRegionName() ); - PerforationData const * wellSubRegionPerforationData= wellSubRegion.getPerforationData(); - arrayView2d< const real64 > wsrPerfLocation = wellSubRegionPerforationData->getLocation(); + PerforationData const * perforationData= wellSubRegion.getPerforationData(); + arrayView2d< const real64 > wsrPerfLocation = perforationData->getLocation(); TableData localPerfoData; - for( globalIndex iperfLocal = 0; iperfLocal < wellSubRegionPerforationData->getNumPerforationsGlobal(); ++iperfLocal ) + for( globalIndex iperfLocal = 0; iperfLocal < perforationData->getNumPerforationsGlobal(); ++iperfLocal ) { - arrayView1d< globalIndex const > const globalIperf = wellSubRegionPerforationData->localToGlobalMap(); + arrayView1d< globalIndex const > const globalIperf = perforationData->localToGlobalMap(); array1d< integer > localCoords; - int localPerfoInRegion = - MpiWrapper::allReduce( wellSubRegion.hasLocalPerforationInRegion( iperfLocal ), - MpiWrapper::Reduction::LogicalOr ); + bool resElemFound = + (bool)MpiWrapper::allReduce( (integer) perforationData->hasLocalPerforationInReservoir( iperfLocal ), + MpiWrapper::Reduction::LogicalOr ); - if( !localPerfoInRegion ) + integer const globalWellElemIndices = wellSubRegion.getGlobalWellElementIndex()[iperfLocal]; + + if( !resElemFound ) { if( MpiWrapper::commRank() == 0 ) - localPerfoData.addRow( globalIperf[iperfLocal], "globalWellElemIndices", localCoords, + localPerfoData.addRow( globalIperf[iperfLocal], globalWellElemIndices, localCoords, "NONE", "NONE", "NONE", rankId ); } - else if( wellSubRegion.hasLocalPerforationInRegion( iperfLocal )) + else if( perforationData->hasLocalPerforationInReservoir( iperfLocal )) { - integer const globalWellElemIndices = wellSubRegion.getGlobalWellElementIndex()[iperfLocal]; - integer const cellId = wellSubRegionPerforationData->getReservoirElementGlobalIndex()[iperfLocal]; - auto const & meshElems = wellSubRegionPerforationData->getMeshElements(); + integer const cellId = perforationData->getReservoirElementGlobalIndex()[iperfLocal]; + auto const & meshElems = perforationData->getMeshElements(); localIndex const targetRegionIndex = meshElems.m_toElementRegion[iperfLocal]; localIndex const targetSubRegionIndex = meshElems.m_toElementSubRegion[iperfLocal]; ElementRegionBase const & region = meshLevel.getElemManager().getRegion< ElementRegionBase >( targetRegionIndex ); - ElementSubRegionBase const & subRegion = region.getSubRegion< ElementSubRegionBase >( targetSubRegionIndex ); + ElementSubRegionBase const & subRegion = + region.getSubRegion< ElementSubRegionBase >( targetSubRegionIndex ); localCoords.emplace_back( wsrPerfLocation[iperfLocal][0] ); localCoords.emplace_back( wsrPerfLocation[iperfLocal][1] ); localCoords.emplace_back( wsrPerfLocation[iperfLocal][2] ); diff --git a/src/coreComponents/mesh/PerforationData.hpp b/src/coreComponents/mesh/PerforationData.hpp index d4da86d8410..db4201d3cb4 100644 --- a/src/coreComponents/mesh/PerforationData.hpp +++ b/src/coreComponents/mesh/PerforationData.hpp @@ -152,6 +152,22 @@ class PerforationData : public ObjectManagerBase */ arrayView1d< localIndex > getWellElements() { return m_wellElementIndex; } + /** + * @return an array containing the value of the local perforations connected to a reservoir element + */ + array1d< bool > & isReservoirElementFound() { return m_isReservoirElementFound; } + + /** + * @return an immutable accessor to an array containing the value of the local perforations connected to a reservoir element + */ + arrayView1d< bool const > isReservoirElementFound() const { return m_isReservoirElementFound; } + + /** + * @param perfoLocalIndex Local index of the perforation + * @return Whether the reservoir element associated with this local perforation is found. + */ + bool hasLocalPerforationInReservoir( localIndex perfoLocalIndex ) const + { return m_isReservoirElementFound[perfoLocalIndex]; } /** * @brief Provide an immutable accessor to a const perforation-to-well-element connectivity. @@ -342,6 +358,9 @@ class PerforationData : public ObjectManagerBase /// Global indices of reservoir cell containing perforation array1d< globalIndex > m_reservoirElementGlobalIndex; + /// Vector indicating if the local perforation is connected to a reservoir element + array1d< bool > m_isReservoirElementFound; + /// Location of the perforations array2d< real64 > m_location; diff --git a/src/coreComponents/mesh/WellElementSubRegion.cpp b/src/coreComponents/mesh/WellElementSubRegion.cpp index 442e8d1f308..5b64ff1ee02 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.cpp +++ b/src/coreComponents/mesh/WellElementSubRegion.cpp @@ -400,7 +400,7 @@ bool searchLocalElements( MeshLevel const & mesh, { ElementRegionBase const & region = mesh.getElemManager().getRegion< ElementRegionBase >( targetRegionIndex ); - bool resElemFound = false; + bool localResElemFound = false; for( localIndex esr = 0; esr < region.numSubRegions(); ++esr ) { ElementSubRegionBase const & subRegionBase = region.getSubRegion( esr ); @@ -447,7 +447,7 @@ bool searchLocalElements( MeshLevel const & mesh, // stop if a reservoir element containing the perforation is found // if not, enlarge the set "nodes" - resElemFound = + localResElemFound = visitNeighborElements< TYPEOFREF( subRegion ) >( mesh, location, nodes, @@ -458,9 +458,9 @@ bool searchLocalElements( MeshLevel const & mesh, giMatched, geomTol ); - if( resElemFound || nNodes == nodes.size()) + if( localResElemFound || nNodes == nodes.size()) { - if( resElemFound ) + if( localResElemFound ) { esrMatched = esr; GEOS_LOG( GEOS_FMT( " found {}/{}/{}", region.getName(), subRegion.getName(), giMatched ) ); @@ -470,13 +470,13 @@ bool searchLocalElements( MeshLevel const & mesh, } } ); - if( resElemFound ) + if( localResElemFound ) { break; } } - return resElemFound; + return localResElemFound; } } @@ -610,10 +610,10 @@ void WellElementSubRegion::assignUnownedElementsInReservoir( MeshLevel & mesh, localIndex esrMatched = -1; localIndex eiMatched = -1; globalIndex giMatched = -1; - integer const resElemFound = searchLocalElements( mesh, location, m_searchDepth, er, esrMatched, eiMatched, giMatched, geomTol ); + integer const localResElemFound = searchLocalElements( mesh, location, m_searchDepth, er, esrMatched, eiMatched, giMatched, geomTol ); // if the element was found - if( resElemFound ) + if( localResElemFound ) { // the well element is in the reservoir element (erMatched,esrMatched,eiMatched), so tag it as local localElems.insert( currGlobal ); @@ -621,7 +621,7 @@ void WellElementSubRegion::assignUnownedElementsInReservoir( MeshLevel & mesh, } // if one rank has found the element, all ranks exit the search - if( MpiWrapper::allReduce( resElemFound, MpiWrapper::Reduction::LogicalOr )) + if( MpiWrapper::allReduce( localResElemFound, MpiWrapper::Reduction::LogicalOr )) break; } } @@ -900,7 +900,7 @@ void WellElementSubRegion::connectPerforationsToMeshElements( MeshLevel & mesh, string_array const & perfName = lineBlock.getPerfName(); string_array const & perfStatusTableName = lineBlock.getPerfStatusTableName(); m_perforationData.resize( perfCoordsGlobal.size( 0 ) ); - localPerfoInRegion.resize( perfCoordsGlobal.size( 0 ) ); + m_perforationData.isReservoirElementFound().resize( perfCoordsGlobal.size( 0 ) ); localIndex iperfLocal = 0; arrayView2d< real64 > const perfLocation = m_perforationData.getLocation(); @@ -910,7 +910,7 @@ void WellElementSubRegion::connectPerforationsToMeshElements( MeshLevel & mesh, // loop over all the perforations for( globalIndex iperfGlobal = 0; iperfGlobal < perfCoordsGlobal.size( 0 ); ++iperfGlobal ) { - bool perfFoundInRegion = false; + bool globalResElemFound = false; real64 const location[3] = { perfCoordsGlobal[iperfGlobal][0], perfCoordsGlobal[iperfGlobal][1], perfCoordsGlobal[iperfGlobal][2] }; @@ -932,7 +932,7 @@ void WellElementSubRegion::connectPerforationsToMeshElements( MeshLevel & mesh, erEnd = elemManager.numRegions(); } - localPerfoInRegion[iperfLocal] = 0; + m_perforationData.isReservoirElementFound()[iperfLocal] = false; // for each perforation, we have to find the reservoir element that contains the perforation for( localIndex targetRegionIndex = erStart; targetRegionIndex < erEnd; targetRegionIndex++ ) { @@ -940,19 +940,19 @@ void WellElementSubRegion::connectPerforationsToMeshElements( MeshLevel & mesh, localIndex esrMatched = -1; localIndex eiMatched = -1; globalIndex giMatched = -1; - integer const resElemFound = searchLocalElements( mesh, - location, - m_searchDepth, - targetRegionIndex, - esrMatched, - eiMatched, - giMatched, - geomTol ); + integer const localResElemFound = searchLocalElements( mesh, + location, + m_searchDepth, + targetRegionIndex, + esrMatched, + eiMatched, + giMatched, + geomTol ); // if one rank has found the element - if( resElemFound ) + if( localResElemFound ) { // if the element was found - localPerfoInRegion[iperfLocal] = true; + m_perforationData.isReservoirElementFound()[iperfLocal] = true; // set the indices for the matched reservoir element m_perforationData.getMeshElements().m_toElementRegion[iperfLocal] = targetRegionIndex; @@ -974,15 +974,14 @@ void WellElementSubRegion::connectPerforationsToMeshElements( MeshLevel & mesh, } - perfFoundInRegion = MpiWrapper::allReduce( resElemFound, MpiWrapper::Reduction::LogicalOr ); - if( perfFoundInRegion ) - { - // all ranks exit the search + globalResElemFound |= (bool) MpiWrapper::allReduce( (integer) localResElemFound, MpiWrapper::Reduction::LogicalOr ); + if( globalResElemFound ) + { // all ranks exit the search break; } } - if( !perfFoundInRegion ) + if( !globalResElemFound ) { GEOS_WARNING( GEOS_FMT( "Perforation {} not maching any regions", iperfGlobal )); } diff --git a/src/coreComponents/mesh/WellElementSubRegion.hpp b/src/coreComponents/mesh/WellElementSubRegion.hpp index 70cfa0d3fd8..51e92f02495 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.hpp +++ b/src/coreComponents/mesh/WellElementSubRegion.hpp @@ -384,9 +384,6 @@ class WellElementSubRegion : public ElementSubRegionBase */ array1d< globalIndex > const & getGlobalElementIndex() const { return m_globalElementIndex; } - integer hasLocalPerforationInRegion( integer perfoLocal ) const - { return localPerfoInRegion[perfoLocal]; } - private: /** @@ -497,8 +494,6 @@ class WellElementSubRegion : public ElementSubRegionBase /// Indices of the next well element (to reconstruct connectivity after ghost exchange) array1d< localIndex > m_nextWellElementIndexGlobal; - array1d< integer > localPerfoInRegion; - /// Local index of well's top segment localIndex m_topWellElementIndex; From ee7d7dab6b7cabd9b591662f2a17a8b8e081ece0 Mon Sep 17 00:00:00 2001 From: arng40 Date: Tue, 31 Mar 2026 10:50:50 +0200 Subject: [PATCH 64/70] :bug: local scope for globalWellElemIndices --- src/coreComponents/mesh/ElementRegionManager.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/coreComponents/mesh/ElementRegionManager.cpp b/src/coreComponents/mesh/ElementRegionManager.cpp index e14c010193c..c92b0f7c515 100644 --- a/src/coreComponents/mesh/ElementRegionManager.cpp +++ b/src/coreComponents/mesh/ElementRegionManager.cpp @@ -243,20 +243,18 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM arrayView1d< globalIndex const > const globalIperf = perforationData->localToGlobalMap(); array1d< integer > localCoords; - bool resElemFound = - (bool)MpiWrapper::allReduce( (integer) perforationData->hasLocalPerforationInReservoir( iperfLocal ), - MpiWrapper::Reduction::LogicalOr ); - - integer const globalWellElemIndices = wellSubRegion.getGlobalWellElementIndex()[iperfLocal]; - - if( !resElemFound ) + bool const localResElementFound = perforationData->hasLocalPerforationInReservoir( iperfLocal ); + bool const globalResElemFound =(bool)MpiWrapper::allReduce( + (integer)localResElementFound, MpiWrapper::Reduction::LogicalOr ); + if( !globalResElemFound ) { if( MpiWrapper::commRank() == 0 ) - localPerfoData.addRow( globalIperf[iperfLocal], globalWellElemIndices, localCoords, + localPerfoData.addRow( globalIperf[iperfLocal], "NONE", localCoords, "NONE", "NONE", "NONE", rankId ); } - else if( perforationData->hasLocalPerforationInReservoir( iperfLocal )) + else if( localResElementFound ) { + integer const globalWellElemIndices = wellSubRegion.getGlobalWellElementIndex()[iperfLocal]; integer const cellId = perforationData->getReservoirElementGlobalIndex()[iperfLocal]; auto const & meshElems = perforationData->getMeshElements(); localIndex const targetRegionIndex = meshElems.m_toElementRegion[iperfLocal]; From dfe0619e68d6ff67b37e023956827d197ee28454 Mon Sep 17 00:00:00 2001 From: arng40 Date: Tue, 31 Mar 2026 10:51:32 +0200 Subject: [PATCH 65/70] :art: format code --- .../common/format/table/TableMpiComponents.cpp | 2 +- .../common/format/table/unitTests/testMpiTable.cpp | 2 +- src/coreComponents/mesh/PerforationData.hpp | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/coreComponents/common/format/table/TableMpiComponents.cpp b/src/coreComponents/common/format/table/TableMpiComponents.cpp index c958deb6eb4..da631658db1 100644 --- a/src/coreComponents/common/format/table/TableMpiComponents.cpp +++ b/src/coreComponents/common/format/table/TableMpiComponents.cpp @@ -80,7 +80,7 @@ void TableTextMpiFormatter::gatherAndOutputTableDataInRankOrder( std::ostream & string const rankStr = !status.m_isMasterRank && status.m_isContributing ? localStringStream.str() : ""; stdVector< string > strsAccrossRanks; - MpiWrapper::gatherStringOnRank0( rankStr, [&]( string_view str ){ + MpiWrapper::gatherStringOnRank0( rankStr, [&]( string_view str ){ status.m_hasContent = true; strsAccrossRanks.emplace_back( str ); } ); diff --git a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp index f044dc35a70..20e11600d64 100644 --- a/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp +++ b/src/coreComponents/common/format/table/unitTests/testMpiTable.cpp @@ -102,7 +102,7 @@ TEST( testMpiTables, testDifferentRankData ) int const rankId = MpiWrapper::commRank(); int const nbRanks = MpiWrapper::commSize(); ASSERT_EQ( nbRanks, 4 ) << "This unit test cases are designed for exactly 4 ranks to check row ordering consistency."; - + for( TestCase const & testCase: testCases ) { TableLayout const layout = TableLayout(). diff --git a/src/coreComponents/mesh/PerforationData.hpp b/src/coreComponents/mesh/PerforationData.hpp index db4201d3cb4..d4104d688f9 100644 --- a/src/coreComponents/mesh/PerforationData.hpp +++ b/src/coreComponents/mesh/PerforationData.hpp @@ -153,12 +153,13 @@ class PerforationData : public ObjectManagerBase arrayView1d< localIndex > getWellElements() { return m_wellElementIndex; } /** - * @return an array containing the value of the local perforations connected to a reservoir element + * @return an array containing the values of the local perforations connected to a reservoir element */ array1d< bool > & isReservoirElementFound() { return m_isReservoirElementFound; } /** - * @return an immutable accessor to an array containing the value of the local perforations connected to a reservoir element + * @return an immutable accessor to an array containing the boolean values of the local perforations + * connected to a reservoir element */ arrayView1d< bool const > isReservoirElementFound() const { return m_isReservoirElementFound; } From b962b2cb7e38eea1131230378ea72c9f4fc9ff4f Mon Sep 17 00:00:00 2001 From: arng40 Date: Tue, 31 Mar 2026 10:52:52 +0200 Subject: [PATCH 66/70] :coffin: dead code & spaces --- src/coreComponents/mesh/WellElementSubRegion.cpp | 1 - src/coreComponents/mesh/WellElementSubRegion.hpp | 1 - 2 files changed, 2 deletions(-) diff --git a/src/coreComponents/mesh/WellElementSubRegion.cpp b/src/coreComponents/mesh/WellElementSubRegion.cpp index 5b64ff1ee02..e9c4a00b7bc 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.cpp +++ b/src/coreComponents/mesh/WellElementSubRegion.cpp @@ -15,7 +15,6 @@ #include "WellElementSubRegion.hpp" -#include "common/logger/Logger.hpp" #include "mesh/MeshLevel.hpp" #include "mesh/NodeManager.hpp" #include "mesh/MeshForLoopInterface.hpp" diff --git a/src/coreComponents/mesh/WellElementSubRegion.hpp b/src/coreComponents/mesh/WellElementSubRegion.hpp index 51e92f02495..26089a42838 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.hpp +++ b/src/coreComponents/mesh/WellElementSubRegion.hpp @@ -383,7 +383,6 @@ class WellElementSubRegion : public ElementSubRegionBase * @return list of indicies */ array1d< globalIndex > const & getGlobalElementIndex() const { return m_globalElementIndex; } - private: /** From 854c07d137242abb8a9e0cdfbbcb209a17716d7e Mon Sep 17 00:00:00 2001 From: Arnaud DUDES <155963334+arng40@users.noreply.github.com> Date: Tue, 31 Mar 2026 12:50:13 +0000 Subject: [PATCH 67/70] =?UTF-8?q?=F0=9F=8E=A8=20doc=20&=20warning=20update?= =?UTF-8?q?d?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/coreComponents/mesh/PerforationData.hpp | 2 +- src/coreComponents/mesh/WellElementSubRegion.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreComponents/mesh/PerforationData.hpp b/src/coreComponents/mesh/PerforationData.hpp index d4104d688f9..4dea7d03370 100644 --- a/src/coreComponents/mesh/PerforationData.hpp +++ b/src/coreComponents/mesh/PerforationData.hpp @@ -153,7 +153,7 @@ class PerforationData : public ObjectManagerBase arrayView1d< localIndex > getWellElements() { return m_wellElementIndex; } /** - * @return an array containing the values of the local perforations connected to a reservoir element + * @return an array of booleans each value of hasLocalPerforationInReservoir() per perforation. */ array1d< bool > & isReservoirElementFound() { return m_isReservoirElementFound; } diff --git a/src/coreComponents/mesh/WellElementSubRegion.cpp b/src/coreComponents/mesh/WellElementSubRegion.cpp index e9c4a00b7bc..a8311062a62 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.cpp +++ b/src/coreComponents/mesh/WellElementSubRegion.cpp @@ -982,9 +982,9 @@ void WellElementSubRegion::connectPerforationsToMeshElements( MeshLevel & mesh, if( !globalResElemFound ) { - GEOS_WARNING( GEOS_FMT( "Perforation {} not maching any regions", iperfGlobal )); + GEOS_WARNING( GEOS_FMT( "Perforation {} not maching any regions", iperfGlobal ), + m_perforation.getName(), m_perforation.getDataContext()); } - //set de boolean } // set the size based on the number of perforations matched with local reservoir elements From 1e1176ef02253b453a299ac79c358a5e019928d1 Mon Sep 17 00:00:00 2001 From: Arnaud DUDES <155963334+arng40@users.noreply.github.com> Date: Tue, 31 Mar 2026 13:09:09 +0000 Subject: [PATCH 68/70] :bug: fix typo --- src/coreComponents/mesh/WellElementSubRegion.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreComponents/mesh/WellElementSubRegion.cpp b/src/coreComponents/mesh/WellElementSubRegion.cpp index a8311062a62..7651601f762 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.cpp +++ b/src/coreComponents/mesh/WellElementSubRegion.cpp @@ -983,7 +983,7 @@ void WellElementSubRegion::connectPerforationsToMeshElements( MeshLevel & mesh, if( !globalResElemFound ) { GEOS_WARNING( GEOS_FMT( "Perforation {} not maching any regions", iperfGlobal ), - m_perforation.getName(), m_perforation.getDataContext()); + m_perforationData.getName(), m_perforationData.getDataContext()); } } From eefa8aa83dafd0b548667c240fcad3dc9ff27a29 Mon Sep 17 00:00:00 2001 From: Arnaud DUDES <155963334+arng40@users.noreply.github.com> Date: Tue, 31 Mar 2026 13:18:22 +0000 Subject: [PATCH 69/70] :bug: fix warning --- src/coreComponents/mesh/WellElementSubRegion.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreComponents/mesh/WellElementSubRegion.cpp b/src/coreComponents/mesh/WellElementSubRegion.cpp index 7651601f762..fcb43449ace 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.cpp +++ b/src/coreComponents/mesh/WellElementSubRegion.cpp @@ -982,8 +982,8 @@ void WellElementSubRegion::connectPerforationsToMeshElements( MeshLevel & mesh, if( !globalResElemFound ) { - GEOS_WARNING( GEOS_FMT( "Perforation {} not maching any regions", iperfGlobal ), - m_perforationData.getName(), m_perforationData.getDataContext()); + GEOS_WARNING( GEOS_FMT( "Perforation {} not maching any regions", m_perforationData.getName() ), + m_perforationData.getDataContext()); } } From f83574c26c9ec37bbe3d9d8abd99bc39a2d8a984 Mon Sep 17 00:00:00 2001 From: Arnaud DUDES <155963334+arng40@users.noreply.github.com> Date: Tue, 31 Mar 2026 13:46:35 +0000 Subject: [PATCH 70/70] :art: update doc --- src/coreComponents/mesh/PerforationData.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreComponents/mesh/PerforationData.hpp b/src/coreComponents/mesh/PerforationData.hpp index 4dea7d03370..cfd06a55aae 100644 --- a/src/coreComponents/mesh/PerforationData.hpp +++ b/src/coreComponents/mesh/PerforationData.hpp @@ -153,13 +153,13 @@ class PerforationData : public ObjectManagerBase arrayView1d< localIndex > getWellElements() { return m_wellElementIndex; } /** - * @return an array of booleans each value of hasLocalPerforationInReservoir() per perforation. + * @return an array of booleans value of hasLocalPerforationInReservoir() per perforation. */ array1d< bool > & isReservoirElementFound() { return m_isReservoirElementFound; } /** - * @return an immutable accessor to an array containing the boolean values of the local perforations - * connected to a reservoir element + * @return an immutable accessor an array of booleans value of hasLocalPerforationInReservoir() + * per perforation. */ arrayView1d< bool const > isReservoirElementFound() const { return m_isReservoirElementFound; }