diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/CMakeLists.txt b/Sofa/Component/SolidMechanics/FEM/Elastic/CMakeLists.txt
index 2602f434a89..28716799cb0 100644
--- a/Sofa/Component/SolidMechanics/FEM/Elastic/CMakeLists.txt
+++ b/Sofa/Component/SolidMechanics/FEM/Elastic/CMakeLists.txt
@@ -7,12 +7,20 @@ set(HEADER_FILES
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/config.h.in
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/init.h
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/fwd.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/BaseElementLinearFEMForceField.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/BaseElementLinearFEMForceField.inl
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/BaseLinearElasticityFEMForceField.h
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/BaseLinearElasticityFEMForceField.inl
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/BeamFEMForceField.h
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/BeamFEMForceField.inl
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/ElementCorotationalFEMForceField.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/ElementCorotationalFEMForceField.inl
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/ElementLinearSmallStrainFEMForceField.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/ElementLinearSmallStrainFEMForceField.inl
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/FastTetrahedralCorotationalForceField.h
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/FastTetrahedralCorotationalForceField.inl
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/FEMForceField.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/FEMForceField.inl
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/HexahedralFEMForceField.h
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/HexahedralFEMForceField.inl
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/HexahedralFEMForceFieldAndMass.h
@@ -37,13 +45,46 @@ set(HEADER_FILES
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/TriangularFEMForceField.inl
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/TriangularFEMForceFieldOptim.h
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/TriangularFEMForceFieldOptim.inl
+
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/finiteelement/FiniteElement.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/finiteelement/FiniteElement[all].h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/finiteelement/FiniteElement[Edge].h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/finiteelement/FiniteElement[Hexahedron].h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/finiteelement/FiniteElement[Quad].h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/finiteelement/FiniteElement[Tetrahedron].h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/finiteelement/FiniteElement[Triangle].h
+
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/impl/ComputeStrategy.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/impl/ElementStiffnessMatrix.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/impl/FullySymmetric4Tensor.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/impl/IsotropicElasticityTensor.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/impl/KroneckerDelta.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/impl/LameParameters.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/impl/MatrixTools.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/impl/StrainDisplacement.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/impl/SymmetricTensor.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/impl/VectorTools.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/impl/VecView.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/impl/VoigtNotation.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/impl/trait.h
+
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/impl/rotations/HexahedronRotation.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/impl/rotations/IdentityRotation.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/impl/rotations/PolarDecomposition.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/impl/rotations/RotationMethodsContainer.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/impl/rotations/StablePolarDecomposition.h
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/impl/rotations/TriangleRotation.h
)
set(SOURCE_FILES
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/init.cpp
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/BaseElementLinearFEMForceField.cpp
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/BaseLinearElasticityFEMForceField.cpp
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/BeamFEMForceField.cpp
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/ElementCorotationalFEMForceField.cpp
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/ElementLinearSmallStrainFEMForceField.cpp
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/FastTetrahedralCorotationalForceField.cpp
+ ${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/FEMForceField.cpp
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/HexahedralFEMForceField.cpp
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/HexahedralFEMForceFieldAndMass.cpp
${SOFACOMPONENTSOLIDMECHANICSFEMELASTIC_SOURCE_DIR}/HexahedronFEMForceField.cpp
diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BaseElementLinearFEMForceField.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BaseElementLinearFEMForceField.cpp
new file mode 100644
index 00000000000..2030ac9cb0d
--- /dev/null
+++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BaseElementLinearFEMForceField.cpp
@@ -0,0 +1,37 @@
+/******************************************************************************
+* SOFA, Simulation Open-Framework Architecture *
+* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
+* *
+* This program is free software; you can redistribute it and/or modify it *
+* under the terms of the GNU Lesser General Public License as published by *
+* the Free Software Foundation; either version 2.1 of the License, or (at *
+* your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details. *
+* *
+* You should have received a copy of the GNU Lesser General Public License *
+* along with this program. If not, see . *
+*******************************************************************************
+* Authors: The SOFA Team and external contributors (see Authors.txt) *
+* *
+* Contact information: contact@sofa-framework.org *
+******************************************************************************/
+#define ELASTICITY_COMPONENT_BASE_ELEMENT_LINEAR_FEM_FORCEFIELD_CPP
+#include
+#include
+
+namespace sofa::component::solidmechanics::fem::elastic
+{
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API BaseElementLinearFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API BaseElementLinearFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API BaseElementLinearFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API BaseElementLinearFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API BaseElementLinearFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API BaseElementLinearFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API BaseElementLinearFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API BaseElementLinearFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API BaseElementLinearFEMForceField;
+}
diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BaseElementLinearFEMForceField.h b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BaseElementLinearFEMForceField.h
new file mode 100644
index 00000000000..5163da659da
--- /dev/null
+++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BaseElementLinearFEMForceField.h
@@ -0,0 +1,87 @@
+/******************************************************************************
+* SOFA, Simulation Open-Framework Architecture *
+* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
+* *
+* This program is free software; you can redistribute it and/or modify it *
+* under the terms of the GNU Lesser General Public License as published by *
+* the Free Software Foundation; either version 2.1 of the License, or (at *
+* your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details. *
+* *
+* You should have received a copy of the GNU Lesser General Public License *
+* along with this program. If not, see . *
+*******************************************************************************
+* Authors: The SOFA Team and external contributors (see Authors.txt) *
+* *
+* Contact information: contact@sofa-framework.org *
+******************************************************************************/
+#pragma once
+
+#include
+#include
+#include
+
+#if !defined(ELASTICITY_COMPONENT_BASE_ELEMENT_LINEAR_FEM_FORCEFIELD_CPP)
+#include
+#endif
+
+namespace sofa::component::solidmechanics::fem::elastic
+{
+
+/**
+ * A base class for all element-based linear elastic force fields.
+ *
+ * It stores precomputed stiffness matrices (one per element) that are derived from:
+ * - The initial configuration of the mechanical model
+ * - Material properties (Young's modulus, Poisson's ratio)
+ */
+template
+class BaseElementLinearFEMForceField : public sofa::component::solidmechanics::fem::elastic::BaseLinearElasticityFEMForceField
+{
+public:
+ SOFA_ABSTRACT_CLASS(
+ SOFA_TEMPLATE2(BaseElementLinearFEMForceField, DataTypes, ElementType),
+ sofa::component::solidmechanics::fem::elastic::BaseLinearElasticityFEMForceField);
+
+ void init() override;
+
+private:
+ using trait = sofa::component::solidmechanics::fem::elastic::trait;
+ using ElementStiffness = typename trait::ElementStiffness;
+ using ElasticityTensor = typename trait::ElasticityTensor;
+ using StrainDisplacement = typename trait::StrainDisplacement;
+
+protected:
+
+ BaseElementLinearFEMForceField();
+
+ /**
+ * With linear small strain, the element stiffness matrix is constant, so it can be precomputed.
+ */
+ void precomputeElementStiffness();
+
+public:
+
+ /**
+ * List of precomputed element stiffness matrices
+ */
+ sofa::Data > d_elementStiffness;
+};
+
+#if !defined(ELASTICITY_COMPONENT_BASE_ELEMENT_LINEAR_FEM_FORCEFIELD_CPP)
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API BaseElementLinearFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API BaseElementLinearFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API BaseElementLinearFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API BaseElementLinearFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API BaseElementLinearFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API BaseElementLinearFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API BaseElementLinearFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API BaseElementLinearFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API BaseElementLinearFEMForceField;
+#endif
+
+} // namespace sofa::component::solidmechanics::fem::elastic
diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BaseElementLinearFEMForceField.inl b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BaseElementLinearFEMForceField.inl
new file mode 100644
index 00000000000..0b90dc96768
--- /dev/null
+++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/BaseElementLinearFEMForceField.inl
@@ -0,0 +1,100 @@
+/******************************************************************************
+* SOFA, Simulation Open-Framework Architecture *
+* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
+* *
+* This program is free software; you can redistribute it and/or modify it *
+* under the terms of the GNU Lesser General Public License as published by *
+* the Free Software Foundation; either version 2.1 of the License, or (at *
+* your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details. *
+* *
+* You should have received a copy of the GNU Lesser General Public License *
+* along with this program. If not, see . *
+*******************************************************************************
+* Authors: The SOFA Team and external contributors (see Authors.txt) *
+* *
+* Contact information: contact@sofa-framework.org *
+******************************************************************************/
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+
+namespace sofa::component::solidmechanics::fem::elastic
+{
+
+template
+BaseElementLinearFEMForceField::BaseElementLinearFEMForceField()
+ : d_elementStiffness(initData(&d_elementStiffness, "elementStiffness", "List of stiffness matrices per element"))
+{
+ this->addUpdateCallback("precomputeStiffness", {&this->d_youngModulus, &this->d_poissonRatio},
+ [this](const sofa::core::DataTracker& )
+ {
+ precomputeElementStiffness();
+ return this->getComponentState();
+ }, {});
+}
+
+template
+void BaseElementLinearFEMForceField::init()
+{
+ sofa::component::solidmechanics::fem::elastic::BaseLinearElasticityFEMForceField::init();
+
+ if (!this->isComponentStateInvalid())
+ {
+ this->precomputeElementStiffness();
+ }
+}
+
+template
+void BaseElementLinearFEMForceField::precomputeElementStiffness()
+{
+ if (!this->l_topology)
+ return;
+
+ if (this->isComponentStateInvalid())
+ return;
+
+ if (!this->mstate)
+ return;
+
+ const auto youngModulusAccessor = sofa::helper::ReadAccessor(this->d_youngModulus);
+ const auto poissonRatioAccessor = sofa::helper::ReadAccessor(this->d_poissonRatio);
+
+ auto restPositionAccessor = this->mstate->readRestPositions();
+
+ const auto& elements = trait::FiniteElement::getElementSequence(*this->l_topology);
+
+ auto elementStiffness = sofa::helper::getWriteOnlyAccessor(d_elementStiffness);
+ elementStiffness.resize(elements.size());
+
+ SCOPED_TIMER("precomputeStiffness");
+ sofa::helper::IotaView indices {static_cast(0ul), elements.size()};
+ std::for_each(indices.begin(), indices.end(),
+ [&](const auto elementId)
+ {
+ const auto& element = elements[elementId];
+
+ const auto youngModulus = this->getYoungModulusInElement(elementId);
+ const auto poissonRatio = this->getPoissonRatioInElement(elementId);
+
+ const auto [mu, lambda] = sofa::component::solidmechanics::fem::elastic::toLameParameters(youngModulus, poissonRatio);
+
+ const auto elasticityTensor = makeIsotropicElasticityTensor(mu, lambda);
+
+ const std::array, trait::NumberOfNodesInElement> nodesCoordinates = extractNodesVectorFromGlobalVector(element, restPositionAccessor.ref());
+ elementStiffness[elementId] = integrate(nodesCoordinates, elasticityTensor);
+ });
+}
+
+}
diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/ElementCorotationalFEMForceField.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/ElementCorotationalFEMForceField.cpp
new file mode 100644
index 00000000000..36b65ff9d12
--- /dev/null
+++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/ElementCorotationalFEMForceField.cpp
@@ -0,0 +1,64 @@
+/******************************************************************************
+* SOFA, Simulation Open-Framework Architecture *
+* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
+* *
+* This program is free software; you can redistribute it and/or modify it *
+* under the terms of the GNU Lesser General Public License as published by *
+* the Free Software Foundation; either version 2.1 of the License, or (at *
+* your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details. *
+* *
+* You should have received a copy of the GNU Lesser General Public License *
+* along with this program. If not, see . *
+*******************************************************************************
+* Authors: The SOFA Team and external contributors (see Authors.txt) *
+* *
+* Contact information: contact@sofa-framework.org *
+******************************************************************************/
+#define ELASTICITY_COMPONENT_ELEMENT_COROTATIONAL_FEM_FORCE_FIELD_CPP
+
+#include
+
+#include
+#include
+
+namespace sofa::component::solidmechanics::fem::elastic
+{
+
+void registerElementCorotationalFEMForceField(sofa::core::ObjectFactory* factory)
+{
+ factory->registerObjects(sofa::core::ObjectRegistrationData("Hooke's law on linear beams using the corotational approach")
+ // .add< ElementCorotationalFEMForceField >()
+ .add< ElementCorotationalFEMForceField >()
+ .add< ElementCorotationalFEMForceField >(true));
+
+ factory->registerObjects(sofa::core::ObjectRegistrationData("Hooke's law on linear triangles using the corotational approach")
+ .add< ElementCorotationalFEMForceField >()
+ .add< ElementCorotationalFEMForceField >(true));
+
+ factory->registerObjects(sofa::core::ObjectRegistrationData("Hooke's law on linear quads using the corotational approach")
+ .add< ElementCorotationalFEMForceField >()
+ .add< ElementCorotationalFEMForceField >(true));
+
+ factory->registerObjects(sofa::core::ObjectRegistrationData("Hooke's law on linear tetrahedra using the corotational approach")
+ .add< ElementCorotationalFEMForceField >(true));
+
+ factory->registerObjects(sofa::core::ObjectRegistrationData("Hooke's law on linear hexahedra using the corotational approach")
+ .add< ElementCorotationalFEMForceField >(true));
+}
+
+// template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementCorotationalFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementCorotationalFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementCorotationalFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementCorotationalFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementCorotationalFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementCorotationalFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementCorotationalFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementCorotationalFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementCorotationalFEMForceField;
+
+}
diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/ElementCorotationalFEMForceField.h b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/ElementCorotationalFEMForceField.h
new file mode 100644
index 00000000000..7bfc3c303f0
--- /dev/null
+++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/ElementCorotationalFEMForceField.h
@@ -0,0 +1,203 @@
+/******************************************************************************
+* SOFA, Simulation Open-Framework Architecture *
+* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
+* *
+* This program is free software; you can redistribute it and/or modify it *
+* under the terms of the GNU Lesser General Public License as published by *
+* the Free Software Foundation; either version 2.1 of the License, or (at *
+* your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details. *
+* *
+* You should have received a copy of the GNU Lesser General Public License *
+* along with this program. If not, see . *
+*******************************************************************************
+* Authors: The SOFA Team and external contributors (see Authors.txt) *
+* *
+* Contact information: contact@sofa-framework.org *
+******************************************************************************/
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if !defined(ELASTICITY_COMPONENT_ELEMENT_COROTATIONAL_FEM_FORCE_FIELD_CPP)
+#include
+#endif
+
+namespace sofa::component::solidmechanics::fem::elastic
+{
+
+/**
+ * @brief A container for rotation computation methods in corotational formulations
+ *
+ * This class provides element-specific rotation computation strategies for common element types.
+ *
+ * @tparam DataTypes The data type used throughout the simulation (e.g., sofa::defaulttype::Vec3Types for 3D)
+ * @tparam ElementType The element type (e.g., sofa::geometry::Triangle, sofa::geometry::Tetrahedron)
+ *
+ * Inherits from RotationMethodsContainer with pre-defined rotation strategies.
+ *
+ * The class is specialized for some elements because some rotation strategies can be used only
+ * for specific elements.
+ */
+template
+struct RotationMethods : RotationMethodsContainer, PolarDecomposition, IdentityRotation
+>
+{
+ using Inherit = RotationMethodsContainer, PolarDecomposition, IdentityRotation>;
+ explicit RotationMethods(sofa::core::objectmodel::BaseObject* parent) : Inherit(parent)
+ {}
+};
+
+template
+using Vec3Real = sofa::defaulttype::StdVectorTypes, sofa::type::Vec<3, Real>, Real>;
+
+//partial specialization for linear triangle in 3D
+template
+struct RotationMethods, sofa::geometry::Triangle> : RotationMethodsContainer, sofa::geometry::Triangle,
+ StablePolarDecomposition>, PolarDecomposition>, IdentityRotation, TriangleRotation>
+>
+{
+ using Inherit = RotationMethodsContainer, sofa::geometry::Triangle,
+ StablePolarDecomposition>, PolarDecomposition>, IdentityRotation, TriangleRotation> >;
+
+ explicit RotationMethods(sofa::core::objectmodel::BaseObject* parent) : Inherit(parent)
+ {
+ this->d_rotationMethod.setValue(TriangleRotation>::getItem().key);
+ }
+};
+
+//partial specialization for linear tetrahedron
+template
+struct RotationMethods : RotationMethodsContainer, PolarDecomposition, IdentityRotation, TriangleRotation
+>
+{
+ using Inherit = RotationMethodsContainer, PolarDecomposition, IdentityRotation, TriangleRotation >;
+
+ explicit RotationMethods(sofa::core::objectmodel::BaseObject* parent) : Inherit(parent)
+ {
+ this->d_rotationMethod.setValue(TriangleRotation::getItem().key);
+ }
+};
+
+//partial specialization for linear hexahedron
+template
+struct RotationMethods : RotationMethodsContainer, PolarDecomposition, IdentityRotation, HexahedronRotation
+>
+{
+ using Inherit = RotationMethodsContainer, PolarDecomposition, IdentityRotation, HexahedronRotation >;
+
+ explicit RotationMethods(sofa::core::objectmodel::BaseObject* parent) : Inherit(parent)
+ {
+ this->d_rotationMethod.setValue(HexahedronRotation::getItem().key);
+ }
+};
+
+
+template
+class ElementCorotationalFEMForceField :
+ public BaseElementLinearFEMForceField,
+ public FEMForceField
+{
+public:
+ SOFA_CLASS2(
+ SOFA_TEMPLATE2(ElementCorotationalFEMForceField, DataTypes, ElementType),
+ SOFA_TEMPLATE2(BaseElementLinearFEMForceField, DataTypes, ElementType),
+ SOFA_TEMPLATE2(FEMForceField, DataTypes, ElementType));
+
+ /**
+ * The purpose of this function is to register the name of this class according to the provided
+ * pattern.
+ *
+ * Example: ElementCorotationalFEMForceField will produce
+ * the class name "EdgeCorotationalFEMForceField".
+ */
+ static const std::string GetCustomClassName()
+ {
+ return std::string(sofa::geometry::elementTypeToString(ElementType::Element_type)) +
+ "CorotationalFEMForceField";
+ }
+
+ static const std::string GetCustomTemplateName() { return DataTypes::Name(); }
+
+private:
+ using trait = sofa::component::solidmechanics::fem::elastic::trait;
+ using ElementForce = typename trait::ElementForce;
+ using RotationMatrix = sofa::type::Mat>;
+
+
+public:
+
+ ElementCorotationalFEMForceField();
+
+ void init() override;
+
+ void buildStiffnessMatrix(sofa::core::behavior::StiffnessMatrix* matrix) override;
+
+ SReal getPotentialEnergy(const sofa::core::MechanicalParams*, const sofa::DataVecCoord_t& x) const override;
+
+ const sofa::type::vector& getElementRotations() const { return m_rotations; }
+
+protected:
+
+ void beforeElementForce(const sofa::core::MechanicalParams* mparams,
+ sofa::type::vector& f,
+ const sofa::VecCoord_t& x) override;
+
+ void computeElementsForces(
+ const sofa::simulation::Range& range,
+ const sofa::core::MechanicalParams* mparams,
+ sofa::type::vector& f,
+ const sofa::VecCoord_t& x) override;
+
+ void computeElementsForcesDeriv(
+ const sofa::simulation::Range& range,
+ const sofa::core::MechanicalParams* mparams,
+ sofa::type::vector& elementForcesDeriv,
+ const sofa::VecDeriv_t& nodeDx) override;
+
+ sofa::type::vector m_rotations;
+ sofa::type::vector m_initialRotationsTransposed;
+
+ sofa::Coord_t translation(const std::array, trait::NumberOfNodesInElement>& nodes) const;
+ static sofa::Coord_t computeCentroid(const std::array, trait::NumberOfNodesInElement>& nodes);
+
+ RotationMethods m_rotationMethods;
+
+ void computeRotations(sofa::type::vector& rotations,
+ const sofa::VecCoord_t& nodePositions,
+ const sofa::VecCoord_t& nodeRestPositions);
+ void computeInitialRotations();
+};
+
+
+
+#if !defined(ELASTICITY_COMPONENT_ELEMENT_COROTATIONAL_FEM_FORCE_FIELD_CPP)
+// extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementCorotationalFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementCorotationalFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementCorotationalFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementCorotationalFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementCorotationalFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementCorotationalFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementCorotationalFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementCorotationalFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementCorotationalFEMForceField;
+#endif
+
+} // namespace sofa::component::solidmechanics::fem::elastic
diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/ElementCorotationalFEMForceField.inl b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/ElementCorotationalFEMForceField.inl
new file mode 100644
index 00000000000..d618649030d
--- /dev/null
+++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/ElementCorotationalFEMForceField.inl
@@ -0,0 +1,277 @@
+/******************************************************************************
+* SOFA, Simulation Open-Framework Architecture *
+* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
+* *
+* This program is free software; you can redistribute it and/or modify it *
+* under the terms of the GNU Lesser General Public License as published by *
+* the Free Software Foundation; either version 2.1 of the License, or (at *
+* your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details. *
+* *
+* You should have received a copy of the GNU Lesser General Public License *
+* along with this program. If not, see . *
+*******************************************************************************
+* Authors: The SOFA Team and external contributors (see Authors.txt) *
+* *
+* Contact information: contact@sofa-framework.org *
+******************************************************************************/
+#pragma once
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+namespace sofa::component::solidmechanics::fem::elastic
+{
+
+template
+ElementCorotationalFEMForceField::ElementCorotationalFEMForceField()
+ : m_rotationMethods(this)
+{
+ this->addUpdateCallback("selectRotationMethod", {&this->m_rotationMethods.d_rotationMethod},
+ [this](const sofa::core::DataTracker&)
+ {
+ m_rotationMethods.selectRotationMethod();
+ computeInitialRotations();
+ return this->getComponentState();
+ },
+ {});
+
+ m_rotationMethods.selectRotationMethod();
+}
+
+template
+void ElementCorotationalFEMForceField::init()
+{
+ BaseElementLinearFEMForceField::init();
+ FEMForceField::init();
+
+ if (!this->isComponentStateInvalid())
+ {
+ m_rotationMethods.selectRotationMethod();
+ computeInitialRotations();
+ }
+
+ if (!this->isComponentStateInvalid())
+ {
+ const auto& elements = trait::FiniteElement::getElementSequence(*this->l_topology);
+ }
+
+ if (!this->isComponentStateInvalid())
+ {
+ this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Valid);
+ }
+}
+
+template
+void ElementCorotationalFEMForceField::beforeElementForce(
+ const sofa::core::MechanicalParams* mparams, sofa::type::vector& f,
+ const sofa::VecCoord_t& x)
+{
+ const auto& elements = trait::FiniteElement::getElementSequence(*this->l_topology);
+ m_rotations.resize(elements.size(), RotationMatrix::Identity());
+}
+
+template
+void ElementCorotationalFEMForceField::computeElementsForces(
+ const sofa::simulation::Range& range, const sofa::core::MechanicalParams* mparams,
+ sofa::type::vector& elementForces, const sofa::VecCoord_t& nodePositions)
+{
+ const auto& elements = trait::FiniteElement::getElementSequence(*this->l_topology);
+ auto restPositionAccessor = this->mstate->readRestPositions();
+ auto elementStiffness = sofa::helper::getReadAccessor(this->d_elementStiffness);
+
+ for (std::size_t elementId = range.start; elementId < range.end; ++elementId)
+ {
+ const auto& element = elements[elementId];
+
+ const std::array, trait::NumberOfNodesInElement> elementNodesCoordinates =
+ extractNodesVectorFromGlobalVector(element, nodePositions);
+ const std::array, trait::NumberOfNodesInElement> restElementNodesCoordinates =
+ extractNodesVectorFromGlobalVector(element, restPositionAccessor.ref());
+
+ auto& elementInitialRotationTransposed = this->m_initialRotationsTransposed[elementId];
+ auto& elementRotation = this->m_rotations[elementId];
+
+ m_rotationMethods.computeRotation(elementRotation, elementInitialRotationTransposed, elementNodesCoordinates, restElementNodesCoordinates);
+
+ const auto t = translation(elementNodesCoordinates);
+ const auto t0 = translation(restElementNodesCoordinates);
+
+ typename trait::ElementDisplacement displacement(sofa::type::NOINIT);
+ for (sofa::Size j = 0; j < trait::NumberOfNodesInElement; ++j)
+ {
+ VecView> transformedDisplacement(displacement, j * trait::spatial_dimensions);
+ transformedDisplacement = elementRotation.multTranspose(elementNodesCoordinates[j] - t) - (restElementNodesCoordinates[j] - t0);
+ }
+
+ const auto& stiffnessMatrix = elementStiffness[elementId];
+
+ auto& elementForce = elementForces[elementId];
+ elementForce = stiffnessMatrix * displacement;
+
+ for (sofa::Size i = 0; i < trait::NumberOfNodesInElement; ++i)
+ {
+ VecView> nodeForce(elementForce, i * trait::spatial_dimensions);
+ nodeForce = elementRotation * nodeForce;
+ }
+ }
+}
+
+
+template
+void ElementCorotationalFEMForceField::computeElementsForcesDeriv(
+ const sofa::simulation::Range& range,
+ const sofa::core::MechanicalParams* mparams,
+ sofa::type::vector& elementForcesDeriv,
+ const sofa::VecDeriv_t& nodeDx)
+{
+ const auto& elements = trait::FiniteElement::getElementSequence(*this->l_topology);
+ auto elementStiffness = sofa::helper::getReadAccessor(this->d_elementStiffness);
+
+ for (std::size_t elementId = range.start; elementId < range.end; ++elementId)
+ {
+ const auto& element = elements[elementId];
+
+ const auto& elementRotation = m_rotations[elementId];
+
+ sofa::type::Vec> element_dx(sofa::type::NOINIT);
+
+ for (sofa::Size n = 0; n < trait::NumberOfNodesInElement; ++n)
+ {
+ VecView> rotated_dx(element_dx, n * trait::spatial_dimensions);
+ rotated_dx = elementRotation.multTranspose(nodeDx[element[n]]);
+ }
+
+ const auto& stiffnessMatrix = elementStiffness[elementId];
+
+ auto& df = elementForcesDeriv[elementId];
+ df = stiffnessMatrix * element_dx;
+
+ for (sofa::Size n = 0; n < trait::NumberOfNodesInElement; ++n)
+ {
+ VecView> nodedForce(df, n * trait::spatial_dimensions);
+ nodedForce = elementRotation * nodedForce;
+ }
+ }
+}
+
+template
+void ElementCorotationalFEMForceField::buildStiffnessMatrix(
+ sofa::core::behavior::StiffnessMatrix* matrix)
+{
+ auto dfdx = matrix->getForceDerivativeIn(this->sofa::core::behavior::ForceField::mstate)
+ .withRespectToPositionsIn(this->sofa::core::behavior::ForceField::mstate);
+
+ sofa::type::Mat> localMatrix(sofa::type::NOINIT);
+
+ const auto& elements = trait::FiniteElement::getElementSequence(*this->l_topology);
+ auto elementStiffness = sofa::helper::getReadAccessor(this->d_elementStiffness);
+
+ if (m_rotations.size() < elements.size() || elementStiffness.size() < elements.size())
+ {
+ return;
+ }
+
+ auto elementStiffnessIt = elementStiffness.begin();
+ auto rotationMatrixIt = m_rotations.begin();
+ for (const auto& element : elements)
+ {
+ const auto& elementRotation = *rotationMatrixIt++;
+ const auto elementRotation_T = elementRotation.transposed();
+
+ const auto& stiffnessMatrix = *elementStiffnessIt++;
+
+ for (sofa::Index n1 = 0; n1 < trait::NumberOfNodesInElement; ++n1)
+ {
+ for (sofa::Index n2 = 0; n2 < trait::NumberOfNodesInElement; ++n2)
+ {
+ stiffnessMatrix.getAssembledMatrix().getsub(trait::spatial_dimensions * n1, trait::spatial_dimensions * n2, localMatrix); // extract the submatrix corresponding to the coupling of nodes n1 and n2
+ dfdx(element[n1] * trait::spatial_dimensions, element[n2] * trait::spatial_dimensions) += -elementRotation * localMatrix * elementRotation_T;
+ }
+ }
+ }
+}
+
+template
+SReal ElementCorotationalFEMForceField::getPotentialEnergy(
+ const sofa::core::MechanicalParams*,
+ const sofa::DataVecCoord_t& x) const
+{
+ return 0;
+}
+
+template
+auto ElementCorotationalFEMForceField::translation(
+ const std::array, trait::NumberOfNodesInElement>& nodes) const -> sofa::Coord_t
+{
+ // return nodes[0];
+ return computeCentroid(nodes);
+}
+
+template
+auto ElementCorotationalFEMForceField::computeCentroid(
+ const std::array, trait::NumberOfNodesInElement>& nodes) -> sofa::Coord_t
+{
+ sofa::Coord_t centroid;
+ for (const auto node : nodes)
+ {
+ centroid += node;
+ }
+ centroid /= static_cast>(trait::NumberOfNodesInElement);
+ return centroid;
+}
+
+template
+void ElementCorotationalFEMForceField::computeRotations(
+ sofa::type::vector& rotations,
+ const sofa::VecCoord_t& nodePositions,
+ const sofa::VecCoord_t& nodeRestPositions)
+{
+ if (!this->l_topology)
+ return;
+
+ const auto& elements = trait::FiniteElement::getElementSequence(*this->l_topology);
+ sofa::helper::IotaView indices {static_cast(0ul), elements.size()};
+
+ rotations.resize(elements.size(), RotationMatrix::Identity());
+ if (m_initialRotationsTransposed.size() < elements.size())
+ {
+ m_initialRotationsTransposed.resize(elements.size(), RotationMatrix::Identity());
+ }
+
+ std::for_each(indices.begin(), indices.end(),
+ [&](const auto elementId)
+ {
+ const auto& element = elements[elementId];
+
+ const std::array, trait::NumberOfNodesInElement> elementNodesCoordinates =
+ extractNodesVectorFromGlobalVector(element, nodePositions);
+ const std::array, trait::NumberOfNodesInElement> restElementNodesCoordinates =
+ extractNodesVectorFromGlobalVector(element, nodeRestPositions);
+
+ m_rotationMethods.computeRotation(rotations[elementId], m_initialRotationsTransposed[elementId], elementNodesCoordinates, restElementNodesCoordinates);
+ }
+ );
+}
+
+template
+void ElementCorotationalFEMForceField::computeInitialRotations()
+{
+ auto restPositionAccessor = this->sofa::core::behavior::ForceField::mstate->readRestPositions();
+ computeRotations(m_initialRotationsTransposed, restPositionAccessor.ref(), restPositionAccessor.ref());
+
+ for (auto& rotation : m_initialRotationsTransposed)
+ {
+ rotation.transpose();
+ }
+}
+
+} // namespace sofa::component::solidmechanics::fem::elastic
diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/ElementLinearSmallStrainFEMForceField.cpp b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/ElementLinearSmallStrainFEMForceField.cpp
new file mode 100644
index 00000000000..227b95654d3
--- /dev/null
+++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/ElementLinearSmallStrainFEMForceField.cpp
@@ -0,0 +1,64 @@
+/******************************************************************************
+* SOFA, Simulation Open-Framework Architecture *
+* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
+* *
+* This program is free software; you can redistribute it and/or modify it *
+* under the terms of the GNU Lesser General Public License as published by *
+* the Free Software Foundation; either version 2.1 of the License, or (at *
+* your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details. *
+* *
+* You should have received a copy of the GNU Lesser General Public License *
+* along with this program. If not, see . *
+*******************************************************************************
+* Authors: The SOFA Team and external contributors (see Authors.txt) *
+* *
+* Contact information: contact@sofa-framework.org *
+******************************************************************************/
+#define ELASTICITY_COMPONENT_ELEMENT_LINEAR_SMALL_STRAIN_FEM_FORCE_FIELD_CPP
+
+#include
+
+#include
+#include
+
+namespace sofa::component::solidmechanics::fem::elastic
+{
+
+void registerElementLinearSmallStrainFEMForceField(sofa::core::ObjectFactory* factory)
+{
+ factory->registerObjects(sofa::core::ObjectRegistrationData("Hooke's law on linear beams assuming small strain")
+ .add< ElementLinearSmallStrainFEMForceField >()
+ .add< ElementLinearSmallStrainFEMForceField >()
+ .add< ElementLinearSmallStrainFEMForceField >(true));
+
+ factory->registerObjects(sofa::core::ObjectRegistrationData("Hooke's law on linear triangles assuming small strain")
+ .add< ElementLinearSmallStrainFEMForceField >()
+ .add< ElementLinearSmallStrainFEMForceField >(true));
+
+ factory->registerObjects(sofa::core::ObjectRegistrationData("Hooke's law on linear quads assuming small strain")
+ .add< ElementLinearSmallStrainFEMForceField >()
+ .add< ElementLinearSmallStrainFEMForceField >(true));
+
+ factory->registerObjects(sofa::core::ObjectRegistrationData("Hooke's law on linear tetrahedra assuming small strain")
+ .add< ElementLinearSmallStrainFEMForceField >(true));
+
+ factory->registerObjects(sofa::core::ObjectRegistrationData("Hooke's law on linear hexahedra assuming small strain")
+ .add< ElementLinearSmallStrainFEMForceField >(true));
+}
+
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementLinearSmallStrainFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementLinearSmallStrainFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementLinearSmallStrainFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementLinearSmallStrainFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementLinearSmallStrainFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementLinearSmallStrainFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementLinearSmallStrainFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementLinearSmallStrainFEMForceField;
+template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementLinearSmallStrainFEMForceField;
+
+}
diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/ElementLinearSmallStrainFEMForceField.h b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/ElementLinearSmallStrainFEMForceField.h
new file mode 100644
index 00000000000..f676e561cb3
--- /dev/null
+++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/ElementLinearSmallStrainFEMForceField.h
@@ -0,0 +1,111 @@
+/******************************************************************************
+* SOFA, Simulation Open-Framework Architecture *
+* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
+* *
+* This program is free software; you can redistribute it and/or modify it *
+* under the terms of the GNU Lesser General Public License as published by *
+* the Free Software Foundation; either version 2.1 of the License, or (at *
+* your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details. *
+* *
+* You should have received a copy of the GNU Lesser General Public License *
+* along with this program. If not, see . *
+*******************************************************************************
+* Authors: The SOFA Team and external contributors (see Authors.txt) *
+* *
+* Contact information: contact@sofa-framework.org *
+******************************************************************************/
+#pragma once
+
+#include
+#include
+#include
+
+#include
+
+#if !defined(ELASTICITY_COMPONENT_ELEMENT_LINEAR_SMALL_STRAIN_FEM_FORCE_FIELD_CPP)
+#include
+#endif
+
+namespace sofa::component::solidmechanics::fem::elastic
+{
+
+template
+class ElementLinearSmallStrainFEMForceField :
+ public BaseElementLinearFEMForceField,
+ public FEMForceField
+{
+public:
+ SOFA_CLASS2(
+ SOFA_TEMPLATE2(ElementLinearSmallStrainFEMForceField, DataTypes, ElementType),
+ SOFA_TEMPLATE2(BaseElementLinearFEMForceField, DataTypes, ElementType),
+ SOFA_TEMPLATE2(FEMForceField, DataTypes, ElementType));
+
+ /**
+ * The purpose of this function is to register the name of this class according to the provided
+ * pattern.
+ *
+ * Example: ElementLinearSmallStrainFEMForceField will produce
+ * the class name "EdgeLinearSmallStrainFEMForceField".
+ */
+ static const std::string GetCustomClassName()
+ {
+ return std::string(sofa::geometry::elementTypeToString(ElementType::Element_type)) +
+ "LinearSmallStrainFEMForceField";
+ }
+
+ static const std::string GetCustomTemplateName() { return DataTypes::Name(); }
+
+private:
+ using trait = sofa::component::solidmechanics::fem::elastic::trait;
+ using ElementStiffness = typename trait::ElementStiffness;
+ using ElasticityTensor = typename trait::ElasticityTensor;
+ using ElementDisplacement = typename trait::ElementDisplacement;
+ using StrainDisplacement = typename trait::StrainDisplacement;
+ using ElementForce = typename trait::ElementForce;
+
+public:
+ void init() override;
+
+ void buildStiffnessMatrix(sofa::core::behavior::StiffnessMatrix* matrix) override;
+
+ SReal getPotentialEnergy(const sofa::core::MechanicalParams*, const sofa::DataVecCoord_t& x) const override;
+
+ using sofa::core::behavior::ForceField::addKToMatrix;
+ // almost deprecated, but here for compatibility with unit tests
+ void addKToMatrix(sofa::linearalgebra::BaseMatrix* matrix, SReal kFact, unsigned& offset) override;
+
+protected:
+
+ void computeElementsForces(
+ const sofa::simulation::Range& range,
+ const sofa::core::MechanicalParams* mparams,
+ sofa::type::vector& elementForces,
+ const sofa::VecCoord_t& nodePositions) override;
+
+ void computeElementsForcesDeriv(
+ const sofa::simulation::Range& range,
+ const sofa::core::MechanicalParams* mparams,
+ sofa::type::vector& elementForcesDeriv,
+ const sofa::VecDeriv_t& nodeDx) override;
+
+};
+
+
+#if !defined(ELASTICITY_COMPONENT_ELEMENT_LINEAR_SMALL_STRAIN_FEM_FORCE_FIELD_CPP)
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementLinearSmallStrainFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementLinearSmallStrainFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementLinearSmallStrainFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementLinearSmallStrainFEMForceField;
+extern template class SOFA_COMPONENT_SOLIDMECHANICS_FEM_ELASTIC_API ElementLinearSmallStrainFEMForceField