diff --git a/CMakeLists.txt b/CMakeLists.txt index 773b9757..d548b957 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,6 +77,8 @@ if ("${PROJECT_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}") endforeach() set(BLT_REQUIRED_CLANGFORMAT_VERSION "19" CACHE STRING "") + set(ENABLE_ALL_WARNINGS ON CACHE BOOL "") + set(ENABLE_WARNINGS_AS_ERRORS ON CACHE BOOL "") endif() include(${BLT_SOURCE_DIR}/SetupBLT.cmake) diff --git a/cmake/TribolCompilerFlags.cmake b/cmake/TribolCompilerFlags.cmake index 8985f91d..59b47038 100644 --- a/cmake/TribolCompilerFlags.cmake +++ b/cmake/TribolCompilerFlags.cmake @@ -19,4 +19,3 @@ string(APPEND CMAKE_EXE_LINKER_FLAGS " -rdynamic") if(APPLE) string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-no_warn_duplicate_libraries") endif() - diff --git a/cmake/thirdparty/SetupMFEM.cmake b/cmake/thirdparty/SetupMFEM.cmake index 412fee6b..961c7e32 100644 --- a/cmake/thirdparty/SetupMFEM.cmake +++ b/cmake/thirdparty/SetupMFEM.cmake @@ -19,6 +19,8 @@ set(_MFEM_DIR ${MFEM_DIR}) # Save MFEM_DIR as a non-cache variable find_package(MFEM CONFIG NO_DEFAULT_PATH PATHS "${MFEM_DIR}/lib/cmake/mfem") # find_package will overwrite MFEM_DIR, so restore it here set(MFEM_DIR ${_MFEM_DIR} CACHE PATH "" FORCE) +set(_mfem_uses_mpi FALSE) +set(_mfem_uses_openmp FALSE) if(MFEM_FOUND) # MFEM was built with CMake so use that config file @@ -26,6 +28,12 @@ if(MFEM_FOUND) set(MFEM_BUILT_WITH_CMAKE TRUE) # It looks like include directories are not always built into the target target_include_directories(mfem INTERFACE ${MFEM_INCLUDE_DIRS}) + if(MFEM_USE_MPI) + set(_mfem_uses_mpi TRUE) + endif() + if(MFEM_USE_OPENMP OR MFEM_USE_LEGACY_OPENMP) + set(_mfem_uses_openmp TRUE) + endif() else() set(MFEM_BUILT_WITH_CMAKE FALSE) find_path( @@ -68,6 +76,12 @@ else() # read config.mk file file(READ "${MFEM_CFG_DIR}/config.mk" mfem_cfg_file_txt) + if(mfem_cfg_file_txt MATCHES "MFEM_USE_MPI[ \\t]*\\+?=[ \\t]*YES") + set(_mfem_uses_mpi TRUE) + endif() + if(mfem_cfg_file_txt MATCHES "MFEM_USE_(LEGACY_)?OPENMP[ \\t]*\\+?=[ \\t]*YES") + set(_mfem_uses_openmp TRUE) + endif() # parse include flags string(REGEX MATCHALL "MFEM_TPLFLAGS [^\n]+\n" mfem_tpl_inc_flags ${mfem_cfg_file_txt}) @@ -128,16 +142,26 @@ else() TREAT_INCLUDES_AS_SYSTEM ON EXPORTABLE ON) - # Tribol edit - if(TRIBOL_USE_MPI) +endif() + +if(_mfem_uses_mpi) + if(NOT TARGET blt::mpi) + message(FATAL_ERROR "MFEM was built with MPI support, but MPI is not enabled in BLT. Configure with ENABLE_MPI=ON.") + endif() + if(NOT MFEM_BUILT_WITH_CMAKE) # Note: -lmpifort is being added to MFEM's link line w/o a -L list(GET MPI_C_LIBRARIES 0 _first_mpi_lib) get_filename_component(_mpi_lib_dir ${_first_mpi_lib} DIRECTORY) target_link_directories(mfem INTERFACE ${_mpi_lib_dir}) - target_link_libraries(mfem INTERFACE mpi) endif() - # End Tribol edit + target_link_libraries(mfem INTERFACE blt::mpi) +endif() +if(_mfem_uses_openmp) + if(NOT TARGET blt::openmp) + message(FATAL_ERROR "MFEM was built with OpenMP support, but OpenMP is not enabled in BLT. Configure with ENABLE_OPENMP=ON.") + endif() + target_link_libraries(mfem INTERFACE blt::openmp) endif() include(FindPackageHandleStandardArgs) diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 088b821e..118ca0d9 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -251,9 +251,6 @@ endif() if( MFEM_FOUND ) set(mfem_smoke_depends mfem gtest) - # MFEM may require OpenMP even when Tribol does not, and FindMFEM.cmake does not propagate that dependency. - blt_list_append(TO mfem_smoke_depends ELEMENTS blt::openmp IF ENABLE_OPENMP ) - blt_list_append(TO mfem_smoke_depends ELEMENTS blt::mpi IF TRIBOL_USE_MPI ) blt_add_executable( NAME mfem_smoke_test SOURCES mfem_smoke.cpp diff --git a/src/tests/tribol_comp_geom_3d.cpp b/src/tests/tribol_comp_geom_3d.cpp index 86042237..523aebe3 100644 --- a/src/tests/tribol_comp_geom_3d.cpp +++ b/src/tests/tribol_comp_geom_3d.cpp @@ -88,7 +88,7 @@ class CompGeomTest : public ::testing::Test { tribol::setKinematicConstantPenalty( meshId, 1.0 ); - return tribol::update( 1, 1., dt ); + const int update_err = tribol::update( 1, 1., dt ); delete[] fx; delete[] fy; @@ -96,6 +96,8 @@ class CompGeomTest : public ::testing::Test { delete[] vx; delete[] vy; delete[] vz; + + return update_err; } protected: diff --git a/src/tribol/geom/CompGeom.hpp b/src/tribol/geom/CompGeom.hpp index 5c420810..cffbb483 100644 --- a/src/tribol/geom/CompGeom.hpp +++ b/src/tribol/geom/CompGeom.hpp @@ -960,7 +960,7 @@ TRIBOL_HOST_DEVICE inline FaceGeomException CheckInterfacePairByMethod( InterfacePair& pair, const MeshData::Viewer& mesh1, const MeshData::Viewer& mesh2, const Parameters& params, ContactCase TRIBOL_UNUSED_PARAM( cCase ), bool& isInteracting, CompGeom::Viewer& cg, IndexT* plane_ct ) { - auto dim = static_cast( mesh1.spatialDimension() ); + auto dim = mesh1.spatialDimension(); T my_plane( &pair, params, dim ); FaceGeomException face_err = NO_FACE_GEOM_EXCEPTION; if ( dim == 3 ) { @@ -2151,7 +2151,8 @@ TRIBOL_HOST_DEVICE inline FaceGeomException CommonPlanePair::computeOverlap3D( c cx[2], 1, &xInter_local, &yInter_local ); // get the local coordinates of the other face's centroid - RealT cx_other_local, cy_other_local; + RealT cx_other_local = 0; + RealT cy_other_local = 0; RealT cz = 0.; // dummy arg. VertexAvgCentroid( &x_other_local[0], &y_other_local[0], nullptr, num_nodes_other, cx_other_local, cy_other_local, cz ); @@ -2465,6 +2466,9 @@ TRIBOL_HOST_DEVICE inline FaceGeomException CommonPlanePair::projectPointsAndCom << "input number of vertices to match number of nodes per element." ); } } +#else + TRIBOL_UNUSED_VAR( m1 ); + TRIBOL_UNUSED_VAR( m2 ); #endif constexpr int max_nodes_per_clipped_face = 5; diff --git a/src/tribol/geom/GeomUtilities.hpp b/src/tribol/geom/GeomUtilities.hpp index 88f9e461..7cc6bf41 100644 --- a/src/tribol/geom/GeomUtilities.hpp +++ b/src/tribol/geom/GeomUtilities.hpp @@ -8,8 +8,8 @@ #include #include -#include +#include "axom/core/NumericLimits.hpp" #include "axom/slic.hpp" #include "tribol/common/Parameters.hpp" @@ -1895,7 +1895,7 @@ TRIBOL_HOST_DEVICE inline void PolyInterYCentroid( const int namax, const RealT* RealT vol; // calculate origin shift to avoid roundoff errors - RealT realt_max = std::numeric_limits::max(); + RealT realt_max = axom::numeric_limits::max(); // clang-format off RealT xorg = realt_max; diff --git a/src/tribol/integ/FE.hpp b/src/tribol/integ/FE.hpp index 9281dc1e..56e9dc8d 100644 --- a/src/tribol/integ/FE.hpp +++ b/src/tribol/integ/FE.hpp @@ -472,6 +472,7 @@ TRIBOL_HOST_DEVICE inline void GalerkinEval( const RealT* const x, const RealT p TRIBOL_HOST_DEVICE inline void EvalBasis( const RealT* const x, const RealT pX, const RealT pY, const RealT pZ, const int numPoints, const int vertexId, RealT& phi ) { + phi = 0.; if ( numPoints > 2 ) { WachspressBasis( x, pX, pY, pZ, numPoints, vertexId, phi ); } else if ( numPoints == 2 ) { @@ -524,14 +525,16 @@ TRIBOL_HOST_DEVICE inline void SegmentBasis( const RealT* const x, const RealT p TRIBOL_HOST_DEVICE inline void WachspressBasis( const RealT* const x, const RealT pX, const RealT pY, const RealT pZ, const int numPoints, const int vertexId, RealT& phi ) { + constexpr int max_nodes_per_elem = 4; #ifdef TRIBOL_USE_HOST SLIC_ERROR_IF( numPoints < 3, "WachspressBasis: numPoints < 3." ); + SLIC_ERROR_IF( numPoints > max_nodes_per_elem, "WachspressBasis: numPoints > 4." ); + SLIC_ERROR_IF( vertexId < 0 || vertexId >= numPoints, "WachspressBasis: vertexId is out of bounds." ); #endif // first compute the areas of all the triangles formed by the i-1,i,i+1 vertices. // These consist of all the numerators in the Wachspress formulation // NOTE: this limits the routine to 4 noded quadrilaterals - constexpr int max_nodes_per_elem = 4; RealT triVertArea[max_nodes_per_elem]; for ( int i = 0; i < numPoints; ++i ) { // determine the i-1, i, i+1 vertices @@ -585,7 +588,7 @@ TRIBOL_HOST_DEVICE inline void WachspressBasis( const RealT* const x, const Real // third, compute all of the weights per Wachspress formulation RealT weight[max_nodes_per_elem]; - RealT myWeight; + RealT myWeight = 0.; RealT weightSum = 0.; for ( int i = 0; i < numPoints; ++i ) { int vId = i; diff --git a/src/tribol/mesh/CouplingScheme.hpp b/src/tribol/mesh/CouplingScheme.hpp index 8b62ca86..b053d126 100644 --- a/src/tribol/mesh/CouplingScheme.hpp +++ b/src/tribol/mesh/CouplingScheme.hpp @@ -128,7 +128,7 @@ class CouplingScheme { * * @return spatial dimension */ - TRIBOL_HOST_DEVICE int spatialDimension() const { return static_cast( m_mesh1.spatialDimension() ); } + TRIBOL_HOST_DEVICE int spatialDimension() const { return m_mesh1.spatialDimension(); } /** * @brief Return a view of the first mesh in the coupling scheme @@ -1072,7 +1072,7 @@ TRIBOL_HOST_DEVICE inline bool CouplingScheme::Viewer::pruneMethodFacePair( cons auto& mesh1 = this->getMesh1View(); auto& mesh2 = this->getMesh2View(); - int dim = static_cast( mesh1.spatialDimension() ); + int dim = mesh1.spatialDimension(); int num_nodes_face_1 = static_cast( mesh1.numberOfNodesPerElement() ); int num_nodes_face_2 = static_cast( mesh2.numberOfNodesPerElement() ); @@ -1111,7 +1111,8 @@ TRIBOL_HOST_DEVICE inline bool CouplingScheme::Viewer::pruneMethodFacePair( cons } } - RealT nrml[max_dim], cx[max_dim]; + RealT nrml[max_dim]{}; + RealT cx[max_dim]{}; switch ( m_contact_method ) { case ALIGNED_MORTAR: diff --git a/src/tribol/mesh/MeshData.hpp b/src/tribol/mesh/MeshData.hpp index 75d958b3..a145119b 100644 --- a/src/tribol/mesh/MeshData.hpp +++ b/src/tribol/mesh/MeshData.hpp @@ -159,7 +159,7 @@ class MeshData { * * @return spatial dimension */ - TRIBOL_HOST_DEVICE IndexT spatialDimension() const { return m_position.size(); } + TRIBOL_HOST_DEVICE int spatialDimension() const { return static_cast( m_position.size() ); } /** * @brief Number of nodes in the mesh diff --git a/src/tribol/physics/AlignedMortar.cpp b/src/tribol/physics/AlignedMortar.cpp index a9aac9ec..fb216298 100644 --- a/src/tribol/physics/AlignedMortar.cpp +++ b/src/tribol/physics/AlignedMortar.cpp @@ -34,7 +34,9 @@ void ComputeAlignedMortarWeights( SurfaceContactElem& elem ) // also initializes the array elem.allocateMortarWts(); - RealT phiNonmortarA, phiNonmortarB, phiMortarA; + RealT phiNonmortarA = 0.; + RealT phiNonmortarB = 0.; + RealT phiMortarA = 0.; // loop over nodes "a", where node "a" can be a nonmortar node or a mortar node for ( int a = 0; a < elem.numFaceVert; ++a ) { @@ -84,8 +86,7 @@ void ComputeNodalGap( SurfaceContactElem& elem ) // set the distance magnitude tolerance as the longest edge of // the mortar face - RealT magTol; - RealT magTest = 0.; + RealT magTol = 0.; for ( int k = 0; k < elem.numFaceVert; ++k ) { int idPlus = ( k == ( elem.numFaceVert - 1 ) ) ? 0 : k + 1; RealT dx = elem.faceCoords1[elem.dim * idPlus] - elem.faceCoords1[elem.dim * k]; @@ -94,8 +95,7 @@ void ComputeNodalGap( SurfaceContactElem& elem ) RealT mag = magnitude( dx, dy, dz ); - magTol = ( mag > magTest ) ? mag : magTest; - magTest = mag; + magTol = ( mag > magTol ) ? mag : magTol; } // loop over nodes on nonmortar side @@ -113,7 +113,7 @@ void ComputeNodalGap( SurfaceContactElem& elem ) // determine which mortar node is aligned with // nonmortar node "a" ////////////////////////////////////////////// - int mortarNodeId; + int mortarNodeId = -1; RealT v[3] = { 0., 0., 0. }; RealT magTest = magTol; // loop over nodes on the mortar side @@ -130,6 +130,11 @@ void ComputeNodalGap( SurfaceContactElem& elem ) } } + SLIC_ERROR_IF( mortarNodeId < 0, "ComputeNodalGap< ALIGNED_MORTAR >: unable to find an aligned mortar node." ); + if ( mortarNodeId < 0 ) { + continue; + } + // store local gap v[0] = elem.faceCoords1[elem.dim * mortarNodeId] - elem.faceCoords2[elem.dim * a]; v[1] = elem.faceCoords1[elem.dim * mortarNodeId + 1] - elem.faceCoords2[elem.dim * a + 1]; diff --git a/src/tribol/physics/ContactFormulationFactory.cpp b/src/tribol/physics/ContactFormulationFactory.cpp index beaed413..22b682dc 100644 --- a/src/tribol/physics/ContactFormulationFactory.cpp +++ b/src/tribol/physics/ContactFormulationFactory.cpp @@ -18,18 +18,18 @@ std::unique_ptr createContactFormulation( CouplingScheme* cs } if ( cs->getContactMethod() == ENERGY_MORTAR ) { +#if defined( TRIBOL_USE_ENZYME ) && defined( BUILD_REDECOMP ) // Default parameters for now, or extract from CouplingScheme if available double k = 1000.0; double delta = 0.1; int N = 3; bool enzyme_quadrature = true; + // ENERGY_MORTAR supports a penalty-style mode driven by the kinematic penalty parameters, even if the coupling // scheme is registered with LM enforcement (which is often done to enable submesh/pressure infrastructure). const auto& penalty_opts = cs->getEnforcementOptions().penalty_options; - // TODO: Figure out how contact formulations interact with coupling scheme duplication (SRW) - bool use_penalty_ = penalty_opts.kinematic_calc_set; + bool use_penalty = penalty_opts.kinematic_calc_set; -#if defined( TRIBOL_USE_ENZYME ) && defined( BUILD_REDECOMP ) if ( cs->hasMfemData() ) { // Attempt to get penalty from MfemMeshData if available auto* k1_ptr = cs->getMfemMeshData()->GetMesh1KinematicConstantPenalty(); @@ -45,7 +45,7 @@ std::unique_ptr createContactFormulation( CouplingScheme* cs return std::make_unique( *cs->getMfemMeshData(), *cs->getMfemSubmeshData(), *cs->getMfemJacobianData(), k, delta, N, enzyme_quadrature, - use_penalty_ ); + use_penalty ); #else SLIC_ERROR_ROOT( "ENERGY_MORTAR requires Enzyme and redecomp to be built." ); return nullptr; diff --git a/src/tribol/physics/Mortar.cpp b/src/tribol/physics/Mortar.cpp index fd75170e..03303af1 100644 --- a/src/tribol/physics/Mortar.cpp +++ b/src/tribol/physics/Mortar.cpp @@ -56,7 +56,9 @@ void ComputeMortarWeights( SurfaceContactElem& elem ) // also initializes the array elem.allocateMortarWts(); - RealT phiNonmortarA, phiNonmortarB, phiMortarA; + RealT phiNonmortarA = 0.; + RealT phiNonmortarB = 0.; + RealT phiMortarA = 0.; // loop over number of nodes on the nonmortar or mortar depending on whether forming // nonmortar/nonmortar or mortar/nonmortar weights diff --git a/src/tribol/search/InterfacePairFinder.cpp b/src/tribol/search/InterfacePairFinder.cpp index ad2bcb30..19031a94 100644 --- a/src/tribol/search/InterfacePairFinder.cpp +++ b/src/tribol/search/InterfacePairFinder.cpp @@ -490,7 +490,7 @@ class BvhSearch : public SearchBase { { auto boxes_view = boxes.view(); forAllExec( m_coupling_scheme->getExecutionMode(), mesh.numberOfElements(), - [this, mesh, boxes_view, binning_proximity] TRIBOL_HOST_DEVICE( IndexT i ) { + [mesh, boxes_view, binning_proximity] TRIBOL_HOST_DEVICE( IndexT i ) { BoxT box; auto num_nodes_per_elem = mesh.numberOfNodesPerElement(); for ( IndexT j{ 0 }; j < num_nodes_per_elem; ++j ) { @@ -516,7 +516,7 @@ class BvhSearch : public SearchBase { * Expands bounding box by projecting the face normal by a distance * equal to the effective face radius */ - TRIBOL_HOST_DEVICE void expandBBoxNormal( BoxT& bbox, const VectorT& faceNormal, const RealT faceRadius ) + TRIBOL_HOST_DEVICE static void expandBBoxNormal( BoxT& bbox, const VectorT& faceNormal, const RealT faceRadius ) { PointT p0 = bbox.getCentroid(); RayT outwardRay( p0, faceNormal ); diff --git a/src/tribol/utils/TestUtils.cpp b/src/tribol/utils/TestUtils.cpp index 533acdec..f09bd38c 100644 --- a/src/tribol/utils/TestUtils.cpp +++ b/src/tribol/utils/TestUtils.cpp @@ -1767,7 +1767,7 @@ void TestMesh::testMeshToVtk( const std::string& dir, int cycle, RealT time ) // specify integer id for each cell type. mesh << "CELL_TYPES " << this->numTotalElements << std::endl; - int element_id; + int element_id = -1; switch ( this->numNodesPerElement ) { case 8: element_id = 12; // vtk 8-node hexahedron