diff --git a/inputFiles/constitutiveDriver/friction/frictionDriver_Coulomb.xml b/inputFiles/constitutiveDriver/friction/frictionDriver_Coulomb.xml
new file mode 100644
index 00000000000..6fd8f7907a2
--- /dev/null
+++ b/inputFiles/constitutiveDriver/friction/frictionDriver_Coulomb.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/constitutiveDriver/friction/frictionDriver_base.xml b/inputFiles/constitutiveDriver/friction/frictionDriver_base.xml
new file mode 100644
index 00000000000..bf4b23983db
--- /dev/null
+++ b/inputFiles/constitutiveDriver/friction/frictionDriver_base.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/constitutiveDriver/friction/tables/jumps.geos b/inputFiles/constitutiveDriver/friction/tables/jumps.geos
new file mode 100644
index 00000000000..3c922732f7a
--- /dev/null
+++ b/inputFiles/constitutiveDriver/friction/tables/jumps.geos
@@ -0,0 +1,6 @@
+0
+1e-3
+2e-3
+3e-3
+4e-3
+5e-3
diff --git a/inputFiles/constitutiveDriver/friction/tables/time.geos b/inputFiles/constitutiveDriver/friction/tables/time.geos
new file mode 100644
index 00000000000..e8371f00609
--- /dev/null
+++ b/inputFiles/constitutiveDriver/friction/tables/time.geos
@@ -0,0 +1,6 @@
+0
+1
+2
+3
+4
+5
diff --git a/inputFiles/constitutiveDriver/friction/tables/tractions.geos b/inputFiles/constitutiveDriver/friction/tables/tractions.geos
new file mode 100644
index 00000000000..c80b1f6d1bd
--- /dev/null
+++ b/inputFiles/constitutiveDriver/friction/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 cbc198074d6..b3554ad559c 100644
--- a/src/coreComponents/constitutiveDrivers/CMakeLists.txt
+++ b/src/coreComponents/constitutiveDrivers/CMakeLists.txt
@@ -29,12 +29,16 @@ set( constitutiveDrivers_headers
relativePermeability/RelpermDriver.hpp
relativePermeability/RelpermDriverRunTest.hpp
solid/TriaxialDriver.hpp
+ contact/FrictionDriver.hpp
+ contact/FrictionDriverRunTest.hpp
)
#
# Specify all sources
#
set( constitutiveDrivers_sources
ConstitutiveDriver.cpp
+ contact/FrictionDriver.cpp
+ contact/FrictionDriverRunTest.cpp
fluid/multiFluid/PVTDriver.cpp
fluid/multiFluid/constant/PVTDriverRunTestInvariantImmiscibleFluid.cpp
fluid/multiFluid/blackOil/PVTDriverRunTestDeadOilFluid.cpp
diff --git a/src/coreComponents/constitutiveDrivers/contact/FrictionDriver.cpp b/src/coreComponents/constitutiveDrivers/contact/FrictionDriver.cpp
new file mode 100644
index 00000000000..c2538822f04
--- /dev/null
+++ b/src/coreComponents/constitutiveDrivers/contact/FrictionDriver.cpp
@@ -0,0 +1,205 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 "FrictionDriver.hpp"
+
+#include "constitutive/ConstitutiveManager.hpp"
+#include "constitutiveDrivers/LogLevelsInfo.hpp"
+#include "constitutive/contact/FrictionBase.hpp"
+#include "constitutive/contact/FrictionSelector.hpp"
+
+#include "functions/FunctionManager.hpp"
+#include "functions/TableFunction.hpp"
+
+namespace geos
+{
+
+using namespace dataRepository;
+using namespace constitutive;
+
+FrictionDriver::FrictionDriver( const string & name, Group * const parent )
+ : ConstitutiveDriver( 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" );
+
+ addLogLevel< logInfo::LogOutput >();
+}
+
+void FrictionDriver::postInputInitialization()
+{
+ ConstitutiveDriver::postInputInitialization();
+
+ // Check that the functions exist
+ FunctionManager & functionManager = FunctionManager::getInstance();
+ GEOS_ERROR_IF( !functionManager.hasGroup< TableFunction >( m_jumpFunctionName ),
+ GEOS_FMT( "Jump function with name '{}' not found", m_jumpFunctionName ),
+ getWrapperDataContext( viewKeyStruct::jumpFunctionString() ) );
+
+ GEOS_ERROR_IF( !functionManager.hasGroup< TableFunction >( m_tractionFunctionName ),
+ GEOS_FMT( "Traction function with name '{}' not found", m_tractionFunctionName ),
+ getWrapperDataContext( viewKeyStruct::tractionFunctionString() ) );
+
+ string_array columnNames;
+ getColumnNames( columnNames );
+ integer const numCols = static_cast< integer >(columnNames.size());
+
+ // initialize functions
+ TableFunction & jumpFunction = functionManager.getGroup< TableFunction >( m_jumpFunctionName );
+ TableFunction & tractionFunction = functionManager.getGroup< TableFunction >( m_tractionFunctionName );
+
+ jumpFunction.initializeFunction();
+ tractionFunction.initializeFunction();
+
+ // TODO: Maybe we should take the maximum extent of jumpFunction and tractionFunction
+ ArrayOfArraysView< real64 > coordinates = jumpFunction.getCoordinates();
+ real64 const minTime = coordinates[0][0];
+ real64 const maxTime = coordinates[0][coordinates.sizeOfArray( 0 )-1];
+
+ // Allocate the data
+ allocateTable( numCols, minTime, maxTime );
+
+ // set input columns
+ initializeTable();
+}
+
+bool FrictionDriver::execute()
+{
+ FrictionBase & baseFriction = getFriction();
+
+ 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, " Steps .................. " << m_numSteps );
+ GEOS_LOG_LEVEL_RANK_0( logInfo::LogOutput, " Output ................. " << m_outputFile );
+
+ // 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 );
+
+ integer const numRows = m_table.size( 0 );
+ discretization.resize( numRows ); // numRows elements
+ baseFriction.allocateConstitutiveData( discretization, 1 ); // one quadrature point
+
+ constitutiveUpdatePassThru( baseFriction, [&]( auto & selectedFrictionModel )
+ {
+ using FRICTION_TYPE = TYPEOFREF( selectedFrictionModel );
+ runTest< FRICTION_TYPE >( selectedFrictionModel, m_table );
+ } );
+
+ return false;
+}
+
+void FrictionDriver::getColumnNames( string_array & columnNames ) const
+{
+ columnNames.emplace_back( "time" );
+ columnNames.emplace_back( "traction,normal" );
+ columnNames.emplace_back( "traction,tangent1" );
+ columnNames.emplace_back( "traction,tangent2" );
+ columnNames.emplace_back( "displacement jump,normal" );
+ columnNames.emplace_back( "displacement jump,tangent1" );
+ columnNames.emplace_back( "displacement jump,tangent2" );
+ columnNames.emplace_back( "fracture state" );
+
+ if( dynamic_cast< CoulombFriction const * >(&getFriction()) != nullptr )
+ {
+ columnNames.emplace_back( "tau limit" );
+ }
+}
+
+void FrictionDriver::initializeTable()
+{
+ integer const numRows = m_table.size( 0 );
+
+ FunctionManager & functionManager = FunctionManager::getInstance();
+ TableFunction const & jumpFunction = functionManager.getGroup< TableFunction >( m_jumpFunctionName );
+ TableFunction const & tractionFunction = functionManager.getGroup< TableFunction >( m_tractionFunctionName );
+
+ real64 const cos_theta = cos( m_theta * M_PI/180.0 );
+ real64 const sin_theta = sin( m_theta * M_PI/180.0 );
+
+ real64 const cos_phi = cos( m_phi * M_PI/180.0 );
+ real64 const sin_phi = sin( m_phi * M_PI/180.0 );
+
+ for( integer index = 0; index < numRows; ++index )
+ {
+ real64 const time = m_table( index, TIME );
+
+ real64 const traction = tractionFunction.evaluate( &time );
+ real64 const jump = jumpFunction.evaluate( &time );
+
+ m_table( index, NTRAC ) = traction*sin_theta;
+ m_table( index, STRAC0 ) = traction*cos_theta*cos_phi;
+ m_table( index, STRAC1 ) = traction*cos_theta*sin_phi;
+
+ m_table( index, NJUMP ) = jump*sin_theta;
+ m_table( index, SLIP0 ) = jump*cos_theta*cos_phi;
+ m_table( index, SLIP1 ) = jump*cos_theta*sin_phi;
+
+ m_table( index, FS ) = fields::contact::FractureState::Stick;
+ }
+
+ if( CoulombFriction const * coulombFriction = dynamic_cast< CoulombFriction const * >(&getFriction()) )
+ {
+ real64 const cohesion = coulombFriction->getCohesion();
+ real64 const frictionCoeff = coulombFriction->getFrictionCoeff();
+ for( integer index = 0; index < numRows; ++index )
+ {
+ real64 const normal_traction = m_table( index, NTRAC );
+ m_table( index, TLIM ) = cohesion - normal_traction * frictionCoeff;
+ }
+ }
+}
+
+FrictionBase & FrictionDriver::getFriction()
+{
+ return getConstitutiveManager().getGroup< FrictionBase >( m_frictionName );
+}
+
+FrictionBase const & FrictionDriver::getFriction() const
+{
+ return getConstitutiveManager().getGroup< FrictionBase >( m_frictionName );
+}
+
+REGISTER_CATALOG_ENTRY( TaskBase,
+ FrictionDriver,
+ string const &, dataRepository::Group * const )
+
+}
diff --git a/src/coreComponents/constitutiveDrivers/contact/FrictionDriver.hpp b/src/coreComponents/constitutiveDrivers/contact/FrictionDriver.hpp
new file mode 100644
index 00000000000..d912eed02d6
--- /dev/null
+++ b/src/coreComponents/constitutiveDrivers/contact/FrictionDriver.hpp
@@ -0,0 +1,92 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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_CONSTITUTIVEDRIVERS_CONTACT_FRICTIONDRIVER_HPP
+#define GEOS_CONSTITUTIVEDRIVERS_CONTACT_FRICTIONDRIVER_HPP
+
+#include "constitutiveDrivers/ConstitutiveDriver.hpp"
+
+namespace geos
+{
+namespace constitutive
+{
+class FrictionBase;
+}
+
+class FrictionDriver : public ConstitutiveDriver
+{
+public:
+ FrictionDriver( const string & name,
+ Group * const parent );
+
+ static string catalogName()
+ { return "FrictionDriver"; }
+
+ void postInputInitialization() override;
+
+ bool execute() override;
+
+ void getColumnNames( string_array & columnNames ) const override;
+
+ template< typename FRICTION_TYPE >
+ void
+ runTest( FRICTION_TYPE & friction,
+ const arrayView2d< real64, 1 > & table );
+
+private:
+ /**
+ * @brief Get the friction model from the catalog
+ */
+ constitutive::FrictionBase & getFriction();
+ constitutive::FrictionBase const & getFriction() const;
+
+ void initializeTable();
+
+ /**
+ * @struct viewKeyStruct holds char strings and viewKeys for fast lookup
+ */
+ struct viewKeyStruct : ConstitutiveDriver::viewKeyStruct
+ {
+ constexpr static char const * frictionNameString()
+ { return "friction"; }
+
+ 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";}
+ };
+
+ // Time is defined in base class
+ enum columnKeys { NJUMP = 1, SLIP0, SLIP1, NTRAC, STRAC0, STRAC1, FS, TLIM };
+
+ string m_jumpFunctionName; ///<
+ string m_tractionFunctionName; ///<
+
+ real64 m_theta{0.0}; ///< x-tilt of fault
+ real64 m_phi{0.0}; ///< y-tilt of fault
+
+ string m_frictionName; ///< frictionType identifier
+};
+
+}
+
+#endif //GEOS_CONSTITUTIVEDRIVERS_CONTACT_FRICTIONDRIVER_HPP
diff --git a/src/coreComponents/constitutiveDrivers/contact/FrictionDriverRunTest.cpp b/src/coreComponents/constitutiveDrivers/contact/FrictionDriverRunTest.cpp
new file mode 100644
index 00000000000..f06fe66436d
--- /dev/null
+++ b/src/coreComponents/constitutiveDrivers/contact/FrictionDriverRunTest.cpp
@@ -0,0 +1,27 @@
+#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< real64 > & );
+
+template
+void
+FrictionDriver::runTest( constitutive::FrictionlessContact &, const arrayView2d< real64 > & );
+
+template
+void
+FrictionDriver::runTest( constitutive::RateAndStateFriction< std::integral_constant< bool, true > > &, const arrayView2d< real64 > & );
+
+template
+void
+FrictionDriver::runTest( constitutive::RateAndStateFriction< std::integral_constant< bool, false > > &, const arrayView2d< real64 > & );
+
+}
diff --git a/src/coreComponents/constitutiveDrivers/contact/FrictionDriverRunTest.hpp b/src/coreComponents/constitutiveDrivers/contact/FrictionDriverRunTest.hpp
new file mode 100644
index 00000000000..5c0e5875dfa
--- /dev/null
+++ b/src/coreComponents/constitutiveDrivers/contact/FrictionDriverRunTest.hpp
@@ -0,0 +1,61 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 )
+{
+ // Create kernel wrapper
+ typename FRICTION_TYPE::KernelWrapper const kernelWrapper = friction.createKernelUpdates();
+
+ integer const numRows = m_table.size( 0 );
+ forAll< parallelDevicePolicy<> >( numRows,
+ [ kernelWrapper, table ]
+ GEOS_HOST_DEVICE ( integer const ei )
+ {
+ stackArray1d< real64, 3 > jump( 3 );
+ stackArray1d< real64, 3 > traction( 3 );
+
+ jump[0] = table( ei, NJUMP );
+ jump[1] = table( ei, SLIP0 );
+ jump[2] = table( ei, SLIP1 );
+
+ traction[0] = table( ei, NTRAC );
+ traction[1] = table( ei, STRAC0 );
+ traction[2] = table( ei, STRAC1 );
+
+ integer fracture_state = fields::contact::FractureState::Stick;
+ kernelWrapper.updateFractureState( jump.toSliceConst(),
+ traction.toSliceConst(),
+ fracture_state );
+
+ table( ei, FS ) = fracture_state;
+ } );
+}
+
+}
+
+#endif //GEOS_FRICTIONDRIVERRUNTEST_HPP_
diff --git a/src/coreComponents/schema/schema.xsd b/src/coreComponents/schema/schema.xsd
index 9a9bb51d843..30a9887b6a5 100644
--- a/src/coreComponents/schema/schema.xsd
+++ b/src/coreComponents/schema/schema.xsd
@@ -569,6 +569,10 @@
+
+
+
+
@@ -6266,6 +6270,7 @@ When set to `all` output both convergence & iteration information to a csv.-->
+
@@ -6380,6 +6385,29 @@ Information output from lower logLevels is added with the desired log level
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+