Caribou
FictitiousGridHyperelasticForce.h
1 #pragma once
2 
3 #include <sofa/helper/OptionsGroup.h>
4 
5 #include <SofaCaribou/Forcefield/HyperelasticForcefield.inl>
6 #include <SofaCaribou/Topology/FictitiousGrid.h>
7 
8 #include <Caribou/config.h>
9 #include <Caribou/Geometry/Hexahedron.h>
10 
11 namespace caribou::geometry {
12 // --------------------------------------------------------------------------------
13 // Subdivided Gauss Hexahedron Element
14 //---------------------------------------------------------------------------------
15 // Regular hexahedron that is cut by a boundary, hence it is only partially filled.
16 // The set of Gauss integration nodes are obtained by recursively subdividing each
17 // cells into 8 sub-cells. The Gauss nodes of the leaf sub-cells are used.
18 //---------------------------------------------------------------------------------
19 struct SubdividedGaussHexahedron;
20 template<>
21 struct traits<SubdividedGaussHexahedron> : traits<caribou::geometry::Hexahedron<caribou::Linear>> {
22  static constexpr INTEGER_TYPE NumberOfGaussNodesAtCompileTime = caribou::Dynamic;
23 };
24 
25 struct SubdividedGaussHexahedron : public caribou::geometry::Hexahedron<caribou::Linear> {
27  using Base::Base;
28 };
29 
30 // --------------------------------------------------------------------------------
31 // Subdivided Volume Hexahedron Element
32 //---------------------------------------------------------------------------------
33 // Regular hexahedron that is cut by a boundary, hence it is only partially filled.
34 // The set of Gauss integration nodes are the same as a regular hexahedral elements.
35 // The weight of each Gauss integration nodes however are computed by recursively
36 // subdividing each cells into 8 sub-cells.
37 //---------------------------------------------------------------------------------
39 template<>
40 struct traits<SubdividedVolumeHexahedron> : traits<caribou::geometry::Hexahedron<caribou::Linear>> {};
41 
44  using Base::Base;
45 };
46 } // namespace caribou::geometry
47 
48 namespace SofaCaribou::forcefield {
49 
54 template <typename Element>
56 public:
57  SOFA_CLASS(SOFA_TEMPLATE(FictitiousGridHyperelasticForcefield, Element), SOFA_TEMPLATE(HyperelasticForcefield, Element));
58 
61 
62  using GaussContainer = typename Base::GaussContainer;
63  using Index = sofa::Index;
64 
65  using typename Base::Mat33;
66 
67  template <typename ObjectType>
68  using Link = SingleLink<FictitiousGridHyperelasticForcefield<Element>, ObjectType, BaseLink::FLAG_STRONGLINK>;
69 
70  // Constructor
72  : Base::Base()
73  , d_grid(initLink("fictitious_grid", "Fictitious grid containing the elements on which this forcefield will be applied."))
74  , d_integration_method(initData(&d_integration_method,
75  "integration_method",
76  R"(
77  Integration method used to integrate the stiffness matrix.
78 
79  Methods are:
80  SubdividedVolume: Hexas are recursively subdivided into cubic subcells and these subcells are used to
81  compute the inside volume of the regular hexa's gauss points.
82  SubdividedGauss: Hexas are recursively subdivided into cubic subcells and these subcells are used to
83  add new gauss points. Gauss points outside of the boundary are ignored.
84  )",
85  true /*displayed_in_GUI*/, true /*read_only_in_GUI*/))
86  {
87  d_integration_method.setValue(sofa::helper::OptionsGroup(std::vector<std::string> {
88  "SubdividedVolume", "SubdividedGauss"
89  }));
90  sofa::helper::WriteAccessor<Data< sofa::helper::OptionsGroup >> integration_method = d_integration_method;
91  integration_method->setSelectedItem((unsigned int) 0);
92  }
93 
94  void init() override {
95  if (d_grid.get() and number_of_elements() == 0) {
96  msg_warning() << "No element found in the grid '" << d_grid->getPathName() << "'.";
97  } else if (not d_grid.get()) {
98  // No topology specified. Try to find one suitable.
99  auto containers = this->getContext()->template getObjects<FictitiousGrid>(BaseContext::Local);
100  if (containers.empty()) {
101  msg_warning() << "Could not find a fictitious grid in the current context.";
102  } else {
103  std::vector<FictitiousGrid *> suitable_containers;
104  for (const auto & container : containers) {
105  d_grid.set(container);
106  if (number_of_elements() > 0) {
107  suitable_containers.push_back(container);
108  }
109  d_grid.set(nullptr);
110  }
111 
112  if (suitable_containers.empty()) {
113  msg_warning() << "Could not find a suitable fictitious grid in the current context, they are all empty.";
114  } else if (suitable_containers.size() > 1) {
115  d_grid.set(suitable_containers[0]);
116  msg_warning() <<
117  "Multiple fictitious grid were found in the context node. The first one will be taken ('" << d_grid.get()->getPathName() << "'). " <<
118  "If it isn't the correct one, please specify which one contains the elements on which this force field will be applied " <<
119  "by explicitly setting the container's path in the '" << d_grid.getName() << "' parameter.";
120  msg_info() << "Automatically found the topology '" << d_grid.get()->getPathName() << "'.";
121  } else {
122  d_grid.set(suitable_containers[0]);
123  msg_info() << "Automatically found the topology '" << d_grid.get()->getPathName() << "'.";
124  }
125  }
126  }
127 
128  Base::init();
129  }
130 
131  static auto templateName(const FictitiousGridHyperelasticForcefield<Element>* = nullptr) -> std::string;
132 
133  static auto canCreate(FictitiousGridHyperelasticForcefield<Element>*, BaseContext*, BaseObjectDescription* arg) -> bool;
134 
136  [[nodiscard]]
137  inline auto number_of_elements() const -> std::size_t override {
138  if (d_grid.get()) {
139  return d_grid->number_of_cells();
140  }
141  return 0;
142  }
143 
144 private:
145  // These private methods are implemented but can be overridden
146 
148  auto get_element_nodes_indices(const std::size_t & element_id) const -> const Index * override {
149  if (not d_grid.get() or d_grid->number_of_cells() == 0) {
150  return nullptr;
151  }
152 
153  return &(d_grid->get_node_indices_of(element_id)[0]);
154  }
155 
161  inline
162  static auto mesh_is_compatible(const sofa::core::topology::BaseMeshTopology *) -> bool {
163  return false;
164  }
165 
167  auto get_gauss_nodes(const std::size_t & /*element_id*/, const Element & /*element*/) const -> GaussContainer override {
168  return {};
169  }
170 
171  // Data members
172  Link<FictitiousGrid> d_grid;
173  Data< sofa::helper::OptionsGroup > d_integration_method;
174 };
175 
176 // SubdividedVolumeHexahedron specialization
177 template <> auto FictitiousGridHyperelasticForcefield<caribou::geometry::SubdividedVolumeHexahedron>::templateName(const FictitiousGridHyperelasticForcefield<caribou::geometry::SubdividedVolumeHexahedron> *) -> std::string;
178 template <> auto FictitiousGridHyperelasticForcefield<caribou::geometry::SubdividedVolumeHexahedron>::canCreate(FictitiousGridHyperelasticForcefield<caribou::geometry::SubdividedVolumeHexahedron>*, BaseContext*, BaseObjectDescription* arg) -> bool;
179 template <> auto FictitiousGridHyperelasticForcefield<caribou::geometry::SubdividedVolumeHexahedron>::get_gauss_nodes(const std::size_t & element_id, const caribou::geometry::SubdividedVolumeHexahedron & e) const -> GaussContainer;
180 extern template class FictitiousGridHyperelasticForcefield<caribou::geometry::SubdividedVolumeHexahedron>;
181 
182 // SubdividedGaussHexahedron specialization
183 template <> auto FictitiousGridHyperelasticForcefield<caribou::geometry::SubdividedGaussHexahedron>::templateName(const FictitiousGridHyperelasticForcefield<caribou::geometry::SubdividedGaussHexahedron> *) -> std::string;
184 template <> auto FictitiousGridHyperelasticForcefield<caribou::geometry::SubdividedGaussHexahedron>::canCreate(FictitiousGridHyperelasticForcefield<caribou::geometry::SubdividedGaussHexahedron>*, BaseContext*, BaseObjectDescription* arg) -> bool;
185 template <> auto FictitiousGridHyperelasticForcefield<caribou::geometry::SubdividedGaussHexahedron>::get_gauss_nodes(const std::size_t & element_id, const caribou::geometry::SubdividedGaussHexahedron & e) const -> GaussContainer;
186 extern template class FictitiousGridHyperelasticForcefield<caribou::geometry::SubdividedGaussHexahedron>;
187 
188 
189 } // namespace SofaCaribou::forcefield
caribou::geometry::Hexahedron
Definition: Hexahedron.h:11
SofaCaribou::forcefield::HyperelasticForcefield
Definition: HyperelasticForcefield.h:50
caribou::geometry::SubdividedVolumeHexahedron
Definition: FictitiousGridHyperelasticForce.h:42
caribou::geometry::Element
Definition: Element.h:28
SofaCaribou::forcefield::FictitiousGridHyperelasticForcefield
Hyperelastic forcefield for cut hexahedral elements.
Definition: FictitiousGridHyperelasticForce.h:55
SofaCaribou::topology::FictitiousGrid
Definition: FictitiousGrid.h:35
SofaCaribou::forcefield::FictitiousGridHyperelasticForcefield::number_of_elements
auto number_of_elements() const -> std::size_t override
Get the number of elements contained in this field.
Definition: FictitiousGridHyperelasticForce.h:137
caribou::geometry::traits
Definition: Element.h:14
caribou::geometry::SubdividedGaussHexahedron
Definition: FictitiousGridHyperelasticForce.h:25