Caribou
HexahedronElasticForce.h
1 #pragma once
2 
3 #include <sofa/core/behavior/ForceField.h>
4 #include <sofa/core/topology/BaseTopology.h>
5 #include <sofa/core/behavior/MechanicalState.h>
6 #include <sofa/helper/OptionsGroup.h>
7 
8 #include <Eigen/Sparse>
9 
10 #include <Caribou/Geometry/Hexahedron.h>
11 
12 namespace SofaCaribou::forcefield {
13 
14 using namespace sofa::core;
15 using namespace sofa::core::objectmodel;
16 using namespace sofa::core::behavior;
17 using namespace sofa::core::topology;
18 using sofa::defaulttype::Vec3Types;
19 
20 class HexahedronElasticForce : public ForceField<Vec3Types>
21 {
22 public:
23  SOFA_CLASS(HexahedronElasticForce, SOFA_TEMPLATE(ForceField, Vec3Types));
24 
25  // Type definitions
26  using DataTypes = Vec3Types;
27  using Inherit = ForceField<DataTypes>;
28  using VecCoord = typename DataTypes::VecCoord;
29  using VecDeriv = typename DataTypes::VecDeriv;
30  using Coord = typename DataTypes::Coord;
31  using Deriv = typename DataTypes::Deriv;
32  using Real = typename Coord::value_type;
33 
35  static constexpr INTEGER_TYPE NumberOfNodes = Hexahedron::NumberOfNodesAtCompileTime;
36 
37 
38  template<int nRows, int nColumns, int Options=Eigen::RowMajor>
39  using Matrix = Eigen::Matrix<Real, nRows, nColumns, Options>;
40 
41  template<int nRows, int nColumns>
42  using Map = Eigen::Map<const Matrix<nRows, nColumns, Eigen::RowMajor>>;
43 
44  template<int nRows, int Options=0>
45  using Vector = Eigen::Matrix<Real, nRows, 1, Options>;
46 
47  template<int nRows>
48  using MapVector = Eigen::Map<const Vector<nRows, Eigen::ColMajor>>;
49 
50  using Rotation = Hexahedron::Matrix<3,3>;
51  using Mat33 = Matrix<3, 3, Eigen::RowMajor>;
52  using Vec3 = Vector<3>;
53  using Mat2424 = Matrix<24, 24, Eigen::RowMajor>;
54  using Vec24 = Vector<24>;
55 
56  template <typename ObjectType>
57  using Link = SingleLink<HexahedronElasticForce, ObjectType, BaseLink::FLAG_STRONGLINK>;
58 
59  // Data structures
60 
61  struct GaussNode {
62  Real weight = 0;
63  Real jacobian_determinant = 0;
64  Matrix<NumberOfNodes, 3> dN_dx = Matrix<NumberOfNodes, 3>::Zero();
65  Mat33 F = Mat33::Identity();
66  };
67 
69  enum class IntegrationMethod : unsigned int {
71  Regular = 0,
72 
74  OnePointGauss = 1
75  };
76 
77  // Public methods
78 
80 
81  void init() override;
82  void reinit() override;
83 
84  void addForce(
85  const MechanicalParams* mparams,
86  Data<VecDeriv>& d_f,
87  const Data<VecCoord>& d_x,
88  const Data<VecDeriv>& d_v) override;
89 
90  void addDForce(
91  const MechanicalParams* /*mparams*/,
92  Data<VecDeriv>& /*d_df*/,
93  const Data<VecDeriv>& /*d_dx*/) override;
94 
95  void draw(const sofa::core::visual::VisualParams* vparams) override;
96 
97  SReal getPotentialEnergy(
98  const MechanicalParams* /* mparams */,
99  const Data<VecCoord>& /* d_x */) const override
100  {return 0;}
101 
102  void addKToMatrix(sofa::defaulttype::BaseMatrix * /*matrix*/, SReal /*kFact*/, unsigned int & /*offset*/) override;
103 
104  void computeBBox(const sofa::core::ExecParams* params, bool onlyVisible) override;
105 
106  template <typename T>
107  inline
108  Hexahedron hexahedron(std::size_t hexa_id, const T & x) const
109  {
110  auto * topology = d_topology_container.get();
111  const auto &node_indices = topology->getHexahedron(hexa_id);
112 
113  Matrix<8, 3> m;
114  for (std::size_t j = 0; j < 8; ++j) {
115  const auto &node_id = node_indices[j];
116  m.row(j) = MapVector<3>(&x[node_id][0]);
117  }
118 
119  return Hexahedron(m);
120  }
121 
122  inline
123  IntegrationMethod integration_method() const
124  {
125  const auto m = static_cast<IntegrationMethod> (d_integration_method.getValue().getSelectedId());
126 
127  if (m == IntegrationMethod::OnePointGauss)
128  return IntegrationMethod::OnePointGauss;
129 
130  return IntegrationMethod::Regular;
131  }
132 
133  inline
134  std::string integration_method_as_string() const
135  {
136  return d_integration_method.getValue().getSelectedItem();
137  }
138 
139  inline
140  void set_integration_method(const IntegrationMethod & m) {
141  auto index = static_cast<unsigned int > (m);
142  sofa::helper::WriteAccessor<Data< sofa::helper::OptionsGroup >> d = d_integration_method;
143  d->setSelectedItem(index);
144  }
145 
146  const std::vector<GaussNode> & gauss_nodes_of(std::size_t hexahedron_id) const {
147  return p_quadrature_nodes[hexahedron_id];
148  }
149 
150  const Matrix<24, 24> & stiffness_matrix_of(std::size_t hexahedron_id) const {
151  return p_stiffness_matrices[hexahedron_id];
152  }
153 
155  const Eigen::SparseMatrix<Real> & K();
156 
158  const Vector<Eigen::Dynamic> & eigenvalues();
159 
161  Real cond();
162 
163 private:
165  virtual void compute_K();
166 
167 protected:
168  Data< Real > d_youngModulus;
169  Data< Real > d_poissonRatio;
170  Data< bool > d_corotated;
171  Data< sofa::helper::OptionsGroup > d_integration_method;
172  Link<BaseMeshTopology> d_topology_container;
173 
174 private:
175  std::vector<Matrix<24, 24>> p_stiffness_matrices;
176  std::vector<std::vector<GaussNode>> p_quadrature_nodes;
177  std::vector<Rotation> p_initial_rotation;
178  std::vector<Rotation> p_current_rotation;
179  Eigen::SparseMatrix<Real> p_K;
180  Vector<Eigen::Dynamic> p_eigenvalues;
181  bool K_is_up_to_date = false;
182  bool eigenvalues_are_up_to_date = false;
183 
184 };
185 
186 } // namespace SofaCaribou::forcefield
SofaCaribou::forcefield::HexahedronElasticForce::IntegrationMethod
IntegrationMethod
Integration method used to integrate the stiffness matrix.
Definition: HexahedronElasticForce.h:69
SofaCaribou::forcefield::HexahedronElasticForce
Definition: HexahedronElasticForce.h:21
caribou::geometry::Hexahedron< caribou::Linear >
SofaCaribou::forcefield::HexahedronElasticForce::GaussNode
Definition: HexahedronElasticForce.h:61