diff --git a/src/coreComponents/common/format/table/TableData.cpp b/src/coreComponents/common/format/table/TableData.cpp index dcbec10a01a..2354365f20f 100644 --- a/src/coreComponents/common/format/table/TableData.cpp +++ b/src/coreComponents/common/format/table/TableData.cpp @@ -87,7 +87,6 @@ TableData2D::TableDataHolder TableData2D::buildTableData( string_view targetUnit string_view columnFmt ) const { TableData2D::TableDataHolder tableData1D; - std::vector< size_t > rowsLength; tableData1D.headerNames.push_back( string( targetUnit ) ); @@ -114,8 +113,7 @@ TableData2D::TableDataHolder TableData2D::buildTableData( string_view targetUnit currentRowValues.push_back( GEOS_FMT( "{}", cellValue ) ); } - tableData1D.tableData.addRow( std::move( currentRowValues ) ); - rowsLength.push_back( currentRowValues.size() ); + tableData1D.tableData.addRow( currentRowValues ); } return tableData1D; diff --git a/src/coreComponents/common/format/table/TableFormatter.cpp b/src/coreComponents/common/format/table/TableFormatter.cpp index 56f529bdcee..992cba9b46d 100644 --- a/src/coreComponents/common/format/table/TableFormatter.cpp +++ b/src/coreComponents/common/format/table/TableFormatter.cpp @@ -13,6 +13,7 @@ * ------------------------------------------------------------------------------------------------------------ */ + /** * @file TableFormatter.cpp */ @@ -20,7 +21,9 @@ #include "TableFormatter.hpp" #include #include "common/format/StringUtilities.hpp" +#include "common/logger/Logger.hpp" #include "TableFormatter.hpp" + namespace geos { @@ -45,7 +48,7 @@ string TableCSVFormatter::headerToString() const for( std::size_t idxColumn = 0; idxColumn < m_tableLayout.getColumns().size(); ++idxColumn ) { - oss << m_tableLayout.getColumns()[idxColumn].m_parameter.columnName; + oss << m_tableLayout.getColumns()[idxColumn].column.columnName; if( idxColumn < m_tableLayout.getColumns().size() - 1 ) { oss << separator; @@ -57,7 +60,8 @@ string TableCSVFormatter::headerToString() const string TableCSVFormatter::dataToString( TableData const & tableData ) const { - std::vector< std::vector< string > > const rowsValues = tableData.getTableDataRows(); + + std::vector< std::vector< string > > const rowsValues( tableData.getTableDataRows() ); std::ostringstream oss; for( const auto & row : rowsValues ) @@ -78,14 +82,29 @@ string TableCSVFormatter::toString< TableData >( TableData const & tableData ) c ////// Log Formatter implementation /////////////////////////////////////////////////////////////////////// +void transpose( std::vector< std::vector< string > > & dest, + std::vector< std::vector< string > > const & source ) +{ + + for( size_t idxRow = 0; idxRow < source.size(); ++idxRow ) + { + GEOS_ERROR_IF( dest.size() != source[idxRow].size(), "Dest matrix must have the number of rows equal to the number of columns in the" \ + "source matrix" ); + for( size_t idxCol = 0; idxCol < source[idxRow].size(); ++idxCol ) + { + dest[idxCol][idxRow] = source[idxRow][idxCol]; + } + } +} + /** - * @brief Build cell given an alignment, a value and spaces + * @brief Build cell given an alignment, a value and spaces * @param alignment The aligment of cell value * @param value The cell value * @param spaces The number of spaces in the cell * @return A formated cell */ -string buildCell( TableLayout::Alignment const alignment, string_view value, integer const spaces ) +string buildCell( TableLayout::Alignment const alignment, string_view value, size_t const spaces ) { switch( alignment ) { @@ -97,19 +116,19 @@ string buildCell( TableLayout::Alignment const alignment, string_view value, int } /** - * @brief Detect columns who are not displayed from TableLayout and therefore modify columns / tableDataRows vectors - * @param columns Vector built in TableLayout containing all columns with their parameters + * @brief Detect tableColumnsData who are not displayed from TableLayout and therefore modify tableColumnsData / tableDataRows vectors + * @param tableColumnsData Vector built in TableLayout containing all tableColumnsData with their parameters * @param tableDataRows Vector built in TableData containing all rows values */ -void formatColumnsFromLayout( std::vector< TableLayout::Column > & columns, - std::vector< std::vector< string > > & tableDataRows ) +void updateVisibleColumns( std::vector< TableLayout::ColumnStructure > & tableColumnsData, + std::vector< std::vector< string > > & tableDataRows ) { integer idxColumn = 0; - for( auto iterColumn = columns.begin(); iterColumn!=columns.end(); ) + for( auto iterColumn = tableColumnsData.begin(); iterColumn != tableColumnsData.end(); ) { - if( !iterColumn->m_parameter.enabled ) + if( !iterColumn->column.enabled ) { - iterColumn = columns.erase( iterColumn ); + iterColumn = tableColumnsData.erase( iterColumn ); for( auto & row : tableDataRows ) { row.erase( row.begin() + idxColumn ); @@ -127,278 +146,417 @@ TableTextFormatter::TableTextFormatter( TableLayout const & tableLayout ): TableFormatter( tableLayout ) {} -void TableTextFormatter::fillTableColumnsFromRows( std::vector< TableLayout::Column > & columns, - std::vector< std::vector< string > > & rows ) const -{ - for( size_t idxRow = 0; idxRow < rows.size(); idxRow++ ) - { - if( rows[idxRow].size() < columns.size() ) - { - rows[idxRow].resize( columns.size(), " " ); - } - - for( size_t idxColumn = 0; idxColumn < columns.size(); idxColumn++ ) - { - if( m_tableLayout.getColumns()[idxColumn].m_parameter.enabled ) - { - columns[idxColumn].m_columnValues.push_back( rows[idxRow][idxColumn] ); - } - } - } -} - -string TableTextFormatter::layoutToString() const +string TableTextFormatter::toString() const { std::ostringstream tableOutput; + std::vector< TableLayout::ColumnStructure > tableColumnsData( m_tableLayout.getColumns()); + TableData tableData; string sectionSeparatingLine; - std::vector< TableLayout::Column > columns = m_tableLayout.getColumns(); + string topSeparator; + + prepareAndBuildTable( tableColumnsData, tableData, sectionSeparatingLine, topSeparator ); + + tableOutput << '\n'; + outputTitleRow( tableOutput, topSeparator ); + tableOutput << GEOS_FMT( "{}\n", sectionSeparatingLine ); + outputHeaderSectionRows( tableColumnsData, tableOutput, sectionSeparatingLine ); - outputLayout( tableOutput, columns, {}, sectionSeparatingLine ); return tableOutput.str(); } template<> string TableTextFormatter::toString< TableData >( TableData const & tableData ) const { - std::ostringstream tableOutput; + std::vector< TableLayout::ColumnStructure > tableColumnsData( m_tableLayout.getColumns()); string sectionSeparatingLine; - std::vector< TableLayout::Column > columns = m_tableLayout.getColumns(); - std::vector< std::vector< string > > tableDataRows = tableData.getTableDataRows(); - std::vector< string > const & msgTableError = tableData.getErrorMsgs(); - integer const nbValuesRows = tableDataRows.size(); + string topSeparator; - formatColumnsFromLayout( columns, tableDataRows ); - fillTableColumnsFromRows( columns, tableDataRows ); + prepareAndBuildTable( tableColumnsData, tableData, sectionSeparatingLine, topSeparator ); - outputLayout( tableOutput, columns, msgTableError, sectionSeparatingLine ); - outputSectionRows( columns, sectionSeparatingLine, tableOutput, nbValuesRows, TableLayout::Section::values ); - tableOutput << '\n'; + std::ostringstream tableOutput; + outputTable( tableOutput, tableColumnsData, sectionSeparatingLine, topSeparator ); return tableOutput.str(); } -void TableTextFormatter::outputLayout( std::ostringstream & tableOutput, - std::vector< TableLayout::Column > & columns, - std::vector< string > const & msgTableError, - string & sectionSeparatingLine ) const +void TableTextFormatter::prepareAndBuildTable( std::vector< TableLayout::ColumnStructure > & tableColumnsData, + TableData const & tableData, + string & sectionSeparatingLine, + string & topSeparator ) const { - string topSeparator; - size_t nbHeaderRows = 0; - std::vector< std::vector< string > > splitHeaders; - string const tableTitle = string( m_tableLayout.getTitle()); + std::vector< std::vector< string > > tableDataRows( tableData.getTableDataRows()); + if( !tableDataRows.empty()) + { + updateVisibleColumns( tableColumnsData, tableDataRows ); + populateColumnsFromTableData( tableColumnsData, tableDataRows ); + } - splitAndSetColumnNames( columns, nbHeaderRows, splitHeaders ); - findAndSetMaxStringSize( columns ); + std::vector< std::vector< string > > allDividedHeaderParts; + splitAndMergeColumnHeaders( tableColumnsData, allDividedHeaderParts ); - computeTableWidth( columns, msgTableError ); - buildTableSeparators( columns, topSeparator, sectionSeparatingLine ); + for( auto & tableColumnData : tableColumnsData ) + { + findAndSetLongestColumnString( tableColumnData ); + } - tableOutput << '\n'; - outputTopRows( tableOutput, {tableTitle}, topSeparator, TableLayout::Alignment::center ); - outputTopRows( tableOutput, msgTableError, topSeparator, TableLayout::Alignment::left ); + computeAndBuildTableSeparator( tableColumnsData, sectionSeparatingLine, topSeparator ); +} + +void TableTextFormatter::outputTable( std::ostringstream & tableOutput, + std::vector< TableLayout::ColumnStructure > & tableColumnsData, + string_view sectionSeparatingLine, + string_view topSeparator ) const +{ + if( m_tableLayout.isLineBreakEnabled()) + { + tableOutput << '\n'; + } + outputTitleRow( tableOutput, topSeparator ); tableOutput << GEOS_FMT( "{}\n", sectionSeparatingLine ); - outputSectionRows( columns, sectionSeparatingLine, tableOutput, nbHeaderRows, TableLayout::Section::header ); + outputHeaderSectionRows( tableColumnsData, tableOutput, sectionSeparatingLine ); + + outputValuesSectionRows( tableColumnsData, tableOutput, sectionSeparatingLine ); + if( m_tableLayout.isLineBreakEnabled()) + { + tableOutput << '\n'; + } +} + +void populateSubColumnsFromTableData( TableLayout::ColumnStructure & tableColumnData, + std::vector< std::vector< string > > const & valuesByColumn, + size_t & idxColumn ) +{ + size_t idxSubColumn = idxColumn; + for( auto & subColumn : tableColumnData.subColumn ) + { + subColumn.columnValues = valuesByColumn[idxSubColumn++]; + } + + size_t nbSubColumns = tableColumnData.column.subColumnNames.size(); + auto subColumnStartIter = valuesByColumn.begin() + idxColumn; + std::vector< std::vector< string > > valuesBySubColumn( subColumnStartIter, + subColumnStartIter + nbSubColumns ); + for( const auto & columnValues : valuesBySubColumn ) + { // add all subcolumn values in parent tableColumnData + tableColumnData.columnValues.insert( tableColumnData.columnValues.end(), + columnValues.begin(), + columnValues.end() ); + } + idxColumn += nbSubColumns; } -void TableTextFormatter::splitAndSetColumnNames( std::vector< TableLayout::Column > & columns, - size_t & nbHeaderRows, - std::vector< std::vector< string > > & splitHeaders ) const +void TableTextFormatter::populateColumnsFromTableData( std::vector< TableLayout::ColumnStructure > & tableColumnsData, + std::vector< std::vector< string > > const & tableDataRows ) const { + size_t currentColumn = 0; + std::vector< std::vector< string > > valuesByColumn( tableDataRows[0].size(), + std::vector< string >( tableDataRows.size())); - splitHeaders.reserve( columns.size() ); - for( auto const & column : columns ) + // to insert directly the values in each columns, we fill with the transposed tableDataRows (row major->column major) + transpose( valuesByColumn, tableDataRows ); + + for( auto & tableColumnData : tableColumnsData ) { - std::vector< string > splitHeaderParts; - std::istringstream ss( column.m_parameter.columnName ); - string subColumnNames; + if( tableColumnData.subColumn.empty()) + { + tableColumnData.columnValues = valuesByColumn[currentColumn++]; + } + else + { + populateSubColumnsFromTableData( tableColumnData, valuesByColumn, currentColumn ); + } + } +} + +void TableTextFormatter::splitAndMergeColumnHeaders( std::vector< TableLayout::ColumnStructure > & tableColumnsData, + std::vector< std::vector< string > > & allDividedHeaderParts ) const +{ + for( auto & tableColumnData : tableColumnsData ) + { + std::vector< string > dividedHeaderParts; + std::istringstream ss( tableColumnData.column.columnName ); + string subColumnNames; while( getline( ss, subColumnNames, '\n' )) { - splitHeaderParts.push_back( subColumnNames ); + dividedHeaderParts.push_back( subColumnNames ); } - splitHeaders.push_back( std::move( splitHeaderParts ) ); + allDividedHeaderParts.push_back( dividedHeaderParts ); + + if( !tableColumnData.subColumn.empty()) + { + std::vector< std::vector< string > > dividedSubColHeaders; + splitAndMergeColumnHeaders( tableColumnData.subColumn, dividedSubColHeaders ); + } } - nbHeaderRows = std::max_element( splitHeaders.begin(), splitHeaders.end(), - []( auto const & v1, auto const & v2 ) { return v1.size() < v2.size(); } )->size(); + size_t nbHeaderRows = std::max_element( allDividedHeaderParts.begin(), allDividedHeaderParts.end(), + []( auto const & v1, auto const & v2 ) + { + return v1.size() < v2.size(); + } )->size(); - for( auto & headerParts : splitHeaders ) + for( auto & headerDivided : allDividedHeaderParts ) { - if( headerParts.size() < nbHeaderRows ) + if( headerDivided.size() < nbHeaderRows ) { - headerParts.resize( nbHeaderRows, " " ); + headerDivided.resize( nbHeaderRows, " " ); } - columns[&headerParts - &splitHeaders[0]].m_parameter.splitColumnNameLines = headerParts; + tableColumnsData[&headerDivided - &allDividedHeaderParts[0]].column.splitColumnNames = headerDivided; } } -void TableTextFormatter::findAndSetMaxStringSize( std::vector< TableLayout::Column > & columns ) const +void TableTextFormatter::findAndSetLongestColumnString( TableLayout::ColumnStructure & tableColumnData ) const { - for( auto & column : columns ) - { - auto const maxStringSizeHeader = *std::max_element( column.m_parameter.splitColumnNameLines.begin(), - column.m_parameter.splitColumnNameLines.end(), - []( const auto & a, const auto & b ) {return a.size() < b.size();} ); - column.m_maxStringSize = maxStringSizeHeader; + size_t & maxStringSizeColumn = tableColumnData.maxStringSize; + + { // header case + auto const maxStringSizeHeader = *std::max_element( tableColumnData.column.splitColumnNames.begin(), + tableColumnData.column.splitColumnNames.end(), + []( const auto & a, const auto & b ) + { + return a.size() < b.size(); + } ); + maxStringSizeColumn = maxStringSizeHeader.length(); + } + + { // cells case + if( tableColumnData.subColumn.empty() && !tableColumnData.columnValues.empty()) + { + auto const maxStringSizeCell = *std::max_element( tableColumnData.columnValues.begin(), + tableColumnData.columnValues.end(), + []( const auto & a, const auto & b ) + { + return a.size() < b.size(); + } ); + if( maxStringSizeColumn < maxStringSizeCell.length()) + { + maxStringSizeColumn = maxStringSizeCell.length(); + } + } + } - for( auto const & cell : column.m_columnValues ) + { // subcolumn values case + size_t totalLengthSubColumns = 0; + if( !tableColumnData.subColumn.empty() ) { - if( column.m_maxStringSize.length() < cell.length()) + for( auto & subColumn : tableColumnData.subColumn ) { - column.m_maxStringSize = cell; + findAndSetLongestColumnString( subColumn ); + totalLengthSubColumns += subColumn.maxStringSize; + if( &subColumn != &tableColumnData.subColumn[0] ) + { + totalLengthSubColumns += m_tableLayout.getColumnMargin(); + } } } + + if( totalLengthSubColumns > tableColumnData.maxStringSize ) + { + tableColumnData.maxStringSize = totalLengthSubColumns; + } } + } -void TableTextFormatter::increaseColumnsSize( std::vector< TableLayout::Column > & columns, - integer const extraCharacters ) const +void TableTextFormatter::computeAndBuildTableSeparator( std::vector< TableLayout::ColumnStructure > & tableColumnsData, + string & sectionSeparatingLine, + string & topSeparator ) const { - integer const extraCharactersPerColumn = std::ceil( extraCharacters / columns.size() ); - for( std::size_t idxColumn = 0; idxColumn < columns.size(); ++idxColumn ) + integer const columnMargin = m_tableLayout.getColumnMargin(); + integer const borderMargin = m_tableLayout.getBorderMargin(); + string const tableTitle = string( m_tableLayout.getTitle() ); + + size_t const numColumns = tableColumnsData.size() - 1; + size_t const spacingBetweenColumns = numColumns * (size_t) columnMargin; + size_t const margins = (size_t) borderMargin * 2; + size_t sectionlineLength = spacingBetweenColumns + margins; + for( auto const & tableColumnData : tableColumnsData ) { - integer newMaxStringSize = extraCharactersPerColumn + columns[idxColumn].m_maxStringSize.size(); - if( idxColumn == columns.size() - 1 ) - { - newMaxStringSize += m_tableLayout.getColumnMargin(); - } + sectionlineLength += tableColumnData.maxStringSize; + } - columns[idxColumn].m_maxStringSize = GEOS_FMT( "{:>{}}", - columns[idxColumn].m_maxStringSize, - newMaxStringSize ); + size_t maxTopLineLength = tableTitle.length() + margins; + maxTopLineLength = std::max( {maxTopLineLength, sectionlineLength} ); + if( sectionlineLength < maxTopLineLength ) + { + size_t const extraCharacters = maxTopLineLength - sectionlineLength; + increaseColumnsSize( tableColumnsData, extraCharacters ); + sectionlineLength = maxTopLineLength; } + + sectionSeparatingLine = GEOS_FMT( "{:-^{}}", m_horizontalLine, sectionlineLength ); + integer const topSeparatorLength = maxTopLineLength - 2; // Adjust for border characters + topSeparator = GEOS_FMT( "{}{:-<{}}{}", m_horizontalLine, "", topSeparatorLength, m_horizontalLine ); } -void computeTableErrorLength( std::vector< string > const & msgTableError, string::size_type & msgTableErrorLength ) +void TableTextFormatter::increaseColumnsSize( std::vector< TableLayout::ColumnStructure > & tableColumnsData, + size_t const extraCharacters ) const { - if( !msgTableError.empty() ) + size_t const extraCharactersPerColumn = std::floor( (extraCharacters) / tableColumnsData.size() ); + size_t const overflowCharacters = extraCharacters - (extraCharactersPerColumn * tableColumnsData.size() ); + for( auto & tableColumnData : tableColumnsData ) { - auto maxStringSize = *(std::max_element( msgTableError.begin(), msgTableError.end(), - []( const auto & a, const auto & b ) { - return a.size() < b.size(); - } )); + if( !tableColumnData.subColumn.empty()) + { + increaseColumnsSize( tableColumnData.subColumn, extraCharactersPerColumn ); + } - msgTableErrorLength += maxStringSize.size() + 1; // max string size + line return at the end + size_t const cellSize = tableColumnData.maxStringSize; + integer const newMaxStringSize = &tableColumnData == &tableColumnsData[0] ? + extraCharactersPerColumn + cellSize + overflowCharacters : + extraCharactersPerColumn + cellSize; + tableColumnData.maxStringSize = newMaxStringSize; } } -void computeTableSectionLength( std::vector< TableLayout::Column > & columns, string::size_type & sectionlineLength ) +void TableTextFormatter::outputTitleRow( std::ostringstream & tableOutput, + string_view topSeparator ) const { - sectionlineLength += std::accumulate( columns.begin(), columns.end(), 0, - []( auto sum, const auto & column ) - { return sum + column.m_maxStringSize.length();} ); + string const tableTitle = string( m_tableLayout.getTitle()); + if( !tableTitle.empty() ) + { + tableOutput << GEOS_FMT( "{}\n", topSeparator ); + tableOutput << GEOS_FMT( "{:<{}}", m_verticalLine, m_tableLayout.getBorderMargin()); + tableOutput << buildCell( TableLayout::Alignment::center, + tableTitle, + (topSeparator.length() - (m_tableLayout.getBorderMargin() * 2))); + tableOutput << GEOS_FMT( "{:>{}}\n", m_verticalLine, m_tableLayout.getBorderMargin() ); + } } -void TableTextFormatter::computeTableWidth( std::vector< TableLayout::Column > & columns, - std::vector< string > const & msgTableError ) const +void TableTextFormatter::outputHeaderSectionRows( std::vector< TableLayout::ColumnStructure > const & tableColumnsData, + std::ostringstream & tableOutput, + string_view sectionSeparatingLine ) const { integer const columnMargin = m_tableLayout.getColumnMargin(); integer const borderMargin = m_tableLayout.getBorderMargin(); - string const tableTitle = string( m_tableLayout.getTitle() ); + string const spaces = string( columnMargin, ' ' ); + bool containSubColumn = false; + size_t nbRows = tableColumnsData[0].column.splitColumnNames.size(); + for( size_t idxRow = 0; idxRow < nbRows; ++idxRow ) + { + // Append the left border + tableOutput << GEOS_FMT( "{:<{}}", m_verticalLine, borderMargin ); - string::size_type sectionLengthWithSpacing = ( ( columns.size() - 1 ) * columnMargin ) + (borderMargin * 2); - string::size_type sectionlineLength = sectionLengthWithSpacing; - string::size_type maxTopLineLength = tableTitle.length(); - string::size_type msgTableErrorLength = borderMargin; + for( std::size_t idxColumn = 0; idxColumn < tableColumnsData.size(); ++idxColumn ) + { + auto const & tableColumnData = tableColumnsData[idxColumn]; + string const cell = tableColumnData.column.splitColumnNames.at( idxRow ); + size_t const cellSize = tableColumnData.maxStringSize; + tableOutput << buildCell( tableColumnData.column.alignmentSettings.headerAlignment, + cell, + cellSize ); + + // Add space between tableColumnsData + if( idxColumn < tableColumnsData.size() - 1 ) + { + tableOutput << GEOS_FMT( "{:^{}}", m_verticalLine, columnMargin ); + } - computeTableErrorLength( msgTableError, msgTableErrorLength ); - computeTableSectionLength( columns, sectionlineLength ); + if( !tableColumnData.subColumn.empty()) + { + containSubColumn = true; + } + } + // Append right border with line return + tableOutput << GEOS_FMT( "{:>{}}\n", m_verticalLine, borderMargin ); + } - maxTopLineLength = std::max( maxTopLineLength, msgTableErrorLength ); - if( sectionlineLength < maxTopLineLength ) + if( nbRows != 0 ) { - integer const extraCharacters = maxTopLineLength - sectionlineLength; - increaseColumnsSize( columns, extraCharacters ); + tableOutput << GEOS_FMT( "{}\n", sectionSeparatingLine ); } -} - -void TableTextFormatter::buildTableSeparators( std::vector< TableLayout::Column > const & columns, - string & topSeparator, - string & sectionSeparatingLine ) const -{ - { // section separator line - integer const columnMargin = m_tableLayout.getColumnMargin(); - integer const borderMargin = m_tableLayout.getBorderMargin(); + // Check and build subrow header + if( containSubColumn ) + { + std::vector< TableLayout::ColumnStructure > rowSubColumns; - std::vector< string > maxStringPerColumn; - for( auto const & column : columns ) + for( auto const & tableColumnData : tableColumnsData ) { - maxStringPerColumn.push_back( string( column.m_maxStringSize.length(), m_horizontalLine ) ); + if( tableColumnData.subColumn.empty()) + { + rowSubColumns.push_back( {TableLayout::Column{""}, {}, tableColumnData.maxStringSize, {}} ); + } + else + { + rowSubColumns.insert( rowSubColumns.end(), + tableColumnData.subColumn.begin(), + tableColumnData.subColumn.end()); + } } + outputHeaderSectionRows( rowSubColumns, tableOutput, sectionSeparatingLine ); - string const patternBetweenColumns = GEOS_FMT( "{:-^{}}", m_horizontalLine, columnMargin ); - - std::string const leftBorder = GEOS_FMT( "{}{:-<{}}", m_horizontalLine, "", borderMargin ); - std::string const rightBorder = GEOS_FMT( "{}{:-<{}}", m_horizontalLine, "", borderMargin ); - std::string const columnJoin = stringutilities::join( maxStringPerColumn, patternBetweenColumns ); - - std::ostringstream oss; - oss << leftBorder << columnJoin << rightBorder; - sectionSeparatingLine = oss.str(); - } - - { // top line separator - // -2 because we can have '+' to the extremity of top separator - integer const topSeparatorLength = sectionSeparatingLine.size() - 2; - topSeparator = GEOS_FMT( "{}{:-<{}}{}", m_horizontalLine, "", topSeparatorLength, m_horizontalLine ); } } -void TableTextFormatter::outputTopRows( std::ostringstream & tableOutput, - std::vector< string > const & msg, - string_view topSeparator, - TableLayout::Alignment alignment ) const +void TableTextFormatter::outputSubSection( std::vector< TableLayout::ColumnStructure > const & tableColumnsData, + std::ostringstream & tableOutput, + integer idxRow ) const { - if( msg.size() != 0 && msg[0] != "" ) + integer const columnMargin = m_tableLayout.getColumnMargin(); + for( auto const & tableColumnData : tableColumnsData ) { - tableOutput << GEOS_FMT( "{}\n", topSeparator ); - for( std::string const & str : msg ) + string const cell = tableColumnData.columnValues[idxRow]; + size_t const cellSize = tableColumnData.maxStringSize; + tableOutput << buildCell( tableColumnData.column.alignmentSettings.valueAlignment, + cell, + cellSize ); + if( &tableColumnData < &tableColumnsData.back() ) { - tableOutput << m_verticalLine << string( m_tableLayout.getBorderMargin(), ' ' ); - tableOutput << buildCell( alignment, str, (topSeparator.length() - 6)); - tableOutput << string( m_tableLayout.getBorderMargin(), ' ' ) << "|\n"; + tableOutput << GEOS_FMT( "{:^{}}", m_verticalLine, columnMargin ); } } } -void TableTextFormatter::outputSectionRows( std::vector< TableLayout::Column > const & columns, - string_view sectionSeparatingLine, - std::ostringstream & tableOutput, - integer const nbRows, - TableLayout::Section const section ) const +void TableTextFormatter::outputValuesSectionRows( std::vector< TableLayout::ColumnStructure > const & tableColumnsData, + std::ostringstream & tableOutput, + string_view sectionSeparatingLine ) const { + size_t const nbRows = tableColumnsData[0].columnValues.size(); integer const columnMargin = m_tableLayout.getColumnMargin(); integer const borderMargin = m_tableLayout.getBorderMargin(); + string const spaces = string( columnMargin - 1, ' ' ); - for( integer idxRow = 0; idxRow< nbRows; ++idxRow ) + for( size_t idxRow = 0; idxRow < nbRows; ++idxRow ) { // Append the left border - tableOutput << GEOS_FMT( "{:<{}}", m_verticalLine, 1 + borderMargin ); - for( std::size_t idxColumn = 0; idxColumn < columns.size(); ++idxColumn ) + tableOutput << GEOS_FMT( "{:<{}}", m_verticalLine, borderMargin ); + + for( std::size_t idxColumn = 0; idxColumn < tableColumnsData.size(); ++idxColumn ) { - TableLayout::Column const currentColumn = columns[idxColumn]; - auto const & columnContent = section == TableLayout::Section::header ? - columns[idxColumn].m_parameter.splitColumnNameLines : - columns[idxColumn].m_columnValues; - string cell = columnContent.at( idxRow ); - integer const cellSize = currentColumn.m_maxStringSize.length(); + auto const & tableColumnData = tableColumnsData[idxColumn]; - tableOutput << buildCell( currentColumn.m_parameter.alignment, cell, cellSize ); + if( !tableColumnData.subColumn.empty()) + { + outputSubSection( tableColumnData.subColumn, tableOutput, idxRow ); + } + else + { + string const cell = tableColumnData.columnValues.at( idxRow ); + size_t const cellSize = tableColumnData.maxStringSize; + tableOutput << buildCell( tableColumnData.column.alignmentSettings.valueAlignment, + cell, + cellSize ); + } - // Add space between column - if( idxColumn < columns.size() - 1 ) + if( idxColumn < tableColumnsData.size() - 1 ) { tableOutput << GEOS_FMT( "{:^{}}", m_verticalLine, columnMargin ); } } - // Append right border with line return - tableOutput << GEOS_FMT( "{:>{}}\n", m_verticalLine, borderMargin + 1 ); + // Append right border + tableOutput << GEOS_FMT( "{:>{}}", m_verticalLine, borderMargin ); + + + tableOutput << "\n"; + } if( nbRows != 0 ) diff --git a/src/coreComponents/common/format/table/TableFormatter.hpp b/src/coreComponents/common/format/table/TableFormatter.hpp index 165533445b6..d474b60c80a 100644 --- a/src/coreComponents/common/format/table/TableFormatter.hpp +++ b/src/coreComponents/common/format/table/TableFormatter.hpp @@ -41,7 +41,7 @@ class TableFormatter /** * @brief Construct a new Table Formatter from a tableLayout - * @param tableLayout Contain all column names and optionnaly the table title + * @param tableLayout Contain all tableColumnData names and optionnaly the table title */ TableFormatter( TableLayout const & tableLayout ); @@ -67,7 +67,7 @@ class TableCSVFormatter : public TableFormatter /** * @brief Construct a new Table Formatter from a tableLayout - * @param tableLayout Contain all column names and optionnaly the table title + * @param tableLayout Contain all tableColumnData names and optionnaly the table title */ TableCSVFormatter( TableLayout const & tableLayout ); @@ -77,7 +77,7 @@ class TableCSVFormatter : public TableFormatter virtual ~TableCSVFormatter() = default; /** - * @return The string with all column names. + * @return The string with all tableColumnData names. */ string headerToString() const; @@ -115,7 +115,6 @@ class TableTextFormatter : public TableFormatter { public: - /** * @brief Construct a new TableFormatter */ @@ -125,7 +124,7 @@ class TableTextFormatter : public TableFormatter /** * @brief Construct a new TableFormatter from a tableLayout - * @param tableLayout Contain all column names and optionnaly the table title + * @param tableLayout Contain all tableColumnData names and optionnaly the table title */ TableTextFormatter( TableLayout const & tableLayout ); @@ -136,9 +135,10 @@ class TableTextFormatter : public TableFormatter virtual ~TableTextFormatter() = default; /** - * @return A TableLayout converted into a formatted representation. + * @return A TableLayout string representation, + * The TableTextFormatter receives hasn't receive any data, so only the header part is returned. */ - string layoutToString() const; + string toString() const; /** * @brief Convert a data source to a table string. @@ -156,95 +156,113 @@ class TableTextFormatter : public TableFormatter static constexpr char m_horizontalLine = '-'; /** - * @brief Fill the vector (m_column) in tableData with values from rows stored in tableData. - * @param columns Vector of columns to be filled. + * @brief Prepare all the tableColumnsData with the appropriate values and formatting separator + * @param tableColumnsData The vector containg all tableColumnsData . Each tableColumnData contains its own + * parameters (such as name, alignment, etc.). * @param tableData Vector containing all rows filled with values + * @param sectionSeparatingLine Separator string used between sections of the table + * @param topSeparator The table top separator */ - void fillTableColumnsFromRows( std::vector< TableLayout::Column > & columns, - std::vector< std::vector< string > > & tableData ) const; + void prepareAndBuildTable( std::vector< TableLayout::ColumnStructure > & tableColumnsData, + TableData const & tableData, + string & sectionSeparatingLine, + string & topSeparator ) const; +/** + * @brief Displays the complete table + * @param tableOutput The output stream + * @param tableColumnsData Vector containg all tableColumnsData + * @param sectionSeparatingLine Separator string used between sections of the table + * @param topSeparator The table top separator + */ + void outputTable( std::ostringstream & tableOutput, + std::vector< TableLayout::ColumnStructure > & tableColumnsData, + string_view sectionSeparatingLine, + string_view topSeparator ) const; /** - * @brief Converts a TableLayout into a formatted representation. - * @param tableOutput The output stream - * @param columns The vector containing all table columns - * @param msgTableError A vector containg all error related to the table - * @param sectionSeparatingLine An empty string for building the section separator + * @brief Populate all the tableColumnData values with values extracted from TableData. + * @param tableColumnsData Vector of tableColumnsData to populate. + * @param tableData Vector containing all rows filled with values + * @param isSubColumn Boolean indicating if the current tableColumnData is a subcolumn */ - void outputLayout( std::ostringstream & tableOutput, - std::vector< TableLayout::Column > & columns, - std::vector< string > const & msgTableError, - string & sectionSeparatingLine ) const; + void populateColumnsFromTableData( std::vector< TableLayout::ColumnStructure > & tableColumnsData, + std::vector< std::vector< string > > const & tableData ) const; /** * @brief Split all header names by detecting the newline \\n character. and - * set the same vector size for each split header and merge it into columns - * @param columns The vector containg all columns - * @param largestHeaderVectorSize The largest split header vector size - * @param splitHeaders A empty vector who will contain all split header names + * set the same vector size for each divided header and merge it into tableColumnsData + * @param tableColumnsData The vector containg all tableColumnsData + * @param allDividedHeaderParts Vector to store the split header names for each tableColumnData */ - void splitAndSetColumnNames( std::vector< TableLayout::Column > & columns, - size_t & largestHeaderVectorSize, - std::vector< std::vector< string > > & splitHeaders ) const; + void splitAndMergeColumnHeaders( std::vector< TableLayout::ColumnStructure > & tableColumnsData, + std::vector< std::vector< string > > & allDividedHeaderParts ) const; /** - * @brief For each column find and set the column's longest string - * @param columns The vector containg all columns + * @brief For each tableColumnData find and set the column's longest string + * @param tableColumnData The tableColumnData to process. + * @param maxStringSize Store the longest string(s) for each tableColumnData. + * @param idxColumn The current index of the tableColumnData + * + * @note Compares the longest string from the header with the longest string from the column values. + * If the column contains subcolumns, it recursively applies the same logic to them */ - void findAndSetMaxStringSize( std::vector< TableLayout::Column > & columns ) const; + void findAndSetLongestColumnString( TableLayout::ColumnStructure & tableColumnData ) const; /** - * @brief recalculate the largest string size for each columns - * @param columns Vector containing all table columns - * @param extraCharacters Extra characters to be added to \p m_maxStringSize of each columns + * @brief Compute the max table line length, taking into account the length of : title, tableColumnsData header/values + * Increase the size of the tableColumnsData if necessary, then builds the table's separating lines + * @param tableColumnsData Vector of tableColumnData containing containing the largest string for each tableColumnData + * @param sectionSeparatingLine Separator string used between sections of the table + * @param topSeparator The table top separator */ - void increaseColumnsSize( std::vector< TableLayout::Column > & columns, - integer const extraCharacters ) const; + void computeAndBuildTableSeparator( std::vector< TableLayout::ColumnStructure > & tableColumnsData, + string & sectionSeparatingLine, + string & topSeparator ) const; /** - * @brief Compute the max table line length, taking into account the length of : title, error, columns header and content - * Increase the size of the columns if necessary - * @param columns Vector of column containing containing the largest string for each column - * @param msgTableError Vector containing all error messages + * @brief Increase each tableColumnData size if the title is larger than all the tableColumnsData + * @param tableColumnsData Vector containing all table tableColumnsData + * @param extraCharacters ExtraCharacters to be distributed between each tableColumnsData */ - void computeTableWidth( std::vector< TableLayout::Column > & columns, - std::vector< string > const & msgTableError ) const; + void increaseColumnsSize( std::vector< TableLayout::ColumnStructure > & tableColumnsData, + size_t const extraCharacters ) const; /** - * @brief Build all separators needed from content length contained in the columns vector - * @param columns Vector containing all table columns - * @param topSeparator Top separator to be built - * @param sectionSeparatingLine Line section separator to be built + * @brief Output the title row in the table + * @param topSeparator The top separator string */ - void buildTableSeparators( std::vector< TableLayout::Column > const & columns, - string & topSeparator, - string & sectionSeparatingLine ) const; + void outputTitleRow( std::ostringstream & tableOutput, + string_view topSeparator ) const; /** - * @brief Add a row on top of the table + * @brief Output the header rows in the table + * @param tableColumnsData Vector containing all table tableColumnsData * @param tableOutput The output stream - * @param msg Vector of string(s) to display - * @param topSeparator The top table separator - * @param alignment The aligment for a row + * @param sectionSeparatingLine Separator string used between sections of the table */ - void outputTopRows( std::ostringstream & tableOutput, - std::vector< string > const & msg, - string_view topSeparator, - TableLayout::Alignment alignment ) const; + void outputHeaderSectionRows( std::vector< TableLayout::ColumnStructure > const & tableColumnsData, + std::ostringstream & tableOutput, + string_view sectionSeparatingLine ) const; /** - * @brief Output a section by specifying it's type ( header or section ) - * @param columns Vector containing all table columns - * @param sectionSeparatingLine Line separator between sections - * @param rows A section row - * @param nbRows Indicates the number of lines in a section - * @param section The section to be built - * @note Add the ending line if there are one or more rows + * @brief Outputs subcolumns for the given row in the table. + * @param tableColumnsData Vector containing the subcolumn values + * @param tableOutput The output stream + * @param idxRow Index of the current row in the table + */ + void outputSubSection( std::vector< TableLayout::ColumnStructure > const & tableColumnsData, + std::ostringstream & tableOutput, + integer idxRow ) const; + + /** + * @brief Output the values rows in the table + * @param tableColumnsData Vector containing all table tableColumnsData + * @param tableOutput The output stream + * @param sectionSeparatingLine Separator string used between sections of the table */ - void outputSectionRows( std::vector< TableLayout::Column > const & columns, - string_view sectionSeparatingLine, - std::ostringstream & rows, - integer const nbRows, - TableLayout::Section const section ) const; + void outputValuesSectionRows( std::vector< TableLayout::ColumnStructure > const & tableColumnsData, + std::ostringstream & tableOutput, + string_view sectionSeparatingLine ) const; }; /** diff --git a/src/coreComponents/common/format/table/TableLayout.cpp b/src/coreComponents/common/format/table/TableLayout.cpp index 7912baa9211..1ed322c8c04 100644 --- a/src/coreComponents/common/format/table/TableLayout.cpp +++ b/src/coreComponents/common/format/table/TableLayout.cpp @@ -16,43 +16,93 @@ /** * @file TableData.hpp */ - #include "TableLayout.hpp" namespace geos { -TableLayout::TableLayout( std::vector< string > const & columnNames, string const & title ): - m_tableTitle( title ) +void TableLayout::addToColumns( const std::vector< string > & columnNames ) { - setMargin( MarginValue::medium ); - m_columns.reserve( columnNames.size() ); - for( auto const & name : columnNames ) + for( const auto & columnName : columnNames ) { - m_columns.push_back( {TableLayout::ColumnParam{{name}, Alignment::right, true}, {}, ""} ); + addToColumns( columnName ); } } -TableLayout::TableLayout( std::vector< ColumnParam > const & columnParameters, string const & title ): - m_tableTitle( title ) +void TableLayout::addToColumns( string_view columnName ) +{ + m_tableColumnsData.push_back( TableLayout::Column{ columnName } ); +} + +void TableLayout::addToColumns( Column const & column ) { - setMargin( MarginValue::medium ); - m_columns.reserve( columnParameters.size() ); - for( auto const & param : columnParameters ) + if( !column.subColumnNames.empty()) { - m_columns.push_back( { param, {}, ""} ); + std::vector< TableLayout::ColumnStructure > subColumns; + for( const auto & subColumnsName : column.subColumnNames ) + { + subColumns.push_back( + TableLayout::ColumnStructure { + TableLayout::Column{ subColumnsName, column.alignmentSettings.headerAlignment } + } ); + } + m_tableColumnsData.push_back( TableLayout::ColumnStructure { column, subColumns } ); + } + else + { + m_tableColumnsData.push_back( TableLayout::ColumnStructure { column } ); } } -void TableLayout::setMargin( MarginValue marginValue ) +TableLayout & TableLayout::setTitle( string_view title ) { - m_borderMargin = marginValue; + m_tableTitle = title; + return *this; +} + +TableLayout & TableLayout::disableLineBreak() +{ + m_wrapLine = false; + return *this; +} + +TableLayout & TableLayout::setMargin( MarginValue marginValue ) +{ + m_marginValue = marginValue; + m_borderMargin = marginValue + 1; // margin + border character m_columnMargin = integer( marginValue ) * 2 + 1; + + return *this; +} + +TableLayout & TableLayout::setValuesAlignment( TableLayout::Alignment alignment ) +{ + for( auto & tableColumnData : m_tableColumnsData ) + { + tableColumnData.column.alignmentSettings.valueAlignment = alignment; + } + return *this; +} + +bool TableLayout::isLineBreakEnabled() const +{ + return m_wrapLine; } -std::vector< TableLayout::Column > const & TableLayout::getColumns() const +void TableLayout::removeSubColumn() { - return m_columns; + for( auto & column : m_tableColumnsData ) + { + if( !column.subColumn.empty() ) + { + column.subColumn.clear(); + } + } +} + +std::vector< TableLayout::ColumnStructure > const & TableLayout::getColumns() const +{ + return m_tableColumnsData; } string_view TableLayout::getTitle() const @@ -60,7 +110,6 @@ string_view TableLayout::getTitle() const return m_tableTitle; } - integer const & TableLayout::getBorderMargin() const { return m_borderMargin; @@ -71,6 +120,11 @@ integer const & TableLayout::getColumnMargin() const return m_columnMargin; } +integer const & TableLayout::getMarginValue() const +{ + return m_marginValue; +} + integer const & TableLayout::getMarginTitle() const { return m_titleMargin; diff --git a/src/coreComponents/common/format/table/TableLayout.hpp b/src/coreComponents/common/format/table/TableLayout.hpp index 4f24fa5559c..eb2d280c619 100644 --- a/src/coreComponents/common/format/table/TableLayout.hpp +++ b/src/coreComponents/common/format/table/TableLayout.hpp @@ -21,6 +21,7 @@ #define GEOS_COMMON_FORMAT_TABLE_TABLELAYOUT_HPP #include "common/DataTypes.hpp" +#include namespace geos { @@ -51,73 +52,197 @@ class TableLayout enum Section { header, values }; /** - * @brief Structure to set up each colum parameters. + * @brief Structure to set up values alignment for each colum. */ - struct ColumnParam + struct ColumnAlignment + { + /// Alignment for column name. By default aligned to center + Alignment headerAlignment = Alignment::center; + /// Alignment for column values. By default aligned to right side + Alignment valueAlignment = Alignment::right; + }; + + /** + * @brief Structure to set up each colum. + */ + struct Column { /// Name for a column string columnName; - /// Alignment for a column. By default aligned to the right side - Alignment alignment = Alignment::right; + /// Alignment for column name. By default aligned to center + ColumnAlignment alignmentSettings; /// A boolean to display a colummn bool enabled = true; + /// Vector containing sub columns name + std::vector< string > subColumnNames; /// Vector containing substring column name delimited by "\n" - std::vector< string > splitColumnNameLines; + std::vector< string > splitColumnNames = {""}; + + /** + * @brief Construct a Column object with the given parameters + * @param name The Column name + */ + Column( string_view name ) + : columnName( name ) + {} + + /** + * @brief Construct a Column object with the given parameters + * @param name The Column name + * @param headerAlign The column name alignment + */ + Column( string_view name, Alignment headerAlign ) + : columnName( name ), alignmentSettings( {headerAlign, Alignment::right} ) + {} /** - * @brief Construct a ColumnParam object with the specified name and alignment. - * @param name The name of the column - * @param align The alignment of the column + * @brief Construct a Column object with the given parameters + * @param name The Column name + * @param subColumnNamesInit Vector containing subcolumn names */ - ColumnParam( std::string const & name, Alignment align ) - : columnName( name ), alignment( align ) + Column( string_view name, std::vector< string > && subColumnNamesInit ) + : columnName( name ), subColumnNames( subColumnNamesInit ) {} /** - * @brief Construct a ColumnParam object with the specified name, alignment, and display flag. - * @param name The name of the column - * @param align The alignment of the column + * @brief Construct a Column object with the given parameters + * @param name The Column name + * @param headerAlign The column name alignment * @param display Flag indicating whether the column is enabled */ - ColumnParam( std::string const & name, Alignment align, bool display ) - : columnName( name ), alignment( align ), enabled( display ) + Column( string_view name, Alignment headerAlign, bool display ) + : columnName( name ), + alignmentSettings( {headerAlign, Alignment::right} ), + enabled( display ) + {} + + /** + * @brief Construct a Column object with the given parameters + * @param name The Column name + * @param headerAlign The column name alignment + * @param display Flag indicating whether the column is enabled + * @param subColumnNamesInit Vector containing subcolumn names + */ + Column( string_view name, Alignment headerAlign, bool display, std::vector< string > && subColumnNamesInit ) + : columnName( name ), + alignmentSettings( {headerAlign, Alignment::right} ), + enabled( display ), + subColumnNames( subColumnNamesInit ) {} }; /** - * @brief Struct for a column. + * @brief Struct for a ColumnStructure. + * Each column contains its own parameters (such as name, alignment, etc.). */ - struct Column + struct ColumnStructure { /// Structure who contains parameters for a column - ColumnParam m_parameter; - /// A vector containing all column values - std::vector< string > m_columnValues; - /// The largest string in the column - string m_maxStringSize; + Column column; + /// A vector containing all the values of a column + std::vector< string > columnValues; + /// Vector of string containing the largest string for a column and its subColumns + size_t maxStringSize; + /// Vector containing all sub columns subdivison + std::vector< ColumnStructure > subColumn; + + /** + * @brief Constructs a ColumnStructure with the given column. + * @param col The parameters for the column. + */ + ColumnStructure ( Column col ) + : column( col ) + {} + + /** + * @brief Constructs a ColumnStructure with the given parameters. + * @param col The parameters for the column. + * @param subColumnInit The subcolumns contained in the colum + */ + ColumnStructure ( Column col, std::vector< ColumnStructure > const & subColumnInit ) + : column( col ), subColumn( subColumnInit ) + {} + + /** + * @brief Constructs a ColumnStructure with the given parameters. + * @param col The parameters for the column. + * @param columnValuesInit The values in the column. + * @param maxStringSizeInit The largest string(s) in the column. + * @param subColumnInit The sub-columns of the column. + */ + ColumnStructure ( Column const & col, + std::vector< string > const & columnValuesInit, + size_t const maxStringSizeInit, + std::vector< ColumnStructure > const & subColumnInit ) + : column( col ), + columnValues( columnValuesInit ), + maxStringSize( maxStringSizeInit ), + subColumn( subColumnInit ) + {} }; + /// Alias for an initializer list of variants that can contain either a string or a layout column. + using TableLayoutArgs = std::initializer_list< std::variant< string_view, TableLayout::Column > >; + TableLayout() = default; /** - * @brief Construct a new Table object, all values in the table are centered by default - * @param columnNames The names of the columns - * @param title The table name + * @brief Construct a new Table Layout object + * @param title The table title + * @param columns A vector containing all column initialized */ - TableLayout( std::vector< string > const & columnNames, string const & title = "" ); + TableLayout( string_view title, + std::vector< TableLayout::Column > & columns ) + { + setMargin( MarginValue::medium ); + setTitle( title ); + for( auto const & column :columns ) + { + addToColumns( column ); + } + } + + /** + * @brief Construct a new Table Layout object + * @param title The table title + * @param args An initializer_list containing string / column + */ + TableLayout( string_view title, + TableLayoutArgs args ) + { + setMargin( MarginValue::medium ); + setTitle( title ); + processArguments( args ); + } + + /** + * @brief Construct a new Table Layout object + * @param args An initializer_list containing string / column + */ + + TableLayout( TableLayoutArgs args ) + { + setMargin( MarginValue::medium ); + processArguments( args ); + } /** - * @brief Construct a new Table object by specifying value alignment and optionally their displays based to log levels - * level - * @param columnParameters List of structures to set up each colum parameters. - * @param title The table name + * @brief Construct a new Table Layout object + * @param title The table title + * @param args An initializer_list containing string / column */ - TableLayout( std::vector< ColumnParam > const & columnParameters, string const & title = "" ); + TableLayout( string_view title, + std::vector< string > args ) + { + setMargin( MarginValue::medium ); + setTitle( title ); + addToColumns( args ); + } /** * @return The columns vector */ - std::vector< Column > const & getColumns() const; + std::vector< ColumnStructure > const & getColumns() const; /** * @return The table name @@ -125,32 +250,114 @@ class TableLayout string_view getTitle() const; /** - * @return The border margin, number of spaces at both left and right table sides + * @param title The table title + * @return The tableLayout reference + */ + TableLayout & setTitle( string_view title ); + + /** + * @brief Remove the return line at the end & begenning of the table + * @return The tableLayout reference + */ + TableLayout & disableLineBreak(); + + /** + * @brief Set the minimal margin width between cell content and borders. + * @param marginValue The margin value + * @return The tableLayout reference + */ + TableLayout & setMargin( MarginValue marginValue ); + + /** + * @brief Set the column values alignment + * @param alignment column values alignment + * @return The tableLayout reference + */ + TableLayout & setValuesAlignment( TableLayout::Alignment alignment ); + + /** + * @return check if the line break at the end & beginning is activated + */ + bool isLineBreakEnabled() const; + + /** + * @brief Remove all subcolumn in all columns + * Can be used if we want to reuse a TableLayout without keep subcolumns + */ + void removeSubColumn(); + + /** + * @return The border margin, number of spaces at both left and right table sides plus vertical character */ integer const & getBorderMargin() const; /** - * @return The column margin, numbers of spaces separating both left and right side from each column content + * @return The column margin, numbers of spaces separating both left and right side from a vertical line */ integer const & getColumnMargin() const; + /** + * @return The table margin value + */ + integer const & getMarginValue() const; + /** * @return The margin title */ integer const & getMarginTitle() const; +private: + /** - * @brief Set the minimal margin width between cell content and borders. - * @param marginValue The margin value + * @brief Add a column to the table given an initializer_list of string & ColumnStructure + * @param args An initializer_list containing string / column */ - void setMargin( MarginValue marginValue ); + void processArguments( TableLayoutArgs args ) + { + for( auto const & arg : args ) + { + std::visit( [this]( auto const & value ) { + addToColumns( value ); + }, arg ); + } + } -private: + /** + * @brief Recursively processes a variable number of arguments and adds them to the table data. + * @tparam Ts The remaining arguments + * @param args The remaining arguments to be processed + */ + template< typename ... Ts > + void processArguments( Ts &... args ) + { + addToColumns( args ... ); + } + + /** + * @brief Create and add columns to the columns vector given a string vector + * @param columnNames The columns name + */ + void addToColumns( std::vector< string > const & columnNames ); + + /** + * @brief Create and add a column to the columns vector given a string + * @param columnName The column name + */ + void addToColumns( 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 + */ + void addToColumns( Column const & column ); + + std::vector< ColumnStructure > m_tableColumnsData; - std::vector< Column > m_columns; + bool m_wrapLine = true; string m_tableTitle; integer m_borderMargin; integer m_columnMargin; + integer m_marginValue; integer m_titleMargin = 2; }; diff --git a/src/coreComponents/common/format/table/unitTests/testTable.cpp b/src/coreComponents/common/format/table/unitTests/testTable.cpp index 3663b5eae22..b56b3777c94 100644 --- a/src/coreComponents/common/format/table/unitTests/testTable.cpp +++ b/src/coreComponents/common/format/table/unitTests/testTable.cpp @@ -27,13 +27,12 @@ using namespace geos; TEST( testTable, tableEmptyRow ) { //table with empty row - TableLayout const tableLayout( {"Well\nelement no.\nPV weighted\nbar", + TableLayout const tableLayout( "InternalWellGenerator well_injector1", + {"Well\nelement no.\nPV weighted\nbar", "CordX", "CoordZ", "Prev\nelement", - "Next\nelement"}, - "InternalWellGenerator well_injector1" - ); + "Next\nelement"} ); TableData tableData; tableData.addRow( "value1", "[30.21543]", "3.0", 54, 0 ); @@ -47,10 +46,10 @@ TEST( testTable, tableEmptyRow ) "\n-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n" "| InternalWellGenerator well_injector1 |\n" "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n" - "| Well | CordX | CoordZ | Prev | Next |\n" - "| element no. | | | element | element |\n" - "| PV weighted | | | | |\n" - "| bar | | | | |\n" + "| Well | CordX | CoordZ | Prev | Next |\n" + "| element no. | | | element | element |\n" + "| PV weighted | | | | |\n" + "| bar | | | | |\n" "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n" "| value1 | [30.21543] | 3.0 | 54 | 0 |\n" "| | | | | |\n" @@ -61,11 +60,12 @@ TEST( testTable, tableEmptyRow ) TEST( testTable, tableClassic ) { - TableLayout const tableLayout( {"Duis fringilla, ligula sed porta fringilla,\nligula wisi commodo felis,ut adipiscing felis dui in enim. Suspendisse malesuada ultrices ante", + TableLayout const tableLayout( "InternalWellGenerator well_injector1", + {"Duis fringilla, ligula sed porta fringilla,\nligula wisi commodo felis,ut adipiscing felis dui in enim. Suspendisse malesuada ultrices ante", "CordX", "CoordZ", "Prev\nelement", - "Next\nelement"}, "InternalWellGenerator well_injector1" ); + "Next\nelement"} ); TableData tableData; tableData.addRow( "value1", "[30.21543]", "3.0", 54, 0 ); @@ -77,7 +77,7 @@ TEST( testTable, tableClassic ) "\n-----------------------------------------------------------------------------------------------------------------------------------------------------------\n" "| InternalWellGenerator well_injector1 |\n" "-----------------------------------------------------------------------------------------------------------------------------------------------------------\n" - "| Duis fringilla, ligula sed porta fringilla, | CordX | CoordZ | Prev | Next |\n" + "| Duis fringilla, ligula sed porta fringilla, | CordX | CoordZ | Prev | Next |\n" "| ligula wisi commodo felis,ut adipiscing felis dui in enim. Suspendisse malesuada ultrices ante | | | element | element |\n" "-----------------------------------------------------------------------------------------------------------------------------------------------------------\n" "| value1 | [30.21543] | 3.0 | 54 | 0 |\n" @@ -87,16 +87,15 @@ TEST( testTable, tableClassic ) ); } -TEST( testTable, tableColumnParamClassic ) +TEST( testTable, tableColumnParamClassic ) //TODO { - TableLayout const tableLayout( { - TableLayout::ColumnParam{{"Cras egestas"}, TableLayout::Alignment::center}, - TableLayout::ColumnParam{{"CoordX"}, TableLayout::Alignment::left}, - TableLayout::ColumnParam{{"C"}, TableLayout::Alignment::left}, - TableLayout::ColumnParam{{"CoordZ"}, TableLayout::Alignment::left}, - TableLayout::ColumnParam{{"Prev\nelement"}, TableLayout::Alignment::right}, - TableLayout::ColumnParam{{"Next\nelement"}, TableLayout::Alignment::right} - }, "InternalWellGenerator well_injector1" ); + TableLayout tableLayout( {TableLayout::Column{{"Cras egestas"}, TableLayout::Alignment::center}, + TableLayout::Column{{"CoordX"}, TableLayout::Alignment::left}, + TableLayout::Column{{"C"}, TableLayout::Alignment::left}, + TableLayout::Column{{"CoordZ"}, TableLayout::Alignment::left}, + TableLayout::Column{{"Prev\nelement"}, TableLayout::Alignment::right}, + TableLayout::Column{{"Next\nelement"}, TableLayout::Alignment::right}} ); + tableLayout.setValuesAlignment( TableLayout::Alignment::right ); TableData tableData; tableData.addRow( "value1", " ", "3.0", 3.0129877, 2.0f, 1 ); @@ -105,27 +104,26 @@ TEST( testTable, tableColumnParamClassic ) TableTextFormatter const tableText( tableLayout ); EXPECT_EQ( tableText.toString( tableData ), "\n-------------------------------------------------------------------------------------------\n" - "| InternalWellGenerator well_injector1 |\n" - "-------------------------------------------------------------------------------------------\n" "| Cras egestas | CoordX | C | CoordZ | Prev | Next |\n" "| | | | | element | element |\n" "-------------------------------------------------------------------------------------------\n" - "| value1 | | 3.0 | 3.0129877 | 2 | 1 |\n" - "| val1 | v | [3.045,42.02,89.25] | 3 | 10 | 3 |\n" + "| value1 | | 3.0 | 3.0129877 | 2 | 1 |\n" + "| val1 | v | [3.045,42.02,89.25] | 3 | 10 | 3 |\n" "-------------------------------------------------------------------------------------------\n\n" ); } -TEST( testTable, tableHiddenColumn ) +TEST( testTable, tableHiddenColumn ) // TODO { - TableLayout const tableLayout( { - TableLayout::ColumnParam{{"Cras egestas"}, TableLayout::Alignment::center}, - TableLayout::ColumnParam{{"CoordX"}, TableLayout::Alignment::right}, - TableLayout::ColumnParam{{"C"}, TableLayout::Alignment::center}, - TableLayout::ColumnParam{{"CoordZ"}, TableLayout::Alignment::left}, - TableLayout::ColumnParam{{"Prev\nelement"}, TableLayout::Alignment::left, false}, - TableLayout::ColumnParam{{"Next\nelement"}, TableLayout::Alignment::center, false}, - }, "Cras egestas ipsum a nisl. Vivamus variu dolor utsisicdis parturient montes, nascetur ridiculus mus. Duis" ); + string const title = "Cras egestas ipsum a nisl. Vivamus variu dolor utsisicdis parturient montes, nascetur ridiculus mus. Duis"; + TableLayout tableLayout( title, + {TableLayout::Column{{"Cras egestas"}, TableLayout::Alignment::center}, + TableLayout::Column{{"CoordX"}, TableLayout::Alignment::right}, + TableLayout::Column{{"C"}, TableLayout::Alignment::center}, + TableLayout::Column{{"CoordZ"}, TableLayout::Alignment::left}, + TableLayout::Column{{"Prev\nelement"}, TableLayout::Alignment::left, false}, + TableLayout::Column{{"Next\nelement"}, TableLayout::Alignment::center, false}} ); + tableLayout.setValuesAlignment( TableLayout::Alignment::left ); TableData tableData; tableData.addRow( "value1", " ", "3.0", 3.0129877, 2.0f, 1 ); @@ -133,21 +131,20 @@ TEST( testTable, tableHiddenColumn ) TableTextFormatter const tableText( tableLayout ); EXPECT_EQ( tableText.toString( tableData ), - "\n----------------------------------------------------------------------------------------------------------------\n" - "| Cras egestas ipsum a nisl. Vivamus variu dolor utsisicdis parturient montes, nascetur ridiculus mus. Duis |\n" - "----------------------------------------------------------------------------------------------------------------\n" - "| Cras egestas | CoordX | C | CoordZ |\n" - "----------------------------------------------------------------------------------------------------------------\n" - "| value1 | | 3.0 | 3.0129877 |\n" - "| val1 | v | [3.045,42.02,89.25] | 3 |\n" - "----------------------------------------------------------------------------------------------------------------\n\n" ); + "\n---------------------------------------------------------------------------------------------------------------\n" + "| Cras egestas ipsum a nisl. Vivamus variu dolor utsisicdis parturient montes, nascetur ridiculus mus. Duis |\n" + "---------------------------------------------------------------------------------------------------------------\n" + "| Cras egestas | CoordX | C | CoordZ |\n" + "---------------------------------------------------------------------------------------------------------------\n" + "| value1 | | 3.0 | 3.0129877 |\n" + "| val1 | v | [3.045,42.02,89.25] | 3 |\n" + "---------------------------------------------------------------------------------------------------------------\n\n" ); } TEST( testTable, tableUniqueColumn ) { - TableLayout const tableLayout( { - TableLayout::ColumnParam{{"Cras egestas"}, TableLayout::Alignment::center}, - }, "Cras egestas ipsu a nisl. Vivamus variu dolor utsisicdis parturient montes, nascetur ridiculus mus. Duis" ); + string const title = "Cras egestas ipsum a nisl. Vivamus variu dolor utsisicdis parturient montes, nascetur ridiculus mus. Duis"; + TableLayout const tableLayout( title, {TableLayout::Column{{"Cras egestas"}, TableLayout::Alignment::center}} ); TableData tableData; tableData.addRow( "value1" ); @@ -156,26 +153,23 @@ TEST( testTable, tableUniqueColumn ) TableTextFormatter const tableText( tableLayout ); EXPECT_EQ( tableText.toString( tableData ), "\n---------------------------------------------------------------------------------------------------------------\n" - "| Cras egestas ipsu a nisl. Vivamus variu dolor utsisicdis parturient montes, nascetur ridiculus mus. Duis |\n" + "| Cras egestas ipsum a nisl. Vivamus variu dolor utsisicdis parturient montes, nascetur ridiculus mus. Duis |\n" "---------------------------------------------------------------------------------------------------------------\n" "| Cras egestas |\n" "---------------------------------------------------------------------------------------------------------------\n" - "| value1 |\n" - "| val1 |\n" + "| value1 |\n" + "| val1 |\n" "---------------------------------------------------------------------------------------------------------------\n\n" ); } TEST( testTable, tableEmptyTitle ) { - TableLayout const tableLayout( { - TableLayout::ColumnParam{{"Cras egestas"}, TableLayout::Alignment::center}, - TableLayout::ColumnParam{{"CoordX"}, TableLayout::Alignment::right}, - TableLayout::ColumnParam{{"C"}, TableLayout::Alignment::center}, - TableLayout::ColumnParam{{"CoordZ"}, TableLayout::Alignment::left}, - TableLayout::ColumnParam{{"Prev\nelement"}, TableLayout::Alignment::left}, - TableLayout::ColumnParam{{"Next\nelement"}, TableLayout::Alignment::center}, - } - ); + TableLayout const tableLayout( {TableLayout::Column{{"Cras egestas"}, TableLayout::Alignment::center}, + TableLayout::Column{{"CoordX"}, TableLayout::Alignment::right}, + TableLayout::Column{{"C"}, TableLayout::Alignment::center}, + TableLayout::Column{{"CoordZ"}, TableLayout::Alignment::left}, + TableLayout::Column{{"Prev\nelement"}, TableLayout::Alignment::left}, + TableLayout::Column{{"Next\nelement"}, TableLayout::Alignment::center}} ); TableData tableData; tableData.addRow( "value1", " ", "3.0", 3.0129877, 2.0f, 1 ); @@ -187,8 +181,8 @@ TEST( testTable, tableEmptyTitle ) "| Cras egestas | CoordX | C | CoordZ | Prev | Next |\n" "| | | | | element | element |\n" "-------------------------------------------------------------------------------------------\n" - "| value1 | | 3.0 | 3.0129877 | 2 | 1 |\n" - "| val1 | v | [3.045,42.02,89.25] | 3 | 10 | 3 |\n" + "| value1 | | 3.0 | 3.0129877 | 2 | 1 |\n" + "| val1 | v | [3.045,42.02,89.25] | 3 | 10 | 3 |\n" "-------------------------------------------------------------------------------------------\n\n" ); } @@ -215,13 +209,13 @@ TEST( testTable, table2DTable ) columnFmt ); //format - TableLayout const tableLayout( tableconverted.headerNames ); + TableLayout const tableLayout( "", tableconverted.headerNames ); //log - TableTextFormatter const tableLog( tableLayout ); - EXPECT_EQ( tableLog.toString( tableconverted.tableData ), + TableTextFormatter const tableText( tableLayout ); + EXPECT_EQ( tableText.toString( tableconverted.tableData ), "\n---------------------------------------------------------------------\n" - "| Viscosity kg*s | Pression = 10000 | Pression = 15000 |\n" + "| Viscosity kg*s | Pression = 10000 | Pression = 15000 |\n" "---------------------------------------------------------------------\n" "| Temperature = 300 | 0.03 | 0.02 |\n" "| Temperature = 350 | 0.035 | 0.023333333333333334 |\n" @@ -230,56 +224,14 @@ TEST( testTable, table2DTable ) ); } - -TEST( testTable, table2DColumnMismatch ) -{ - //test 2D table column mismatch - { - // collect - TableData2D tableData; - - tableData.addCell( 300, 10000, 0.03 ); - tableData.addCell( 300, 15000, 0.02 ); - tableData.addCell( 350, 10000, 0.035 ); - tableData.addCell( 350, 10000, 0.035 ); - tableData.addCell( 400, 10000, 0.04 ); - tableData.addCell( 400, 15000, 0.02666666666666667 ); - - //convert - string const rowFmt = GEOS_FMT( "{} = {{}}", "Temperature" ); - string const columnFmt = GEOS_FMT( "{} = {{}}", "Pression" ); - TableData2D::TableDataHolder tableConverted = tableData.buildTableData( "Viscosity kg*s", - rowFmt, - columnFmt ); - - //format - TableLayout const tableLayout( tableConverted.headerNames ); - - //log - TableTextFormatter const tableLog( tableLayout ); - EXPECT_EQ( tableLog.toString( tableConverted.tableData ), - "\n--------------------------------------------------------------------\n" - "| Remarks : some cells may be missing |\n" - "--------------------------------------------------------------------\n" - "| Viscosity kg*s | Pression = 10000 | Pression = 15000 |\n" - "--------------------------------------------------------------------\n" - "| Temperature = 300 | 0.03 | 0.02 |\n" - "| Temperature = 350 | 0.035 | |\n" - "| Temperature = 400 | 0.04 | 0.02666666666666667 |\n" - "--------------------------------------------------------------------\n\n" - ); - } -} - TEST( testTable, layoutTable ) { string filename = "fluid1_phaseModel1_PhillipsBrineDensity_table"; - string log = GEOS_FMT( "The {} PVT table exceeding 500 rows.\nTo visualize the tables, go to the generated csv \n", filename ); - TableLayout const tableLayoutInfos( {TableLayout::ColumnParam{{log}, TableLayout::Alignment::left}}, filename ); + TableLayout const tableLayoutInfos( filename, {TableLayout::Column{{log}, TableLayout::Alignment::left}} ); - TableTextFormatter const tableLog( tableLayoutInfos ); - EXPECT_EQ( tableLog.layoutToString(), + TableTextFormatter const tableText( tableLayoutInfos ); + EXPECT_EQ( tableText.toString(), "\n-------------------------------------------------------------------------------------\n" "| fluid1_phaseModel1_PhillipsBrineDensity_table |\n" "-------------------------------------------------------------------------------------\n" @@ -289,41 +241,85 @@ TEST( testTable, layoutTable ) ); } -TEST( testTable, tableSetMargin ) +TEST( testTable, subColumns ) { - //////////// - //////// If setMargin used elsewhere make it public and remove comments for this test - //////////// - //test with tiny margin - // { - // TableLayout tableLayout( { - // TableLayout::ColumnParam{{"Colonne 1"}, TableLayout::Alignment::center}, - // TableLayout::ColumnParam{{"Colonne 2"}, TableLayout::Alignment::center}, - // TableLayout::ColumnParam{{"Colonne 3"}, TableLayout::Alignment::right}, - // TableLayout::ColumnParam{{"Colonne 4"}, TableLayout::Alignment::right}, - // TableLayout::ColumnParam{{"Prev\nelement"}, TableLayout::Alignment::right}, - // TableLayout::ColumnParam{{"Next\nelement"}, TableLayout::Alignment::right}, - // }, "InternalWellGenerator well_injector1" ); - - // //tableLayout.setMargin( TableLayout::MarginValue::tiny ); - - // TableData tableData; - // tableData.addRow( "value 1", "long value 1", "3.0034", 3.0129877, "" , 1 ); - // tableData.addRow( "value 1", "long value 2", "100.45", 4.0129877, 1 , 2 ); - - // TableTextFormatter const tableText( tableLayout ); - // EXPECT_EQ( tableText.toString( tableData ), -// "\n------------------------------------------------------------\n" -// "| InternalWellGenerator well_injector1 |\n" -// "------------------------------------------------------------\n" -// "|Colonne 1| Colonne 2 |Colonne 3|Colonne 4| Prev| Next|\n" -// "| | | | |element|element|\n" -// "------------------------------------------------------------\n" -// "| value 1 |long value 1| 3.0034|3.0129877| | 1|\n" -// "| value 1 |long value 2| 100.45|4.0129877| 1| 2|\n" -// "------------------------------------------------------------\n\n" -// ); -// } + { + TableLayout const tableLayout( { + " ", + "Column1", + TableLayout::Column{"Nodes", TableLayout::Alignment::right, true, {"Locales", "Ghost", "Active"}}, + "Column3", + TableLayout::Column{"Column4", TableLayout::Alignment::right, true, {"Locales", "Ghost"}}, + "Column5"} ); + + TableData tableData; + tableData.addRow( "min", "125", "375,0001", " YES", 2354654, 562, 43.0, 43.0, 562, 5 ); + tableData.addRow( "max", "360", "390,1", " YES", 383213213, 712, 48.0, 47.0, 72, 2 ); + + TableTextFormatter tableText( tableLayout ); + EXPECT_EQ( tableText.toString( tableData ), + "\n--------------------------------------------------------------------------------------------------------\n" + "| | Column1 | Nodes | Column3 | Column4 | Column5 |\n" + "--------------------------------------------------------------------------------------------------------\n" + "| | | Locales | Ghost | Active | | Locales | Ghost | |\n" + "--------------------------------------------------------------------------------------------------------\n" + "| min | 125 | 375,0001 | YES | 2354654 | 562 | 43 | 43 | 562 |\n" + "| max | 360 | 390,1 | YES | 383213213 | 712 | 48 | 47 | 72 |\n" + "--------------------------------------------------------------------------------------------------------\n\n" + ); + } +} + +TEST( testTable, variadicTest ) +{ + { + TableLayout const layoutTest( "Cras egestas ipsum a nisl. Vivamus variu dolor utsisicdis parturient montes, nascetur ridiculus mus. Duis nascetur ridiculus mus", + { "Rank", + TableLayout::Column{"Nodes", TableLayout::Alignment::center, true, {"local", "ghost"}}, + "Edge", + TableLayout::Column{"Faces", TableLayout::Alignment::center, true, {"local", "ghost"}}, + TableLayout::Column{"Elems", TableLayout::Alignment::center, true, {"local", "ghost"}} } ); + + TableData tableData; + tableData.addRow( "min(local/total)", 1, 2, 3, 4, 5, 6, 7 ); + tableData.addRow( "min(local/total)", 1, 2, 3, 4, 5, 6, 7 ); + TableTextFormatter log( layoutTest ); + EXPECT_EQ( log.toString( tableData ), + "\n--------------------------------------------------------------------------------------------------------------------------------------\n" + "| Cras egestas ipsum a nisl. Vivamus variu dolor utsisicdis parturient montes, nascetur ridiculus mus. Duis nascetur ridiculus mus |\n" + "--------------------------------------------------------------------------------------------------------------------------------------\n" + "| Rank | Nodes | Edge | Faces | Elems |\n" + "--------------------------------------------------------------------------------------------------------------------------------------\n" + "| | local | ghost | | local | ghost | local | ghost |\n" + "--------------------------------------------------------------------------------------------------------------------------------------\n" + "| min(local/total) | 1 | 2 | 3 | 4 | 5 | 6 | 7 |\n" + "| min(local/total) | 1 | 2 | 3 | 4 | 5 | 6 | 7 |\n" + "--------------------------------------------------------------------------------------------------------------------------------------\n\n" + ); + } +} +TEST( testTable, testLineBreak ) +{ + TableLayout tableLayout( {"Cras egestas", "CoordX", "C", "CoordZ", "Prev\nelement", "Next\nelement"} ); + tableLayout.setTitle( "title" ).setMargin( TableLayout::MarginValue::tiny ).disableLineBreak(); + + TableData tableData; + tableData.addRow( "1", "2", "3.0", 3.0129877, 2.0f, 1 ); + tableData.addRow( "1", "2", "3.0", 3.0129877, 2.0f, 1 ); + + TableTextFormatter const tableText( tableLayout ); + + EXPECT_EQ( tableText.toString( tableData ), + "---------------------------------------------------\n" + "| title |\n" + "---------------------------------------------------\n" + "|Cras egestas|CoordX| C | CoordZ | Prev | Next |\n" + "| | | | |element|element|\n" + "---------------------------------------------------\n" + "| 1| 2|3.0|3.0129877| 2| 1|\n" + "| 1| 2|3.0|3.0129877| 2| 1|\n" + "---------------------------------------------------\n" + ); } int main( int argc, char * * argv ) diff --git a/src/coreComponents/common/initializeEnvironment.cpp b/src/coreComponents/common/initializeEnvironment.cpp index ee3b826aec6..3f3403163b3 100644 --- a/src/coreComponents/common/initializeEnvironment.cpp +++ b/src/coreComponents/common/initializeEnvironment.cpp @@ -345,11 +345,11 @@ static void addUmpireHighWaterMarks() pushStatsIntoAdiak( allocatorName + " rank max", mark ); } - TableLayout const memoryStatLayout ( {"Umpire Memory Pool\n(reserved / % over total)", - "Min over ranks", - "Max over ranks", - "Avg over ranks", - "Sum over ranks" } ); + TableLayout const memoryStatLayout ( { "Umpire Memory Pool\n(reserved / % over total)", + "Min over ranks", + "Max over ranks", + "Avg over ranks", + "Sum over ranks" } ); TableTextFormatter const memoryStatLog( memoryStatLayout ); GEOS_LOG_RANK_0( memoryStatLog.toString( tableData )); diff --git a/src/coreComponents/functions/TableFunction.cpp b/src/coreComponents/functions/TableFunction.cpp index 2e1897e7629..43f476e5cf7 100644 --- a/src/coreComponents/functions/TableFunction.cpp +++ b/src/coreComponents/functions/TableFunction.cpp @@ -307,7 +307,7 @@ string TableCSVFormatter::toString< TableFunction >( TableFunction const & table units::getDescription( tableFunction.getDimUnit( 0 ) ), units::getDescription( tableFunction.getDimUnit( 1 ) ) ); - TableLayout tableLayout( tableConverted.headerNames ); + TableLayout const tableLayout( "", tableConverted.headerNames ); TableCSVFormatter csvFormat( tableLayout ); formatterStream << csvFormat.headerToString() << csvFormat.dataToString( tableConverted.tableData ); @@ -322,7 +322,7 @@ string TableTextFormatter::toString< TableFunction >( TableFunction const & tabl units::Unit const valueUnit = tableFunction.getValueUnit(); arrayView1d< real64 const > const values = tableFunction.getValues(); integer const numDimensions = LvArray::integerConversion< integer >( coordinates.size() ); - string const filename = tableFunction.getName(); + std::string_view filename = tableFunction.getName(); string logOutput; GEOS_LOG_RANK_0( GEOS_FMT( "Values in the table are represented by : {}", units::getDescription( valueUnit ))); @@ -335,12 +335,10 @@ string TableTextFormatter::toString< TableFunction >( TableFunction const & tabl { tableData.addRow( coords[idx], values[idx] ); } - - TableLayout const tableLayout( { + TableLayout const tableLayout( filename, { string( units::getDescription( tableFunction.getDimUnit( 0 ))), string( units::getDescription( valueUnit )) - }, filename ); - + } ); TableTextFormatter const logTable( tableLayout ); logOutput = logTable.toString( tableData ); } @@ -358,17 +356,16 @@ string TableTextFormatter::toString< TableFunction >( TableFunction const & tabl units::getDescription( tableFunction.getDimUnit( 0 ) ), units::getDescription( tableFunction.getDimUnit( 1 ) )); - TableLayout tableLayout( tableConverted.headerNames, filename ); - + TableLayout const tableLayout( filename, tableConverted.headerNames ); TableTextFormatter const table2DLog( tableLayout ); logOutput = table2DLog.toString( tableConverted.tableData ); } else { string log = GEOS_FMT( "The {} PVT table exceeding 500 rows.\nTo visualize the tables, go to the generated csv \n", filename ); - TableLayout const tableLayoutInfos( {TableLayout::ColumnParam{{log}, TableLayout::Alignment::left}}, filename ); + TableLayout const tableLayoutInfos( filename, {TableLayout::Column{{log}, TableLayout::Alignment::left}} ); TableTextFormatter const tableLog( tableLayoutInfos ); - logOutput = tableLog.layoutToString(); + logOutput = tableLog.toString(); } } return logOutput; diff --git a/src/coreComponents/mesh/DomainPartition.cpp b/src/coreComponents/mesh/DomainPartition.cpp index 0dd8a8a3623..4469411a9b6 100644 --- a/src/coreComponents/mesh/DomainPartition.cpp +++ b/src/coreComponents/mesh/DomainPartition.cpp @@ -18,6 +18,9 @@ */ #include "DomainPartition.hpp" +#include "common/format/table/TableData.hpp" +#include "common/format/table/TableFormatter.hpp" +#include "common/format/table/TableLayout.hpp" #include "common/DataTypes.hpp" #include "common/TimingMacros.hpp" @@ -322,7 +325,6 @@ void DomainPartition::addNeighbors( const unsigned int idim, void DomainPartition::outputPartitionInformation() const { - auto numberOfEntities = []( ObjectManagerBase const & objectManager ) { return std::make_pair( objectManager.getNumberOfLocalIndices(), objectManager.getNumberOfGhosts() ); @@ -345,7 +347,6 @@ void DomainPartition::outputPartitionInformation() const GEOS_LOG_RANK_0( "MPI Partition information:" ); - forMeshBodies( [&]( MeshBody const & meshBody ) { meshBody.getMeshLevels().forSubGroupsIndex< MeshLevel >( [&]( int const level, MeshLevel const & meshLevel ) @@ -408,45 +409,34 @@ void DomainPartition::outputPartitionInformation() const real64 const maxElemRatio = maxRatios[3]; GEOS_LOG_RANK_0( " MeshBody: " + meshBody.getName() + " MeshLevel: " + meshLevel.getName() + "\n" ); - GEOS_LOG_RANK_0( " |------------------------------------------------------------------------------------------------------------------------------------------------|" ); - GEOS_LOG_RANK_0( " | | Nodes | Edges | Faces | Elems |" ); - GEOS_LOG_RANK_0( " |------------------------------------------------------------------------------------------------------------------------------------------------|" ); - GEOS_LOG_RANK_0( GEOS_FMT( " |min(local/total)| {:4.2f} | {:4.2f} | {:4.2f} | {:4.2f} | ", - minNodeRatio, - minEdgeRatio, - minFaceRatio, - minElemRatio ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " |max(local/total)| {:4.2f} | {:4.2f} | {:4.2f} | {:4.2f} | ", - maxNodeRatio, - maxEdgeRatio, - maxFaceRatio, - maxElemRatio ) ); - GEOS_LOG_RANK_0( " |------------------------------------------------------------------------------------------------------------------------------------------------|" ); - GEOS_LOG_RANK_0( " | Rank | local | ghost | local | ghost | local | ghost | local | ghost |" ); - GEOS_LOG_RANK_0( " |----------------|---------------|---------------|---------------|---------------|---------------|---------------|---------------|---------------|" ); - - - GEOS_LOG_RANK_0( GEOS_FMT( " | min | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} |", - addCommaSeparators( minNumLocalNodes ), - addCommaSeparators( minNumGhostNodes ), - addCommaSeparators( minNumLocalEdges ), - addCommaSeparators( minNumGhostEdges ), - addCommaSeparators( minNumLocalFaces ), - addCommaSeparators( minNumGhostFaces ), - addCommaSeparators( minNumLocalElems ), - addCommaSeparators( minNumGhostElems ) ) ); - - GEOS_LOG_RANK_0( GEOS_FMT( " | max | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} |", - addCommaSeparators( maxNumLocalNodes ), - addCommaSeparators( maxNumGhostNodes ), - addCommaSeparators( maxNumLocalEdges ), - addCommaSeparators( maxNumGhostEdges ), - addCommaSeparators( maxNumLocalFaces ), - addCommaSeparators( maxNumGhostFaces ), - addCommaSeparators( maxNumLocalElems ), - addCommaSeparators( maxNumGhostElems ) ) ); - - GEOS_LOG_RANK_0( " |------------------------------------------------------------------------------------------------------------------------------------------------|" ); + + TableLayout layoutPartition( "Rank", + {" ", + TableLayout::Column{"Nodes", {"local", "ghost"}}, + TableLayout::Column{"Edges", {"local", "ghost"}}, + TableLayout::Column{"Faces", {"local", "ghost"}}, + TableLayout::Column{"Elems", {"local", "ghost"}}} ); + layoutPartition.setMargin( TableLayout::MarginValue::large ).disableLineBreak(); + + TableData dataPartition; + dataPartition.addRow( "min", + addCommaSeparators( minNumLocalNodes ), + addCommaSeparators( minNumGhostNodes ), + addCommaSeparators( minNumLocalEdges ), + addCommaSeparators( minNumGhostEdges ), + addCommaSeparators( minNumLocalFaces ), + addCommaSeparators( minNumGhostFaces ), + addCommaSeparators( minNumLocalElems ), + addCommaSeparators( minNumGhostElems )); + dataPartition.addRow( "max", + addCommaSeparators( maxNumLocalNodes ), + addCommaSeparators( maxNumGhostNodes ), + addCommaSeparators( maxNumLocalEdges ), + addCommaSeparators( maxNumGhostEdges ), + addCommaSeparators( maxNumLocalFaces ), + addCommaSeparators( maxNumGhostFaces ), + addCommaSeparators( maxNumLocalElems ), + addCommaSeparators( maxNumGhostElems )); // output in rank order int const thisRank = MpiWrapper::commRank(); @@ -454,25 +444,42 @@ void DomainPartition::outputPartitionInformation() const { if( rank == thisRank ) { - GEOS_LOG( GEOS_FMT( " | {:14} | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} | {:>13} | ", - rank, - addCommaSeparators( numLocalNodes ), - addCommaSeparators( numGhostNodes ), - addCommaSeparators( numLocalEdges ), - addCommaSeparators( numGhostEdges ), - addCommaSeparators( numLocalFaces ), - addCommaSeparators( numGhostFaces ), - addCommaSeparators( numLocalElems ), - addCommaSeparators( numGhostElems ) ) ); + dataPartition.addRow( rank, + addCommaSeparators( numLocalNodes ), + addCommaSeparators( numGhostNodes ), + addCommaSeparators( numLocalEdges ), + addCommaSeparators( numGhostEdges ), + addCommaSeparators( numLocalFaces ), + addCommaSeparators( numGhostFaces ), + addCommaSeparators( numLocalElems ), + addCommaSeparators( numGhostElems )); } MpiWrapper::barrier(); } MpiWrapper::barrier(); - GEOS_LOG_RANK_0( " |------------------------------------------------------------------------------------------------------------------------------------------------|" ); + TableTextFormatter logPartition( layoutPartition ); + GEOS_LOG_RANK_0( logPartition.toString( dataPartition )); + + TableLayout layoutPartitionRatio( {"Rank", "Nodes ", "Edges ", "Faces ", "Elems "} ); + layoutPartitionRatio.setMargin( TableLayout::MarginValue::large ); + + TableData dataPartitionRatio; + dataPartitionRatio.addRow( "min(local/total)", + minNodeRatio, + minEdgeRatio, + minFaceRatio, + minElemRatio ); + dataPartitionRatio.addRow( "min(local/total)", + maxNodeRatio, + maxEdgeRatio, + maxFaceRatio, + maxElemRatio ); + + TableTextFormatter logPartitionRation( layoutPartitionRatio ); + GEOS_LOG_RANK_0( logPartitionRation.toString( dataPartitionRatio )); } } ); } - ); } diff --git a/src/coreComponents/mesh/generators/WellGeneratorBase.cpp b/src/coreComponents/mesh/generators/WellGeneratorBase.cpp index 1617aa3fdb4..dae451ea4c9 100644 --- a/src/coreComponents/mesh/generators/WellGeneratorBase.cpp +++ b/src/coreComponents/mesh/generators/WellGeneratorBase.cpp @@ -526,7 +526,7 @@ void WellGeneratorBase::mergePerforations( array1d< array1d< localIndex > > cons void WellGeneratorBase::logInternalWell() const { - TableData tableWellData; + TableData wellData; for( globalIndex iwelem = 0; iwelem < m_numElems; ++iwelem ) { std::optional< globalIndex > nextElement; @@ -542,40 +542,38 @@ void WellGeneratorBase::logInternalWell() const prevElement = m_prevElemId[iwelem][0]; } - tableWellData.addRow( iwelem, - m_elemCenterCoords[iwelem][0], - m_elemCenterCoords[iwelem][1], - m_elemCenterCoords[iwelem][2], - prevElement, - nextElement ); + wellData.addRow( iwelem, + m_elemCenterCoords[iwelem][0], + m_elemCenterCoords[iwelem][1], + m_elemCenterCoords[iwelem][2], + prevElement, + nextElement ); } - string const wellTitle = GEOS_FMT( "Well '{}' Element Table", getName() ); - TableLayout const tableWellLayout = TableLayout( { - TableLayout::ColumnParam{"Element no.", TableLayout::Alignment::right}, - TableLayout::ColumnParam{"CoordX", TableLayout::Alignment::right}, - TableLayout::ColumnParam{"CoordY", TableLayout::Alignment::right}, - TableLayout::ColumnParam{"CoordZ", TableLayout::Alignment::right}, - TableLayout::ColumnParam{"Prev\nElement", TableLayout::Alignment::right}, - TableLayout::ColumnParam{"Next\nElement", TableLayout::Alignment::right}, - }, wellTitle ); - - TableTextFormatter const tableFormatter( tableWellLayout ); - GEOS_LOG_RANK_0( tableFormatter.toString( tableWellData )); + TableLayout const wellLayout( GEOS_FMT( "Well '{}' Element Table", getName() ), + {"Element no.", + "CoordX", + "CoordY", + "CoordZ", + "Prev\nElement", + "Next\nElement"} ); + + TableTextFormatter const wellFormatter( wellLayout ); + GEOS_LOG_RANK_0( wellFormatter.toString( wellData )); } void WellGeneratorBase::logPerforationTable() const { - TableData tablePerfoData; + TableData dataPerforation; for( globalIndex iperf = 0; iperf < m_numPerforations; ++iperf ) { - tablePerfoData.addRow( iperf, m_perfCoords[iperf], m_perfElemId[iperf] ); + dataPerforation.addRow( iperf, m_perfCoords[iperf], m_perfElemId[iperf] ); } - TableLayout const tableLayoutPerfo ( {"Perforation no.", "Coordinates", "Well element no."}, - GEOS_FMT( "Well '{}' Perforation Table", getName() ) ); - TableTextFormatter const tablePerfoLog( tableLayoutPerfo ); - GEOS_LOG_RANK_0( tablePerfoLog.toString( tablePerfoData )); + 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 )); } } diff --git a/src/coreComponents/physicsSolvers/LinearSolverParameters.cpp b/src/coreComponents/physicsSolvers/LinearSolverParameters.cpp index 3bc0888dae6..5a8746a0510 100644 --- a/src/coreComponents/physicsSolvers/LinearSolverParameters.cpp +++ b/src/coreComponents/physicsSolvers/LinearSolverParameters.cpp @@ -341,10 +341,9 @@ void LinearSolverParametersInput::print() tableData.addRow( "ILU(T) threshold factor", m_parameters.ifact.threshold ); } } - TableLayout const tableLayout = TableLayout( { - TableLayout::ColumnParam{"Parameter", TableLayout::Alignment::left}, - TableLayout::ColumnParam{"Value", TableLayout::Alignment::left}, - }, GEOS_FMT( "{}: linear solver", getParent().getName() ) ); + TableLayout const tableLayout = TableLayout( GEOS_FMT( "{}: linear solver", getParent().getName() ), + { TableLayout::Column{"Parameter", TableLayout::Alignment::left}, + TableLayout::Column{"Value", TableLayout::Alignment::left} } ); TableTextFormatter const tableFormatter( tableLayout ); GEOS_LOG_RANK_0( tableFormatter.toString( tableData )); } diff --git a/src/coreComponents/physicsSolvers/NonlinearSolverParameters.cpp b/src/coreComponents/physicsSolvers/NonlinearSolverParameters.cpp index c8438212f63..a4d3198d1c8 100644 --- a/src/coreComponents/physicsSolvers/NonlinearSolverParameters.cpp +++ b/src/coreComponents/physicsSolvers/NonlinearSolverParameters.cpp @@ -235,10 +235,10 @@ void NonlinearSolverParameters::print() const tableData.addRow( "Sequential convergence criterion", m_sequentialConvergenceCriterion ); tableData.addRow( "Subcycling", m_subcyclingOption ); } - TableLayout const tableLayout = TableLayout( { - TableLayout::ColumnParam{"Parameter", TableLayout::Alignment::left}, - TableLayout::ColumnParam{"Value", TableLayout::Alignment::left}, - }, GEOS_FMT( "{}: nonlinear solver", getParent().getName() ) ); + TableLayout const tableLayout = TableLayout( GEOS_FMT( "{}: nonlinear solver", getParent().getName() ), + { TableLayout::Column{"Parameter", TableLayout::Alignment::left}, + TableLayout::Column{"Value", TableLayout::Alignment::left} } + ); TableTextFormatter const tableFormatter( tableLayout ); GEOS_LOG_RANK_0( tableFormatter.toString( tableData )); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/StencilDataCollection.cpp b/src/coreComponents/physicsSolvers/fluidFlow/StencilDataCollection.cpp index dcd795ec3ed..ba14e8b2ba1 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/StencilDataCollection.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/StencilDataCollection.cpp @@ -236,10 +236,8 @@ string formatKernelDataExtract( arrayView1d< StencilDataCollection::KernelConnec kernelIterator->m_transmissibility[0], kernelIterator->m_transmissibility[1] ); } - TableLayout const tableLayout{ - { "regionId A/B", "subRegionId A/B", "elementId A/B", "transmissibilityAB", "transmissibilityBA" }, - GEOS_FMT( "Kernel data (real row count = {})", kernelData.size() ) - }; + TableLayout const tableLayout = TableLayout( GEOS_FMT( "Kernel data (real row count = {})", kernelData.size() ), + {"regionId A/B", "subRegionId A/B", "elementId A/B", "transmissibilityAB", "transmissibilityBA"} ); TableTextFormatter const tableFormatter{ tableLayout }; return tableFormatter.toString( tableData ); } diff --git a/src/coreComponents/schema/docs/CO2BrineEzrokhiFluid.rst b/src/coreComponents/schema/docs/CO2BrineEzrokhiFluid.rst new file mode 100644 index 00000000000..ea8921a885a --- /dev/null +++ b/src/coreComponents/schema/docs/CO2BrineEzrokhiFluid.rst @@ -0,0 +1,18 @@ + + +==================== ================== ======== ============================================================================================================ +Name Type Default Description +==================== ================== ======== ============================================================================================================ +checkPVTTablesRanges integer 1 Enable (1) or disable (0) an error when the input pressure or temperature of the PVT tables is out of range. +componentMolarWeight real64_array {0} Component molar weights +componentNames string_array {} List of component names +flashModelParaFile path Name of the file defining the parameters of the flash model +logLevel integer 0 Log level +name groupName required A name is required for any non-unique nodes +phaseNames groupNameRef_array {} List of fluid phases +phasePVTParaFiles path_array required Names of the files defining the parameters of the viscosity and density models +solubilityTableNames string_array {} Names of solubility tables for each phase +writeCSV integer 0 Write PVT tables into a CSV file +==================== ================== ======== ============================================================================================================ + + diff --git a/src/coreComponents/schema/docs/CO2BrineEzrokhiThermalFluid.rst b/src/coreComponents/schema/docs/CO2BrineEzrokhiThermalFluid.rst new file mode 100644 index 00000000000..ea8921a885a --- /dev/null +++ b/src/coreComponents/schema/docs/CO2BrineEzrokhiThermalFluid.rst @@ -0,0 +1,18 @@ + + +==================== ================== ======== ============================================================================================================ +Name Type Default Description +==================== ================== ======== ============================================================================================================ +checkPVTTablesRanges integer 1 Enable (1) or disable (0) an error when the input pressure or temperature of the PVT tables is out of range. +componentMolarWeight real64_array {0} Component molar weights +componentNames string_array {} List of component names +flashModelParaFile path Name of the file defining the parameters of the flash model +logLevel integer 0 Log level +name groupName required A name is required for any non-unique nodes +phaseNames groupNameRef_array {} List of fluid phases +phasePVTParaFiles path_array required Names of the files defining the parameters of the viscosity and density models +solubilityTableNames string_array {} Names of solubility tables for each phase +writeCSV integer 0 Write PVT tables into a CSV file +==================== ================== ======== ============================================================================================================ + + diff --git a/src/coreComponents/schema/docs/CO2BrinePhillipsFluid.rst b/src/coreComponents/schema/docs/CO2BrinePhillipsFluid.rst new file mode 100644 index 00000000000..ea8921a885a --- /dev/null +++ b/src/coreComponents/schema/docs/CO2BrinePhillipsFluid.rst @@ -0,0 +1,18 @@ + + +==================== ================== ======== ============================================================================================================ +Name Type Default Description +==================== ================== ======== ============================================================================================================ +checkPVTTablesRanges integer 1 Enable (1) or disable (0) an error when the input pressure or temperature of the PVT tables is out of range. +componentMolarWeight real64_array {0} Component molar weights +componentNames string_array {} List of component names +flashModelParaFile path Name of the file defining the parameters of the flash model +logLevel integer 0 Log level +name groupName required A name is required for any non-unique nodes +phaseNames groupNameRef_array {} List of fluid phases +phasePVTParaFiles path_array required Names of the files defining the parameters of the viscosity and density models +solubilityTableNames string_array {} Names of solubility tables for each phase +writeCSV integer 0 Write PVT tables into a CSV file +==================== ================== ======== ============================================================================================================ + + diff --git a/src/coreComponents/schema/docs/CO2BrinePhillipsThermalFluid.rst b/src/coreComponents/schema/docs/CO2BrinePhillipsThermalFluid.rst new file mode 100644 index 00000000000..ea8921a885a --- /dev/null +++ b/src/coreComponents/schema/docs/CO2BrinePhillipsThermalFluid.rst @@ -0,0 +1,18 @@ + + +==================== ================== ======== ============================================================================================================ +Name Type Default Description +==================== ================== ======== ============================================================================================================ +checkPVTTablesRanges integer 1 Enable (1) or disable (0) an error when the input pressure or temperature of the PVT tables is out of range. +componentMolarWeight real64_array {0} Component molar weights +componentNames string_array {} List of component names +flashModelParaFile path Name of the file defining the parameters of the flash model +logLevel integer 0 Log level +name groupName required A name is required for any non-unique nodes +phaseNames groupNameRef_array {} List of fluid phases +phasePVTParaFiles path_array required Names of the files defining the parameters of the viscosity and density models +solubilityTableNames string_array {} Names of solubility tables for each phase +writeCSV integer 0 Write PVT tables into a CSV file +==================== ================== ======== ============================================================================================================ + + diff --git a/src/coreComponents/schema/docs/ReactiveBrine.rst b/src/coreComponents/schema/docs/ReactiveBrine.rst new file mode 100644 index 00000000000..9d0af7f1a17 --- /dev/null +++ b/src/coreComponents/schema/docs/ReactiveBrine.rst @@ -0,0 +1,15 @@ + + +==================== ================== ======== ============================================================================================================ +Name Type Default Description +==================== ================== ======== ============================================================================================================ +checkPVTTablesRanges integer 1 Enable (1) or disable (0) an error when the input pressure or temperature of the PVT tables is out of range. +componentMolarWeight real64_array {0} Component molar weights +componentNames string_array {} List of component names +name groupName required A name is required for any non-unique nodes +phaseNames groupNameRef_array {} List of fluid phases +phasePVTParaFiles path_array required Names of the files defining the parameters of the viscosity and density models +writeCSV integer 0 Write PVT tables into a CSV file +==================== ================== ======== ============================================================================================================ + + diff --git a/src/coreComponents/schema/docs/ReactiveBrineThermal.rst b/src/coreComponents/schema/docs/ReactiveBrineThermal.rst new file mode 100644 index 00000000000..9d0af7f1a17 --- /dev/null +++ b/src/coreComponents/schema/docs/ReactiveBrineThermal.rst @@ -0,0 +1,15 @@ + + +==================== ================== ======== ============================================================================================================ +Name Type Default Description +==================== ================== ======== ============================================================================================================ +checkPVTTablesRanges integer 1 Enable (1) or disable (0) an error when the input pressure or temperature of the PVT tables is out of range. +componentMolarWeight real64_array {0} Component molar weights +componentNames string_array {} List of component names +name groupName required A name is required for any non-unique nodes +phaseNames groupNameRef_array {} List of fluid phases +phasePVTParaFiles path_array required Names of the files defining the parameters of the viscosity and density models +writeCSV integer 0 Write PVT tables into a CSV file +==================== ================== ======== ============================================================================================================ + +