diff --git a/src/coreComponents/codingUtilities/tests/CMakeLists.txt b/src/coreComponents/codingUtilities/tests/CMakeLists.txt index 1fe1863459d..013fefbab0f 100644 --- a/src/coreComponents/codingUtilities/tests/CMakeLists.txt +++ b/src/coreComponents/codingUtilities/tests/CMakeLists.txt @@ -10,7 +10,6 @@ geos_decorate_link_dependencies( LIST decoratedDependencies DEPENDENCIES ${dependencyList} ) # Add gtest C++ based tests foreach( test ${testSources} ) - get_filename_component( test_name ${test} NAME_WE ) blt_add_executable( NAME ${test_name} SOURCES ${test} diff --git a/src/coreComponents/dataRepository/ExecutableGroup.hpp b/src/coreComponents/dataRepository/ExecutableGroup.hpp index b1751f3e1f0..e350cb60598 100644 --- a/src/coreComponents/dataRepository/ExecutableGroup.hpp +++ b/src/coreComponents/dataRepository/ExecutableGroup.hpp @@ -119,8 +119,38 @@ class ExecutableGroup : public dataRepository::Group */ TimesteppingBehavior getTimesteppingBehavior() const { return m_timesteppingBehavior; } + /** + * @brief Get the track of substeps for each substep + * @return A vector containing the time step size for each substep + */ + std::vector< real64 > const & getSubStepDt() const { return m_subStepDt; } + + /** + * @brief Get the track of substeps for each substep + * @return A const vector containing the time step size for each substep + */ + std::vector< real64 > & getSubStepDt() { return m_subStepDt; } + + /** + * @brief Get number of time sub-steps allowed for the solver + * @return The number of substeps taken + */ + integer const & getNumOfSubSteps() { return m_numOfSubSteps; } + + /** + * @brief Set number of time sub-steps allowed for the solver + * @param nbStep Number of subtimestep to set + */ + void setNumOfSubSteps( integer nbStep ) { m_numOfSubSteps = nbStep;} + private: + /// Keep track of substeps + std::vector< real64 > m_subStepDt = {}; + + /// number of time sub-steps allowed for the solver + integer m_numOfSubSteps = 0; + TimesteppingBehavior m_timesteppingBehavior = TimesteppingBehavior::DoesNotDetermineTimeStepSize; }; diff --git a/src/coreComponents/events/EventBase.cpp b/src/coreComponents/events/EventBase.cpp index 52b3c386c2d..bed4a034585 100644 --- a/src/coreComponents/events/EventBase.cpp +++ b/src/coreComponents/events/EventBase.cpp @@ -361,7 +361,6 @@ void EventBase::getExecutionOrder( array1d< integer > & eventCounters ) } ); } - void EventBase::setProgressIndicator( array1d< integer > & eventCounters ) { // Calculate the event progress indicator diff --git a/src/coreComponents/events/EventBase.hpp b/src/coreComponents/events/EventBase.hpp index c3e4920b188..429e1b824d3 100644 --- a/src/coreComponents/events/EventBase.hpp +++ b/src/coreComponents/events/EventBase.hpp @@ -167,6 +167,19 @@ class EventBase : public ExecutableGroup */ void getExecutionOrder( array1d< integer > & eventCounters ); + /** + * @brief Get the track of substeps + * @return A vector containing the the track of substeps + */ + std::vector< real64 > const & getSubStepDt() const { return m_target->getSubStepDt(); } + + /** + * @brief Get number of time sub-steps allowed for the solver + * @return The number of substeps taken + */ + integer const & getNumOfSubSteps() const { return m_target->getNumOfSubSteps(); } + + /** * @brief Update the event progress for the event/sub-events. * @note This method is used to determine how to handle the timestamp for an event @@ -270,6 +283,13 @@ class EventBase : public ExecutableGroup return m_eventTarget; } + /** + * @brief Get the target of this event. + * @return The target of this event. + */ + ExecutableGroup * getEventTarget() const + { return m_target; } + protected: /** @@ -301,13 +321,6 @@ class EventBase : public ExecutableGroup void setForecast( integer forecast ) { m_eventForecast = forecast; } - /** - * @brief Get the target of this event. - * @return The target of this event. - */ - ExecutableGroup * getEventTarget() const - { return m_target; } - /** * @brief Is the event active? * @param time The time at which we want to check if the event is active. diff --git a/src/coreComponents/events/EventManager.cpp b/src/coreComponents/events/EventManager.cpp index 3f709bce94b..b02d66cebe4 100644 --- a/src/coreComponents/events/EventManager.cpp +++ b/src/coreComponents/events/EventManager.cpp @@ -171,9 +171,11 @@ bool EventManager::run( DomainPartition & domain ) m_dt = dt_global; #endif } - - outputTime(); - + LogPart logPart( "TIMESTEP" ); + outputTime( logPart ); + logPart.begin(); + std::vector< real64 > subStepDt; + integer numTimeSteps = 0; // Execute for(; m_currentSubEventnumSubGroups(); ++m_currentSubEvent ) { @@ -195,6 +197,13 @@ bool EventManager::run( DomainPartition & domain ) else if( subEvent->isReadyForExec() ) { earlyReturn = subEvent->execute( m_time, m_dt, m_cycle, 0, 0, domain ); + + if( subEvent->getEventTarget()->getTimesteppingBehavior() == ExecutableGroup::TimesteppingBehavior::DeterminesTimeStepSize ) + { + subStepDt = subEvent->getSubStepDt(); + numTimeSteps = subEvent->getNumOfSubSteps(); + } + } // Check the exit flag @@ -209,6 +218,9 @@ bool EventManager::run( DomainPartition & domain ) } } + + logEndOfCycleInformation( logPart, m_cycle, numTimeSteps, subStepDt ); + // Increment time/cycle, reset the subevent counter m_time += m_dt; ++m_cycle; @@ -226,7 +238,7 @@ bool EventManager::run( DomainPartition & domain ) return false; } -void EventManager::outputTime() const +void EventManager::outputTime( LogPart & logPart ) const { const bool isTimeLimited = m_maxTime < std::numeric_limits< real64 >::max(); const bool isCycleLimited = m_maxCycle < std::numeric_limits< integer >::max(); @@ -246,19 +258,17 @@ void EventManager::outputTime() const m_maxCycle, ( 100.0 * m_cycle ) / m_maxCycle ); }; - // The formating here is a work in progress. - GEOS_LOG_RANK_0( "\n------------------------- TIMESTEP START -------------------------" ); - GEOS_LOG_RANK_0( GEOS_FMT( " - Time: {}{}", - timeInfo.toUnfoldedString(), - isTimeLimited ? timeCompletionUnfoldedString() : "" ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " ({}{})", - timeInfo.toSecondsString(), - isTimeLimited ? timeCompletionSecondsString() : "" ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " - Delta Time: {}", units::TimeFormatInfo::fromSeconds( m_dt ) ) ); - GEOS_LOG_RANK_0( GEOS_FMT( " - Cycle: {}{}", - m_cycle, - isCycleLimited ? cycleCompletionString() : "" ) ); - GEOS_LOG_RANK_0( "--------------------------------------------------------------------\n" ); + string const timeCompletionUnfolded = isTimeLimited ? timeCompletionUnfoldedString() : ""; + string const timeCompletionSecond = isTimeLimited ? timeCompletionSecondsString() : ""; + string const cycleLimited = isCycleLimited ? cycleCompletionString() : ""; + + string const timeInfosUnfolded = timeInfo.toUnfoldedString() + timeCompletionUnfolded; + string const timeCompletionSeconds = timeInfo.toSecondsString() + timeCompletionSecond; + + logPart.addDescription( "- Time : ", timeInfosUnfolded, timeCompletionSeconds ); + logPart.addDescription( "- Delta Time : ", units::TimeFormatInfo::fromSeconds( m_dt ).toString() ); + logPart.addDescription( "- Cycle : ", m_cycle, cycleLimited ); + logPart.setMinWidth( 65 ); // We are keeping the old outputs to keep compatibility with current log reading scripts. if( m_timeOutputFormat==TimeOutputFormat::full ) @@ -296,4 +306,28 @@ void EventManager::outputTime() const } } +void EventManager::logEndOfCycleInformation( LogPart & logpart, + integer const cycleNumber, + integer const numOfSubSteps, + std::vector< real64 > const & subStepDt ) const +{ + logpart.addEndDescription( "- Cycle: ", cycleNumber ); + logpart.addEndDescription( "- N substeps: ", numOfSubSteps ); + std::stringstream logMessage; + for( integer i = 0; i < numOfSubSteps; ++i ) + { + if( i > 0 ) + { + logMessage << ", "; + } + logMessage << units::TimeFormatInfo::fromSeconds( subStepDt[i] ).toString(); + } + + if( logMessage.rdbuf()->in_avail() == 0 ) + logMessage << "/"; + + logpart.addEndDescription( "- dt: ", logMessage.str() ); + logpart.end(); +} + } /* namespace geos */ diff --git a/src/coreComponents/events/EventManager.hpp b/src/coreComponents/events/EventManager.hpp index b86f48b8518..32b27fd671e 100644 --- a/src/coreComponents/events/EventManager.hpp +++ b/src/coreComponents/events/EventManager.hpp @@ -19,6 +19,7 @@ #include "dataRepository/Group.hpp" #include "EventBase.hpp" +#include "fileIO/logPart/LogPart.hpp" namespace geos { @@ -134,7 +135,19 @@ class EventManager : public dataRepository::Group * @brief ouput time information to the log * */ - void outputTime() const; + void outputTime( LogPart & section ) const; + + /** + * @brief output information about the cycle to the log + * @param logpart the end of section to be displayed + * @param cycleNumber the current cycle number + * @param numOfSubSteps the number of substeps taken + * @param subStepDt the time step size for each substep + */ + void logEndOfCycleInformation( LogPart & logpart, + integer const cycleNumber, + integer const numOfSubSteps, + std::vector< real64 > const & subStepDt ) const; /// Min time for a simulation real64 m_minTime; diff --git a/src/coreComponents/fileIO/CMakeLists.txt b/src/coreComponents/fileIO/CMakeLists.txt index a53eda4945c..c73a82e72b0 100644 --- a/src/coreComponents/fileIO/CMakeLists.txt +++ b/src/coreComponents/fileIO/CMakeLists.txt @@ -29,6 +29,7 @@ set( fileIO_headers Outputs/OutputUtilities.hpp Outputs/PythonOutput.hpp Outputs/RestartOutput.hpp + logPart/LogPart.hpp Outputs/TimeHistoryOutput.hpp timeHistory/HDFFile.hpp timeHistory/HistoryCollectionBase.hpp @@ -47,6 +48,7 @@ set( fileIO_sources Outputs/OutputUtilities.cpp Outputs/PythonOutput.cpp Outputs/RestartOutput.cpp + logPart/LogPart.cpp Outputs/TimeHistoryOutput.cpp timeHistory/HDFFile.cpp timeHistory/HistoryCollectionBase.cpp @@ -120,5 +122,9 @@ target_include_directories( fileIO PUBLIC ${CMAKE_SOURCE_DIR}/coreComponents ) install( TARGETS fileIO LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) +if( GEOS_ENABLE_TESTS ) + add_subdirectory( logPart/unitTests ) +endif( ) + diff --git a/src/coreComponents/fileIO/logPart/LogPart.cpp b/src/coreComponents/fileIO/logPart/LogPart.cpp new file mode 100644 index 00000000000..6d8b32507ea --- /dev/null +++ b/src/coreComponents/fileIO/logPart/LogPart.cpp @@ -0,0 +1,270 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2020 TotalEnergies + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file LogPart.cpp + */ + +#include "LogPart.hpp" +#include "common/format/StringUtilities.hpp" +#include + +using namespace geos::stringutilities; +namespace geos +{ + +LogPart::LogPart( string_view logPartTitle ) +{ + m_startDesc.m_title = logPartTitle; + m_endDesc.m_title = GEOS_FMT( "{}{}", m_prefixEndTitle, logPartTitle ); +} + +void LogPart::addDescription( string const & description ) +{ + m_startDesc.m_descriptionNames.push_back( description ); + m_startDesc.m_descriptionsValues.push_back( std::vector< string >() ); +} + +void LogPart::addEndDescription( string const & description ) +{ + m_endDesc.m_descriptionNames.push_back( description ); + m_endDesc.m_descriptionsValues.push_back( std::vector< string >() ); +} + + +void LogPart::setMinWidth( size_t const & minWidth ) +{ + m_startDesc.m_logPartMinWidth = minWidth; + m_endDesc.m_logPartMinWidth = minWidth; +} + +void LogPart::setMaxWidth( size_t const & maxWidth ) +{ + m_startDesc.m_logPartMaxWidth = maxWidth; + m_endDesc.m_logPartMaxWidth = maxWidth; +} + +string_view ltrim( string_view s ) +{ + std::size_t const first = s.find_first_not_of( " " ); + if( first != string::npos ) + { + return s.substr( first, ( s.size() - first ) ); + } + return {}; +} + +std::vector< string > splitAndFormatStringByDelimiter( string const & description, size_t maxLength ) +{ + std::vector< string > formattedDescription; + size_t startIdx = 0; + size_t endIdx = 0; + size_t captureIdx = 0; + size_t spaceIdx = 0; + while( endIdx < description.size()) + { + endIdx = description.find( ' ', spaceIdx ); + if( endIdx == std::string::npos ) + { + if( description.substr( startIdx ).size() > maxLength ) + { + formattedDescription.push_back( string( ltrim( description.substr( startIdx, captureIdx )))); + formattedDescription.push_back( string( ltrim( description.substr( startIdx + captureIdx ))) ); + } + else + { + formattedDescription.push_back( string( ltrim( description.substr( startIdx, endIdx )))); + } + } + else + { + size_t partLength = endIdx - startIdx; + if( partLength > maxLength ) + { + formattedDescription.push_back( string( ltrim( description.substr( startIdx, captureIdx )))); + startIdx = spaceIdx; + captureIdx = 0; + } + + spaceIdx = endIdx + 1; + captureIdx = partLength; + } + } + return formattedDescription; +} + +void LogPart::formatDescriptions( LogPart::Description & description ) +{ + auto & names = description.m_descriptionNames; + auto & valuesList = description.m_descriptionsValues; + size_t & logPartWidth = description.m_logPartWidth; + size_t & logPartMaxWidth = description.m_logPartMaxWidth; + size_t & logPartMinWidth = description.m_logPartMinWidth; + size_t & logPartMaxNameWidth = description.m_logPartMaxNameWidth; + std::vector< string > & formattedLines = description.m_formattedDescriptionLines; + + size_t extraChars = m_nbBorderChar * 2 + m_borderMargin * 2; + for( size_t idxName = 0; idxName < names.size(); idxName++ ) + { + string const & name = names[idxName]; + auto const & values = valuesList[idxName]; + + if( values.empty()) + { + if( name.size() > logPartMaxWidth ) + { + auto formattedName = splitAndFormatStringByDelimiter( name, logPartMaxWidth - extraChars ); + formattedLines.insert( formattedLines.end(), formattedName.begin(), formattedName.end()); + } + else + { + formattedLines.push_back( name ); + } + } + else + { + string const spaces = std::string( logPartMaxNameWidth - name.size(), ' ' ); + string const formattedName = GEOS_FMT( "{}{}", name, spaces ); + string const firstValue = values[0]; + size_t const formattedLineWidth = formattedName.size() + firstValue.size() + extraChars; + if( formattedLineWidth > logPartMaxWidth ) + { + auto formattedDescription = + splitAndFormatStringByDelimiter( firstValue, logPartMaxWidth - formattedName.size() - extraChars ); + for( auto const & format : formattedDescription ) + { + if( &format == &formattedDescription.front()) + { + formattedLines.push_back( GEOS_FMT( "{}{}", formattedName, format )); + } + else + { + formattedLines.push_back( GEOS_FMT( "{:>{}}", format, formattedName.size() + format.size() ) ); + } + } + } + else + { + formattedLines.push_back( GEOS_FMT( "{}{}", formattedName, firstValue )); + } + + logPartWidth = std::max( logPartWidth, formattedLines[idxName].size() ); + + for( size_t idxValue = 1; idxValue < values.size(); idxValue++ ) + { + formattedLines.push_back( + GEOS_FMT( "{:>{}}", values[idxValue], formattedName.size() + values[idxValue].size() )); + logPartWidth = std::max( logPartWidth, formattedLines.back().size() ); + } + } + + } + if( logPartWidth > logPartMaxWidth ) + logPartWidth = logPartMaxWidth; + + if( logPartWidth != logPartMinWidth ) + logPartWidth += extraChars; + + logPartWidth = std::max( logPartWidth, logPartMinWidth ); +} + +string LogPart::buildDescriptionPart( LogPart::Description const & description ) +{ + std::ostringstream oss; + for( auto const & formattedDescription : description.m_formattedDescriptionLines ) + { + string const borderCharacters = string( m_nbBorderChar, m_borderCharacter ); + oss << borderCharacters; + oss << GEOS_FMT( "{:<{}}{:<{}}", " ", m_borderMargin, + formattedDescription, description.m_logPartWidth - m_nbBorderChar * 2 - m_borderMargin ); + oss << borderCharacters << '\n'; + } + return oss.str(); +} + +string LogPart::buildTitlePart( LogPart::Description const & description ) +{ + std::ostringstream oss; + size_t const titleRowLength = description.m_logPartWidth; + string const borderCharacters = string( m_nbBorderChar, m_borderCharacter ); + oss << GEOS_FMT( "{}{:^{}}{}\n", + borderCharacters, + description.m_title, + titleRowLength - 4, + borderCharacters ); + return oss.str(); +} + +void LogPart::computeInitialLogWidth( LogPart::Description & description, + std::vector< string > const & descriptionNames, + std::vector< std::vector< string > > m_descriptionsValues ) +{ + + if( !descriptionNames.empty() ) + { + size_t maxStringSize = 0; + for( size_t idxDescription = 0; idxDescription < descriptionNames.size(); idxDescription++ ) + { + if( !m_descriptionsValues[idxDescription].empty()) + { + maxStringSize = std::max( maxStringSize, descriptionNames[idxDescription].size() ); + } + } + + description.m_logPartMaxNameWidth = maxStringSize; + } +} + +void LogPart::begin( std::ostream & os ) +{ + string bottomPart = ""; + auto & descriptionNames = m_startDesc.m_descriptionNames; + + computeInitialLogWidth( m_startDesc, descriptionNames, m_startDesc.m_descriptionsValues ); + + if( !descriptionNames.empty()) + { + formatDescriptions( m_startDesc ); + } + + bottomPart = buildDescriptionPart( m_startDesc ); + + string const line = string( m_startDesc.m_logPartWidth, m_borderCharacter ); + string const topPart = GEOS_FMT( "{}\n{}{}\n", + line, + buildTitlePart( m_startDesc ), + line ); + os << GEOS_FMT( "\n{}{}\n", topPart, bottomPart ); +} + +void LogPart::end( std::ostream & os ) +{ + string topPart = ""; + auto & descriptionNames = m_endDesc.m_descriptionNames; + + computeInitialLogWidth( m_endDesc, descriptionNames, m_endDesc.m_descriptionsValues ); + + formatDescriptions( m_endDesc ); + + string const line = string( m_endDesc.m_logPartWidth, m_borderCharacter ); + if( !descriptionNames.empty() ) + { + topPart = GEOS_FMT( "{}{}\n", buildDescriptionPart( m_endDesc ), line ); + } + + string const bottomPart = GEOS_FMT( "{}{}\n", buildTitlePart( m_endDesc ), line ); + os << GEOS_FMT( "\n{}{}\n", topPart, bottomPart ); +} + +} diff --git a/src/coreComponents/fileIO/logPart/LogPart.hpp b/src/coreComponents/fileIO/logPart/LogPart.hpp new file mode 100644 index 00000000000..4d18b925e90 --- /dev/null +++ b/src/coreComponents/fileIO/logPart/LogPart.hpp @@ -0,0 +1,204 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2020 TotalEnergies + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file LogPart.hpp + */ + +#ifndef GEOS_COMMON_SECTION_HPP +#define GEOS_COMMON_SECTION_HPP + +#include "common/DataTypes.hpp" +#include "common/format/Format.hpp" + +namespace geos +{ + +/** + * @brief Class for displaying section for different steps of simulation + */ +class LogPart +{ +public: + + /** + * @brief Construct a new LogPart + * @param m_logPartTitle The logPart title + */ + LogPart( string_view m_logPartTitle ); + + /** + * @brief Add a description to the opening logPart by concatening a description name and descriptions values. + * @param name The description name + * @param args Descriptions values to be concatened. + * @note Descriptions values can be be any formatted types. Values will be aligned altogether. + */ + template< typename ... Args > + void addDescription( string const & name, Args const & ... args ); + + /** + * @brief Add a description to the opening logPart + * @param description The string value of the description + */ + void addDescription( string const & description ); + + /** + * @brief Add a description to the closing logPart by concatening a description name and descriptions values. + * @param name The description name + * @param args Descriptions values to be concatened. + * @note Descriptions values can be be any formatted types. Values will be aligned altogether. + */ + template< typename ... Args > + void addEndDescription( string const & name, Args const & ... args ); + + /** + * @brief Add a description to the closing logPart + * @param description The string value of the description + */ + void addEndDescription( string const & description ); + + /** + * @brief Set the minimal width of a row + * @param minWidth The minimal width of the table + */ + void setMinWidth( size_t const & minWidth ); + + /** + * @brief Set the minimal width of a row + * @param maxWidth The maximal width of the table + */ + void setMaxWidth( size_t const & maxWidth ); + + /** + * @brief Draw the first part of the logPart. It include the title and optionnaly, the end description(s). + * @param os An output stream (by default, std::cout) + */ + void begin( std::ostream & os = std::cout ); + + /** + * @brief Draw the last part of the logPart. It include the title + * @param oss An output stream (by default, std::cout) + */ + void end( std::ostream & oss = std::cout ); + +private: + + struct Description + { + /// Title footer string + string m_title; + + /// Name of the description, formatted to be : [Name] : [Values1]\n[Values2] + std::vector< string > m_descriptionNames; + /// Values in the description + std::vector< std::vector< string > > m_descriptionsValues; + /// Vector containing the descriptions formatted by formatDescriptions() + std::vector< string > m_formattedDescriptionLines; + + /// logPart length + size_t m_logPartWidth; + /// logPart length + size_t m_logPartMaxWidth; + /// min width of logPart length + size_t m_logPartMinWidth; + /// min width of logPart length + size_t m_logPartMaxNameWidth; + }; + + /** + * @brief Add a description to a specific section + * @param name The description name + * @param args Descriptions values to be concatened. + * @note Descriptions values can be be any formatted types. Values will be aligned altogether. + */ + template< typename ... Args > + void addDescriptionBySection( LogPart::Description & description, string const & name, Args const &... args ); + + /** + * @brief Computes the initial log width based on the provided description and names. + * @param description A description object that contains the current log part + * @param descriptionNames A vector containing all name used in the log Part + */ + void computeInitialLogWidth( LogPart::Description & description, + std::vector< string > const & descriptionNames, + std::vector< std::vector< string > > m_descriptionsValues ); + /** + * @brief Build a description from the name and description values + * @param name The decription name + * @param decriptionsValues The description values + */ + void formatDescriptions( LogPart::Description & description ); + + /** + * @brief Constructs the string logPart title of the log part. + */ + string buildTitlePart( LogPart::Description const & description ); + + /** + * @brief Constructs the string logPart descriptions of the log part. + */ + string buildDescriptionPart( LogPart::Description const & description ); + + /// prefix to append to the title of closing section + string const m_prefixEndTitle = "End of "; + + Description m_startDesc = { "", {}, {}, {}, 50, SIZE_MAX, 50, 0 }; + Description m_endDesc = { "", {}, {}, {}, 50, SIZE_MAX, 50, 0 }; + + /// description border margin + static constexpr size_t m_borderMargin = 2; + /// numbers of character used as border + static constexpr size_t m_nbBorderChar = 2; + /// character used for logPart construction + static constexpr size_t m_borderCharacter = '#'; + + /// String containing horizontal border + string m_horizontalBorder; +}; + +template< typename ... Args > +void LogPart::addDescriptionBySection( Description & description, string const & name, Args const &... args ) +{ + std::vector< string > values; + size_t maxValueSize = 0; + + ( [&] { + static_assert( has_formatter_v< decltype(args) >, + "Argument passed cannot be converted to string" ); + string const value = GEOS_FMT( "{}", args ); + values.push_back( value ); + maxValueSize = std::max( maxValueSize, value.size()); + } (), ...); + + description.m_descriptionNames.push_back( name ); + description.m_descriptionsValues.push_back( values ); + description.m_logPartWidth = std::min( description.m_logPartWidth, maxValueSize + 6 ); + +} + +template< typename ... Args > +void LogPart::addDescription( string const & name, Args const &... args ) +{ + addDescriptionBySection( m_startDesc, name, args ... ); +} + +template< typename ... Args > +void LogPart::addEndDescription( string const & name, Args const &... args ) +{ + addDescriptionBySection( m_endDesc, name, args ... ); +} + +} + +#endif diff --git a/src/coreComponents/fileIO/logPart/unitTests/CMakeLists.txt b/src/coreComponents/fileIO/logPart/unitTests/CMakeLists.txt new file mode 100644 index 00000000000..8297f46d077 --- /dev/null +++ b/src/coreComponents/fileIO/logPart/unitTests/CMakeLists.txt @@ -0,0 +1,18 @@ +# Specify list of tests +set( gtest_geosx_tests + testLogPart.cpp ) + +set( dependencyList gtest fileIO ${parallelDeps} ) + +# Add gtest C++ based tests +foreach(test ${gtest_geosx_tests}) + get_filename_component( test_name ${test} NAME_WE ) + blt_add_executable( NAME ${test_name} + SOURCES ${test} + OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY} + DEPENDS_ON ${dependencyList} ) + + geos_add_test( NAME ${test_name} + COMMAND ${test_name} ) + +endforeach() diff --git a/src/coreComponents/fileIO/logPart/unitTests/testLogPart.cpp b/src/coreComponents/fileIO/logPart/unitTests/testLogPart.cpp new file mode 100644 index 00000000000..c03b63c3f33 --- /dev/null +++ b/src/coreComponents/fileIO/logPart/unitTests/testLogPart.cpp @@ -0,0 +1,212 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2020 TotalEnergies + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "common/DataTypes.hpp" +#include "fileIO/logPart/LogPart.hpp" +#include + +using namespace geos; + +TEST( testSection, sectionWithTitle ) +{ + std::ostringstream oss; + LogPart logPart( "section name" ); + logPart.begin( oss ); + EXPECT_EQ( oss.str(), + "\n##################################################\n" + "## section name ##\n" + "##################################################\n\n" + ); + oss.clear(); + oss.str( "" ); + + logPart.end( oss ); + EXPECT_EQ( oss.str(), + "\n## End of section name ##\n" + "##################################################\n\n" + ); + oss.clear(); +} + +TEST( testSection, sectionWithTitleAndOneDescription ) +{ + std::ostringstream oss; + LogPart logPart( "section name" ); + logPart.addDescription( "description name" ); + logPart.begin( oss ); + EXPECT_EQ( oss.str(), + "\n##################################################\n" + "## section name ##\n" + "##################################################\n" + "## description name ##\n\n" + ); + oss.clear(); +} + +TEST( testSection, sectionWithSetWidth ) +{ + std::ostringstream oss; + LogPart logPart( "section name" ); + logPart.addDescription( "description name 1" ); + logPart.addDescription( "description name 2" ); + logPart.setMinWidth( 100 ); + logPart.begin( oss ); + EXPECT_EQ( oss.str(), + "\n####################################################################################################\n" + "## section name ##\n" + "####################################################################################################\n" + "## description name 1 ##\n" + "## description name 2 ##\n\n" + ); + oss.clear(); + oss.str( "" ); + + logPart.end( oss ); + EXPECT_EQ( oss.str(), + "\n## End of section name ##\n" + "####################################################################################################\n\n" + ); + oss.clear(); +} + +TEST( testSection, sectionMultipleDescriptions ) +{ + std::ostringstream oss; + LogPart logPart( "TIMESTEP START" ); + logPart.addDescription( "- Time : ", "00h08m20s out of 2d, 21h26m40s (0% completed)", "500 s / 250000 s" ); + logPart.addDescription( "- Delta Time : ", "00h16m40s (1000 s)" ); + logPart.addDescription( "Description test" ); + logPart.setMinWidth( 70 ); + logPart.begin( oss ); + EXPECT_EQ ( oss.str(), + "\n######################################################################\n" + "## TIMESTEP START ##\n" + "######################################################################\n" + "## - Time : 00h08m20s out of 2d, 21h26m40s (0% completed) ##\n" + "## 500 s / 250000 s ##\n" + "## - Delta Time : 00h16m40s (1000 s) ##\n" + "## Description test ##\n\n" + ); + oss.clear(); + oss.str( "" ); + + logPart.end( oss ); + EXPECT_EQ( oss.str(), + "\n## End of TIMESTEP START ##\n" + "######################################################################\n\n" + ); + oss.clear(); +} + +TEST( testSection, sectionEndDescription ) +{ + std::ostringstream oss; + LogPart logPart( "TIMESTEP START" ); + logPart.addEndDescription( "test end description" ); + logPart.setMinWidth( 70 ); + logPart.begin( oss ); + oss.clear(); + oss.str( "" ); + + logPart.end( oss ); + + EXPECT_EQ( oss.str(), + "\n## test end description ##\n" + "######################################################################\n" + "## End of TIMESTEP START ##\n" + "######################################################################\n\n" + ); + oss.clear(); +} + +TEST( testSection, valuesMultiLines ) +{ + std::ostringstream oss; + LogPart logPart( "TIMESTEP START" ); + logPart.addDescription( "dummy name : ", "long dummy values, long dummy values1, long dummy values2, long dummy values3" ); + logPart.addDescription( "dummy name : ", "long dummy values", "long dummy values", "long dummy values", "long dummy values" ); + logPart.addDescription( "dummy name : ", "small dummy value" ); + logPart.addDescription( "dummy name, long dummy values, long dummy values, long dummy values, long dummy values" ); + + logPart.addEndDescription( "dummy name : ", "long dummy end values, long dummy end values, long dummy end values, long dummy end values" ); + logPart.addEndDescription( "dummy name : ", "long dummy end values", "long dummy end values", "long dummy end values", "long dummy end values" ); + logPart.addEndDescription( "dummy name : ", "small dummy end value" ); + logPart.addEndDescription( "Ceci est un timestep extremement long 10h00h00545ms ( 1h 30 s en heure)" ); + logPart.setMaxWidth( 50 ); + logPart.begin( oss ); + EXPECT_EQ( oss.str(), + "\n##################################################\n" + "## TIMESTEP START ##\n" + "##################################################\n" + "## dummy name : long dummy values, long dummy ##\n" + "## values1, long dummy values2, ##\n" + "## long dummy values3 ##\n" + "## dummy name : long dummy values ##\n" + "## long dummy values ##\n" + "## long dummy values ##\n" + "## long dummy values ##\n" + "## dummy name : small dummy value ##\n" + "## dummy name, long dummy values, long dummy ##\n" + "## values, long dummy values, long dummy ##\n" + "## values ##\n\n" ); + oss.clear(); + oss.str( "" ); + + logPart.end( oss ); + EXPECT_EQ( oss.str(), + "\n## dummy name : long dummy end values, long ##\n" + "## dummy end values, long dummy ##\n" + "## end values, long dummy end ##\n" + "## values ##\n" + "## dummy name : long dummy end values ##\n" + "## long dummy end values ##\n" + "## long dummy end values ##\n" + "## long dummy end values ##\n" + "## dummy name : small dummy end value ##\n" + "## Ceci est un timestep extremement long ##\n" + "## 10h00h00545ms ( 1h 30 s en heure) ##\n" + "##################################################\n" + "## End of TIMESTEP START ##\n" + "##################################################\n\n" + ); + oss.clear(); +} + +TEST( testSection, multiLineWithExtraSpace ) +{ + std::ostringstream oss; + LogPart logPart( "TIMESTEP" ); + logPart.addDescription( "- Time : ", "00h00m00s out of 2y, 269d, 12h21m36s (0% completed), 0 s / 86400000 s" ); + logPart.addDescription( "- Delta Time : ", "00h00m00s (0.001 s)" ); + logPart.addDescription( "- Cycle : ", "0" ); + logPart.setMaxWidth( 60 ); + logPart.begin( oss ); + + EXPECT_EQ( oss.str(), + "\n###########################################################\n" + "## TIMESTEP ##\n" + "###########################################################\n" + "## - Time : 00h00m00s out of 2y, 269d, 12h21m36s ##\n" + "## (0% completed), 0 s / 86400000 s ##\n" + "## - Delta Time : 00h00m00s (0.001 s) ##\n" + "## - Cycle : 0 ##\n\n" ); + oss.clear(); + oss.str( "" ); +} + +int main( int argc, char * * argv ) +{ + testing::InitGoogleTest( &argc, argv ); + return RUN_ALL_TESTS();; +} diff --git a/src/coreComponents/mainInterface/ProblemManager.cpp b/src/coreComponents/mainInterface/ProblemManager.cpp index 890f550c752..22f30818b15 100644 --- a/src/coreComponents/mainInterface/ProblemManager.cpp +++ b/src/coreComponents/mainInterface/ProblemManager.cpp @@ -32,6 +32,7 @@ #include "events/tasks/TasksManager.hpp" #include "events/EventManager.hpp" #include "finiteElement/FiniteElementDiscretization.hpp" +#include "fileIO/logPart/LogPart.hpp" #include "finiteElement/FiniteElementDiscretizationManager.hpp" #include "finiteVolume/FluxApproximationBase.hpp" #include "finiteVolume/HybridMimeticDiscretization.hpp" @@ -168,19 +169,28 @@ Group * ProblemManager::createChild( string const & GEOS_UNUSED_PARAM( childKey void ProblemManager::problemSetup() { GEOS_MARK_FUNCTION; + postInputInitializationRecursive(); + LogPart meshGenerationLog( "Mesh generation" ); + meshGenerationLog.begin(); generateMesh(); + meshGenerationLog.end(); // initialize_postMeshGeneration(); - + LogPart numericalMethodLog( "Numerical Methods" ); + numericalMethodLog.begin(); applyNumericalMethods(); + numericalMethodLog.end(); registerDataOnMeshRecursive( getDomainPartition().getMeshBodies() ); initialize(); + LogPart importFieldsLog( "Import fields" ); + importFieldsLog.begin(); importFields(); + importFieldsLog.end(); } diff --git a/src/coreComponents/physicsSolvers/PhysicsSolverBase.cpp b/src/coreComponents/physicsSolvers/PhysicsSolverBase.cpp index e0eefbde8c2..4e9147dd46e 100644 --- a/src/coreComponents/physicsSolvers/PhysicsSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/PhysicsSolverBase.cpp @@ -16,6 +16,7 @@ #include "PhysicsSolverBase.hpp" #include "PhysicsSolverManager.hpp" +#include "fileIO/logPart/LogPart.hpp" #include "common/TimingMacros.hpp" #include "linearAlgebra/solvers/KrylovSolver.hpp" #include "mesh/DomainPartition.hpp" @@ -276,8 +277,10 @@ bool PhysicsSolverBase::execute( real64 const time_n, integer const maxSubSteps = m_nonlinearSolverParameters.m_maxSubSteps; // Keep track of substeps. It is useful to output these. - std::vector< real64 > subStepDt( maxSubSteps, 0.0 ); - integer numOfSubSteps = 0; + std::vector< real64 > & subStepDt = getSubStepDt(); + subStepDt.resize( maxSubSteps, 0.0 ); + + setNumOfSubSteps( 0 ); for( integer subStep = 0; subStep < maxSubSteps && dtRemaining > 0.0; ++subStep ) { @@ -288,7 +291,9 @@ bool PhysicsSolverBase::execute( real64 const time_n, nextDt, cycleNumber, domain ); - numOfSubSteps++; + setNumOfSubSteps( subStep + 1 ); + std::cout << " 1 substep " << subStep << std::endl; + subStepDt[subStep] = dtAccepted; // increment the cumulative number of nonlinear and linear iterations @@ -341,29 +346,9 @@ bool PhysicsSolverBase::execute( real64 const time_n, m_numTimestepsSinceLastDtCut++; } - logEndOfCycleInformation( cycleNumber, numOfSubSteps, subStepDt ); - return false; } -void PhysicsSolverBase::logEndOfCycleInformation( integer const cycleNumber, - integer const numOfSubSteps, - std::vector< real64 > const & subStepDt ) const -{ - // The formating here is a work in progress. - GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, "\n------------------------- TIMESTEP END -------------------------" ); - GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, GEOS_FMT( " - Cycle: {}", cycleNumber ) ); - GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, GEOS_FMT( " - N substeps: {}", numOfSubSteps ) ); - std::string logMessage = " - dt:"; - for( integer i = 0; i < numOfSubSteps; ++i ) - { - logMessage += " " + units::TimeFormatInfo::fromSeconds( subStepDt[i] ).toString(); - } - // Log the complete message once - GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, logMessage ); - GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::TimeStep, "------------------------------------------------------------------\n" ); -} - real64 PhysicsSolverBase::setNextDt( real64 const & currentDt, DomainPartition & domain ) { diff --git a/src/coreComponents/physicsSolvers/PhysicsSolverBase.hpp b/src/coreComponents/physicsSolvers/PhysicsSolverBase.hpp index 95a87f1a87f..5ac6a394f90 100644 --- a/src/coreComponents/physicsSolvers/PhysicsSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/PhysicsSolverBase.hpp @@ -1076,17 +1076,6 @@ class PhysicsSolverBase : public ExecutableGroup real64 const & dt, integer const cycleNumber, DomainPartition & domain ); - - /** - * @brief output information about the cycle to the log - * @param cycleNumber the current cycle number - * @param numOfSubSteps the number of substeps taken - * @param subStepDt the time step size for each substep - */ - void logEndOfCycleInformation( integer const cycleNumber, - integer const numOfSubSteps, - std::vector< real64 > const & subStepDt ) const; - }; template< typename CONSTITUTIVE_BASE_TYPE > 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 +==================== ================== ======== ============================================================================================================ + + diff --git a/src/coreComponents/schema/schema.xsd b/src/coreComponents/schema/schema.xsd index 9c0418e4f5f..54f97b0a39f 100644 --- a/src/coreComponents/schema/schema.xsd +++ b/src/coreComponents/schema/schema.xsd @@ -4895,7 +4895,7 @@ Level 0 outputs no specific information for this solver. Higher levels require m - + @@ -5086,7 +5086,7 @@ Level 0 outputs no specific information for this solver. Higher levels require m - Print statistics--> - + @@ -5114,7 +5114,7 @@ Level 0 outputs no specific information for this solver. Higher levels require m - + @@ -5133,7 +5133,7 @@ Level 0 outputs no specific information for this solver. Higher levels require m - Print statistics for each source flux in each regions--> - +