diff --git a/inputFiles/frictionDriver/frictionDriver_Coulomb.xml b/inputFiles/frictionDriver/frictionDriver_Coulomb.xml new file mode 100644 index 00000000000..3a1c0a5b630 --- /dev/null +++ b/inputFiles/frictionDriver/frictionDriver_Coulomb.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + diff --git a/inputFiles/frictionDriver/frictionDriver_base.xml b/inputFiles/frictionDriver/frictionDriver_base.xml new file mode 100644 index 00000000000..df5ef688301 --- /dev/null +++ b/inputFiles/frictionDriver/frictionDriver_base.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/frictionDriver/tables/jumps.geos b/inputFiles/frictionDriver/tables/jumps.geos new file mode 100644 index 00000000000..3c922732f7a --- /dev/null +++ b/inputFiles/frictionDriver/tables/jumps.geos @@ -0,0 +1,6 @@ +0 +1e-3 +2e-3 +3e-3 +4e-3 +5e-3 diff --git a/inputFiles/frictionDriver/tables/time.geos b/inputFiles/frictionDriver/tables/time.geos new file mode 100644 index 00000000000..e8371f00609 --- /dev/null +++ b/inputFiles/frictionDriver/tables/time.geos @@ -0,0 +1,6 @@ +0 +1 +2 +3 +4 +5 diff --git a/inputFiles/frictionDriver/tables/tractions.geos b/inputFiles/frictionDriver/tables/tractions.geos new file mode 100644 index 00000000000..c80b1f6d1bd --- /dev/null +++ b/inputFiles/frictionDriver/tables/tractions.geos @@ -0,0 +1,6 @@ +0 +1e6 +2e6 +3e6 +4e6 +5e6 diff --git a/src/coreComponents/constitutive/contact/CoulombFriction.hpp b/src/coreComponents/constitutive/contact/CoulombFriction.hpp index e5a3387743d..5bf8057fef6 100644 --- a/src/coreComponents/constitutive/contact/CoulombFriction.hpp +++ b/src/coreComponents/constitutive/contact/CoulombFriction.hpp @@ -182,6 +182,14 @@ class CoulombFriction : public FrictionBase */ KernelWrapper createKernelUpdates() const; + /// getting cohesion value + real64 getCohesion() const + { return m_cohesion; } + + /// getting friction coeff + real64 getFrictionCoeff() const + { return m_frictionCoefficient; } + /** * @struct Set of "char const *" and keys for data specified in this class. */ diff --git a/src/coreComponents/constitutiveDrivers/CMakeLists.txt b/src/coreComponents/constitutiveDrivers/CMakeLists.txt index de519ea2fdb..b64c154dd1d 100644 --- a/src/coreComponents/constitutiveDrivers/CMakeLists.txt +++ b/src/coreComponents/constitutiveDrivers/CMakeLists.txt @@ -29,6 +29,8 @@ set( constitutiveDrivers_headers relativePermeability/RelpermDriver.hpp relativePermeability/RelpermDriverRunTest.hpp solid/TriaxialDriver.hpp + contact/FrictionDriver.hpp + contact/FrictionDriverRunTest.hpp ) # # Specify all sources @@ -57,6 +59,8 @@ set( constitutiveDrivers_sources relativePermeability/RelpermDriverTableRelativeRunTest.cpp relativePermeability/RelpermDriverTableRelativeHysteresisRunTest.cpp solid/TriaxialDriver.cpp + contact/FrictionDriver.cpp + contact/FrictionDriverRunTest.cpp ) set( dependencyList ${parallelDeps} constitutive events ) diff --git a/src/coreComponents/constitutiveDrivers/contact/FrictionDriver.cpp b/src/coreComponents/constitutiveDrivers/contact/FrictionDriver.cpp new file mode 100644 index 00000000000..1f475f27a45 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/contact/FrictionDriver.cpp @@ -0,0 +1,301 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "common/MpiWrapper.hpp" +#include "constitutive/ConstitutiveManager.hpp" +#include "constitutiveDrivers/contact/LogLevelsInfo.hpp" +#include "constitutive/contact/FrictionBase.hpp" +#include "constitutive/contact/FrictionSelector.hpp" + +#include "functions/FunctionManager.hpp" +#include "functions/TableFunction.hpp" +#include +#include + +#include "FrictionDriver.hpp" + +namespace geos { + +using namespace dataRepository; +using namespace constitutive; + +FrictionDriver::FrictionDriver(const string& name, Group * const parent) +: +TaskBase(name, parent) +{ + registerWrapper( viewKeyStruct::frictionNameString(), &m_frictionName ). + setRTTypeName( rtTypes::CustomTypes::groupNameRef ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Friction model to test" ); + + registerWrapper( viewKeyStruct::numStepsString(), &m_numSteps ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Number of sample step to take in both jumps and traction increments" ); + + registerWrapper( viewKeyStruct::jumpFunctionString(), &m_jumpFunctionName ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Name of the input function representing jump function along world x-axis" ); + + registerWrapper( viewKeyStruct::tractionFunctionString(), &m_tractionFunctionName ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Name of the input function representing traction function along world x-axis"); + + registerWrapper( viewKeyStruct::thetaString(), &m_theta ). + setInputFlag( InputFlags::REQUIRED ). + setDescription( "Number of increment step to take in both jumps and traction increments" ); + + registerWrapper( viewKeyStruct::phiString(), &m_phi ). + setInputFlag( InputFlags::INVALID). + setDescription( "Number of increment step to take in both jumps and traction increments" ); + + registerWrapper( viewKeyStruct::outputString(), &m_outputFile ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( "none" ). + setDescription( "Output file" ); + + registerWrapper( viewKeyStruct::baselineString(), &m_baselineFile ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( "none" ). + setDescription( "Baseline file" ); + + addLogLevel< logInfo::LogOutput >(); +} + +void FrictionDriver::compareWithBaseline() +{ + // open baseline file + + std::ifstream file( m_baselineFile.c_str() ); + GEOS_THROW_IF( !file.is_open(), "Can't seem to open the baseline file " << m_baselineFile, InputError ); + + // discard file header + + string line; + for( integer row=0; row < m_numColumns; ++row ) + { + getline( file, line ); + } + + // read data block. we assume the file size is consistent with m_table, + // but check for a premature end-of-file. we then compare results value by value. + // we ignore the newton iteration and residual columns, as those may be platform + // specific. + + real64 value; + real64 error; + + for( integer row=0; row < m_table.size( 0 ); ++row ) + { + for( integer col=0; col < m_table.size( 1 ); ++col ) + { + GEOS_THROW_IF( file.eof(), "Baseline file appears shorter than internal results", std::runtime_error ); + file >> value; + + error = fabs( m_table[row][col]-value ) / ( fabs( value )+1 ); + GEOS_THROW_IF( error > m_baselineTol, "Results do not match baseline at data row " << row+1 + << " (row " << row+10 << " with header)" + << " and column " << col+1, std::runtime_error ); + + } + } + + // check we actually reached the end of the baseline file + + file >> value; + GEOS_THROW_IF( !file.eof(), "Baseline file appears longer than internal results", std::runtime_error ); + + // success + + GEOS_LOG_LEVEL_RANK_0( logInfo::LogOutput, " Comparison ........ Internal results consistent with baseline." ); + + file.close(); +} + +void FrictionDriver::outputResults() +{ + // TODO: improve file path output to grab command line -o directory + // for the moment, we just use the specified m_outputFile directly + + FILE * fp = fopen( m_outputFile.c_str(), "w" ); + + fprintf( fp, "# column 1 = index \n" ); + fprintf( fp, "# column 2-3 = normal and in-plane displacement jump\n" ); + fprintf( fp, "# columns 5-7 = normal and in-place tractions\n"); + fprintf( fp, "# columns 8 = fracture state (0:Stick,1-2:[new]Slip,3:Open)\n"); + fprintf( fp, "# columns 9 = tau lim\n"); + + for( integer n = 0; n < m_table.size( 0 ); ++n ) + { + for( integer col = 0; col < m_table.size( 1 ); ++col ) + { + fprintf( fp, "%.4e ", m_table( n, col ) ); + } + fprintf( fp, "\n" ); + } + fclose( fp ); + +} + + +void FrictionDriver::postInputInitialization() +{ + ConstitutiveManager + & constitutiveManager = this->getGroupByPath< ConstitutiveManager >( "/Problem/domain/Constitutive" ); + FrictionBase& baseFriction = constitutiveManager.getGroup< FrictionBase >( m_frictionName ); + +// m_numPhases = baseFriction.numSubGroups(); + +} + + +bool FrictionDriver::execute( const geos::real64 GEOS_UNUSED_PARAM( time_n ), + const geos::real64 GEOS_UNUSED_PARAM( dt ), + const geos::integer GEOS_UNUSED_PARAM( cycleNumber ), + const geos::integer GEOS_UNUSED_PARAM( eventCounter ), + const geos::real64 GEOS_UNUSED_PARAM( eventProgress ), + geos::DomainPartition & + GEOS_UNUSED_PARAM( domain ) ) +{ + // this code only makes sense in serial + + GEOS_THROW_IF( MpiWrapper::commRank() > 0, "FrictionDriver should only be run in serial", std::runtime_error ); + + + ConstitutiveManager + & constitutiveManager = this->getGroupByPath< ConstitutiveManager >( "/Problem/domain/Constitutive" ); + FrictionBase + & baseFriction = constitutiveManager.getGroup< FrictionBase >( m_frictionName ); + + GEOS_LOG_LEVEL_RANK_0( logInfo::LogOutput, "Launching Friction Driver" ); + GEOS_LOG_LEVEL_RANK_0( logInfo::LogOutput, " Friction .................. " << m_frictionName ); + GEOS_LOG_LEVEL_RANK_0( logInfo::LogOutput, " Type ................... " << baseFriction.getCatalogName() ); +// GEOS_LOG_LEVEL_RANK_0( logInfo::LogOutput, " No. of Phases .......... " << m_numPhases ); + GEOS_LOG_LEVEL_RANK_0( logInfo::LogOutput, " Steps .................. " << m_numSteps ); + GEOS_LOG_LEVEL_RANK_0( logInfo::LogOutput, " Output ................. " << m_outputFile ); + GEOS_LOG_LEVEL_RANK_0( logInfo::LogOutput, " Baseline ............... " << m_baselineFile ); + + // create a dummy discretization with one quadrature point for + // storing constitutive data + + conduit::Node node; + dataRepository::Group rootGroup( "root", node ); + dataRepository::Group discretization( "discretization", &rootGroup ); + + discretization.resize( 1 ); // one element + baseFriction.allocateConstitutiveData( discretization, 1 ); // one quadrature point + + constitutiveUpdatePassThru( baseFriction, [&]( auto & selectedFrictionModel ) + { + using FRICTION_TYPE = TYPEOFREF( selectedFrictionModel ); + resizeTables< FRICTION_TYPE >(); + runTest< FRICTION_TYPE >( selectedFrictionModel, m_table ); + } ); + + // move table back to host for output + m_table.move( LvArray::MemorySpace::host ); + + if( m_outputFile != "none" ) + { + outputResults(); + } + + if( m_baselineFile != "none" ) + { + compareWithBaseline(); + } + + return false; +} + + +template< typename FRICTION_TYPE > +void FrictionDriver::resizeTables() +{ + ConstitutiveManager + & constitutiveManager = this->getGroupByPath< ConstitutiveManager >( "/Problem/domain/Constitutive" ); + FrictionBase + & baseFriction = constitutiveManager.getGroup< FrictionBase >( m_frictionName ); + + // initialize table functions + FunctionManager & functionManager = FunctionManager::getInstance(); + + TableFunction & jumpFunction = functionManager.getGroup< TableFunction >( m_jumpFunctionName ); + TableFunction & tractionFunction = functionManager.getGroup< TableFunction >( m_tractionFunctionName ); + + jumpFunction.initializeFunction(); + tractionFunction.initializeFunction(); + + ArrayOfArraysView< real64 > coordinates = jumpFunction.getCoordinates(); + real64 const minTime = coordinates[0][0]; + real64 const maxTime = coordinates[0][coordinates.sizeOfArray( 0 )-1]; + real64 const dt = (maxTime-minTime) / m_numSteps; + + // set input columns + resizeTable< FRICTION_TYPE >(); + + // set time column + for( integer k=0; k ) { + + cohesion = dynamic_cast(&baseFriction)->getCohesion(); + frictionCoeff = dynamic_cast(&baseFriction)->getFrictionCoeff(); + } + + //All variation + for( integer nt = 0; nt < m_numSteps+1; ++nt ) + { + for( integer nj = 0; nj < m_numSteps+1; ++nj ) + { + + integer index = nt * (m_numSteps+1) + nj; + m_table( index, NTRAC ) = tractionFunction.evaluate(&m_table(nt,TIME))*sin(m_theta * M_PI/180); + m_table( index, STRAC0 ) = tractionFunction.evaluate(&m_table(nt,TIME))*cos(m_theta * M_PI/180); + m_table( index, STRAC1 ) = tractionFunction.evaluate(&m_table(nt,TIME))*cos(m_theta * M_PI/180); + + m_table( index, NJUMP ) = jumpFunction.evaluate(&m_table(nj,TIME))*sin(m_theta * M_PI/180); + m_table( index, SLIP0 ) = jumpFunction.evaluate(&m_table(nj,TIME))*cos(m_theta * M_PI/180); + m_table( index, SLIP1 ) = jumpFunction.evaluate(&m_table(nj,TIME))*cos(m_theta * M_PI/180); + + m_table( index, FS ) = fields::contact::FractureState::Stick; + + //Only for Coulomb + m_table( index, TLIM ) = cohesion - m_table(index, NTRAC) * frictionCoeff; + + } + } + +} + + +template< typename FRICTION_TYPE > +void +FrictionDriver::resizeTable() +{ + m_table.resize((m_numSteps + 1)*(m_numSteps + 1), m_numColumns ); +} + +REGISTER_CATALOG_ENTRY( TaskBase, + FrictionDriver, + string const &, dataRepository::Group * const ) + +} \ No newline at end of file diff --git a/src/coreComponents/constitutiveDrivers/contact/FrictionDriver.hpp b/src/coreComponents/constitutiveDrivers/contact/FrictionDriver.hpp new file mode 100644 index 00000000000..dddaffafc80 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/contact/FrictionDriver.hpp @@ -0,0 +1,135 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#ifndef GEOS_frictionDRIVER_HPP_ +#define GEOS_frictionDRIVER_HPP_ + +#include "events/tasks/TaskBase.hpp" + +namespace geos +{ + +class FrictionDriver : public TaskBase +{ + +public: + FrictionDriver( const string & name, + Group * const parent ); + + static string catalogName() + { return "FrictionDriver"; } + + void postInputInitialization() override; + + virtual bool execute( real64 const GEOS_UNUSED_PARAM( time_n ), + real64 const GEOS_UNUSED_PARAM( dt ), + integer const GEOS_UNUSED_PARAM( cycleNumber ), + integer const GEOS_UNUSED_PARAM( eventCounter ), + real64 const GEOS_UNUSED_PARAM( eventProgress ), + DomainPartition & + GEOS_UNUSED_PARAM( domain ) ) override; + + // /** + // * @brief Run test using loading protocol in table + // * @param i friction constitutive model + // * @param table Table with input/output time history + // */ + // template< typename friction_TYPE > + // std::enable_if_t< std::is_same< constitutive::TableRelativePermeabilityHysteresis, friction_TYPE >::value, void > + // runTest( friction_TYPE & friction, + // const arrayView2d< real64, 1 > & table ); + + template< typename FRICTION_TYPE > + void + runTest( FRICTION_TYPE & friction, + const arrayView2d< real64, 1 > & table ); + + /** + * @brief Ouput table to file for easy plotting + */ + void outputResults(); + + /** + * @brief Read in a baseline table from file and compare with computed one (for unit testing purposes) + */ + void compareWithBaseline(); + +private: + + template< typename FRICTION_TYPE > + void resizeTable(); + + template< typename FRICTION_TYPE > + void resizeTables(); + + // template< typename friction_TYPE > + // std::enable_if_t< !std::is_same< constitutive::TableRelativePermeabilityHysteresis, friction_TYPE >::value, void > + // resizeTable(); + + /** + * @struct viewKeyStruct holds char strings and viewKeys for fast lookup + */ + struct viewKeyStruct + { + constexpr static char const * frictionNameString() + { return "friction"; } + + constexpr static char const * numStepsString() + { return "steps"; } + + constexpr static char const * jumpFunctionString() + { return "jumpControl"; } + + constexpr static char const * tractionFunctionString() + { return "tractionControl"; } + + constexpr static char const * thetaString() + { return "xTiltAngle";} + + constexpr static char const * phiString() + { return "yTiltAngle";} + + constexpr static char const * outputString() + { return "output"; } + + constexpr static char const * baselineString() + { return "baseline"; } + + }; + + integer m_numSteps; ///< Number of load steps + static integer const m_numColumns = 9; ///< Number of columns in dat + enum columnKeys { TIME, NJUMP, SLIP0, SLIP1, NTRAC, STRAC0, STRAC1, FS, TLIM }; + + string m_jumpFunctionName; ///< + string m_tractionFunctionName; ///< + + float m_theta, m_phi;///< x- and y-tilt of fault + + string m_frictionName; ///< frictionType identifier + string m_outputFile; ///< Output file (optional, no output if not specified) + + array2d< real64 > m_table; ///< Table storing time-history of input/output + + Path m_baselineFile; ///< Baseline file (optional, for unit testing of solid models) + + + static constexpr real64 m_baselineTol = 1e-3; ///< Comparison tolerance for baseline results +}; + + +} + +#endif //GEOS_FRICTIONDRIVER_HPP_ diff --git a/src/coreComponents/constitutiveDrivers/contact/FrictionDriverRunTest.cpp b/src/coreComponents/constitutiveDrivers/contact/FrictionDriverRunTest.cpp new file mode 100644 index 00000000000..2d40f34235f --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/contact/FrictionDriverRunTest.cpp @@ -0,0 +1,26 @@ +#include "FrictionDriverRunTest.hpp" +#include "constitutive/contact/CoulombFriction.hpp" +#include "constitutive/contact/FrictionlessContact.hpp" +#include "constitutive/contact/RateAndStateFriction.hpp" +#include + + +namespace geos { + +template +void +FrictionDriver::runTest(constitutive::CoulombFriction&, const arrayView2d &); + +template +void +FrictionDriver::runTest(constitutive::FrictionlessContact&, const arrayView2d &); + +template +void +FrictionDriver::runTest(constitutive::RateAndStateFriction>&, const arrayView2d &); + +template +void +FrictionDriver::runTest(constitutive::RateAndStateFriction>&, const arrayView2d &); + +} diff --git a/src/coreComponents/constitutiveDrivers/contact/FrictionDriverRunTest.hpp b/src/coreComponents/constitutiveDrivers/contact/FrictionDriverRunTest.hpp new file mode 100644 index 00000000000..cde385ff032 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/contact/FrictionDriverRunTest.hpp @@ -0,0 +1,74 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#ifndef GEOS_FRICTIONDRIVERRUNTEST_HPP_ +#define GEOS_FRICTIONDRIVERRUNTEST_HPP_ + +#include "constitutiveDrivers/contact/FrictionDriver.hpp" +#include "physicsSolvers/solidMechanics/contact/FractureState.hpp" +#include "constitutive/solid/SolidFields.hpp" + + +namespace geos +{ + + +template< typename FRICTION_TYPE > +void +FrictionDriver::runTest( FRICTION_TYPE & friction, + const arrayView2d< real64 > & table ) +{ + + array2d< real64 > jumps, tractions; + jumps.resize(table.size(0),3); + tractions.resize(table.size(0),3); + + for( integer n = 0; n < table.size(0); ++n) + { + jumps[n][0] = table(n,NJUMP); + jumps[n][1] = table(n,SLIP0); + jumps[n][2] = table(n,SLIP1); + + tractions[n][0] = table(n,NTRAC); + tractions[n][1] = table(n,STRAC0); + tractions[n][2] = table(n,STRAC1); + + } + + + // create kernel wrapper + typename FRICTION_TYPE::KernelWrapper const kernelWrapper = friction.createKernelUpdates(); + + forAll< parallelDevicePolicy<> >( 1, + [ kernelWrapper, table, jumps, tractions ] + GEOS_HOST_DEVICE ( integer const ei ) + { + for( integer i = 1; i < table.size(0) ; ++i ) + { + integer fs = fields::contact::FractureState::Stick; + kernelWrapper.updateFractureState( jumps[i], + tractions[i], + fs ); + + table(i,FS) = fs; + } + } ); + +} + +} + + +#endif //GEOS_FRICTIONDRIVERRUNTEST_HPP_ diff --git a/src/coreComponents/constitutiveDrivers/contact/LogLevelsInfo.hpp b/src/coreComponents/constitutiveDrivers/contact/LogLevelsInfo.hpp new file mode 100644 index 00000000000..1a0319a7db4 --- /dev/null +++ b/src/coreComponents/constitutiveDrivers/contact/LogLevelsInfo.hpp @@ -0,0 +1,52 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file LogLevelsInfo.hpp + * This file contains common log level informations for PVT driver + */ + +#ifndef GEOS_CONSTITUTIVEDRIVERS_CONTACT_LOGLEVELSINFO_HPP_ +#define GEOS_CONSTITUTIVEDRIVERS_CONTACT_LOGLEVELSINFO_HPP_ + +#include "common/DataTypes.hpp" + +namespace geos +{ + +namespace logInfo +{ + +/** + * @name Common LogLevels info structures. They must comply with the `is_log_level_info` trait. + */ +///@{ + +/// @cond DO_NOT_DOCUMENT + +struct LogOutput +{ + static constexpr int getMinLogLevel() { return 1; } + static constexpr std::string_view getDescription() { return "Enable log output"; } +}; + +/// @endcond +///@} + +} + +} + +#endif // GEOS_CONSTITUTIVEDRIVERS_CONTACT_LOGLEVELSINFO_HPP_