GCC Code Coverage Report


Directory: ./
File: include/crocoddyl/multibody/impulses/multiple-impulses.hxx
Date: 2025-06-03 08:14:12
Exec Total Coverage
Lines: 0 209 0.0%
Functions: 0 44 0.0%
Branches: 0 493 0.0%

Line Branch Exec Source
1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (C) 2019-2025, LAAS-CNRS, University of Edinburgh,
5 // Heriot-Watt University
6 // Copyright note valid unless otherwise stated in individual files.
7 // All rights reserved.
8 ///////////////////////////////////////////////////////////////////////////////
9
10 namespace crocoddyl {
11
12 template <typename Scalar>
13 ✗ ImpulseModelMultipleTpl<Scalar>::ImpulseModelMultipleTpl(
14 std::shared_ptr<StateMultibody> state)
15 ✗ : state_(state), nc_(0), nc_total_(0) {}
16
17 template <typename Scalar>
18 ✗ ImpulseModelMultipleTpl<Scalar>::~ImpulseModelMultipleTpl() {}
19
20 template <typename Scalar>
21 ✗ void ImpulseModelMultipleTpl<Scalar>::addImpulse(
22 const std::string& name, std::shared_ptr<ImpulseModelAbstract> impulse,
23 const bool active) {
24 std::pair<typename ImpulseModelContainer::iterator, bool> ret =
25 ✗ impulses_.insert(std::make_pair(
26 name, std::make_shared<ImpulseItem>(name, impulse, active)));
27 ✗ if (ret.second == false) {
28 std::cerr << "Warning: we couldn't add the " << name
29 ✗ << " impulse item, it already existed." << std::endl;
30 ✗ } else if (active) {
31 ✗ nc_ += impulse->get_nc();
32 ✗ nc_total_ += impulse->get_nc();
33 ✗ active_set_.insert(name);
34 ✗ } else if (!active) {
35 ✗ nc_total_ += impulse->get_nc();
36 ✗ inactive_set_.insert(name);
37 }
38 ✗ }
39
40 template <typename Scalar>
41 ✗ void ImpulseModelMultipleTpl<Scalar>::removeImpulse(const std::string& name) {
42 ✗ typename ImpulseModelContainer::iterator it = impulses_.find(name);
43 ✗ if (it != impulses_.end()) {
44 ✗ nc_ -= it->second->impulse->get_nc();
45 ✗ nc_total_ -= it->second->impulse->get_nc();
46 ✗ impulses_.erase(it);
47 ✗ active_set_.erase(name);
48 ✗ inactive_set_.erase(name);
49 } else {
50 std::cerr << "Warning: we couldn't remove the " << name
51 ✗ << " impulse item, it doesn't exist." << std::endl;
52 }
53 ✗ }
54
55 template <typename Scalar>
56 ✗ void ImpulseModelMultipleTpl<Scalar>::changeImpulseStatus(
57 const std::string& name, const bool active) {
58 ✗ typename ImpulseModelContainer::iterator it = impulses_.find(name);
59 ✗ if (it != impulses_.end()) {
60 ✗ if (active && !it->second->active) {
61 ✗ nc_ += it->second->impulse->get_nc();
62 ✗ active_set_.insert(name);
63 ✗ inactive_set_.erase(name);
64 ✗ } else if (!active && it->second->active) {
65 ✗ nc_ -= it->second->impulse->get_nc();
66 ✗ inactive_set_.insert(name);
67 ✗ active_set_.erase(name);
68 }
69 ✗ it->second->active = active;
70 } else {
71 std::cerr << "Warning: we couldn't change the status of the " << name
72 ✗ << " impulse item, it doesn't exist." << std::endl;
73 }
74 ✗ }
75
76 template <typename Scalar>
77 ✗ void ImpulseModelMultipleTpl<Scalar>::calc(
78 const std::shared_ptr<ImpulseDataMultiple>& data,
79 const Eigen::Ref<const VectorXs>& x) {
80 ✗ if (data->impulses.size() != impulses_.size()) {
81 ✗ throw_pretty("Invalid argument: "
82 << "it doesn't match the number of impulse datas and models");
83 }
84
85 ✗ std::size_t nc = 0;
86 ✗ const std::size_t nv = state_->get_nv();
87 ✗ typename ImpulseModelContainer::iterator it_m, end_m;
88 ✗ typename ImpulseDataContainer::iterator it_d, end_d;
89 ✗ for (it_m = impulses_.begin(), end_m = impulses_.end(),
90 ✗ it_d = data->impulses.begin(), end_d = data->impulses.end();
91 ✗ it_m != end_m || it_d != end_d; ++it_m, ++it_d) {
92 ✗ const std::shared_ptr<ImpulseItem>& m_i = it_m->second;
93 ✗ if (m_i->active) {
94 ✗ const std::shared_ptr<ImpulseDataAbstract>& d_i = it_d->second;
95 ✗ assert_pretty(it_m->first == it_d->first,
96 "it doesn't match the impulse name between model and data ("
97 << it_m->first << " != " << it_d->first << ")");
98
99 ✗ m_i->impulse->calc(d_i, x);
100 ✗ const std::size_t nc_i = m_i->impulse->get_nc();
101 ✗ data->Jc.block(nc, 0, nc_i, nv) = d_i->Jc;
102 ✗ nc += nc_i;
103 }
104 }
105 ✗ }
106
107 template <typename Scalar>
108 ✗ void ImpulseModelMultipleTpl<Scalar>::calcDiff(
109 const std::shared_ptr<ImpulseDataMultiple>& data,
110 const Eigen::Ref<const VectorXs>& x) {
111 ✗ if (data->impulses.size() != impulses_.size()) {
112 ✗ throw_pretty("Invalid argument: "
113 << "it doesn't match the number of impulse datas and models");
114 }
115
116 ✗ std::size_t nc = 0;
117 ✗ const std::size_t nv = state_->get_nv();
118 ✗ typename ImpulseModelContainer::iterator it_m, end_m;
119 ✗ typename ImpulseDataContainer::iterator it_d, end_d;
120 ✗ for (it_m = impulses_.begin(), end_m = impulses_.end(),
121 ✗ it_d = data->impulses.begin(), end_d = data->impulses.end();
122 ✗ it_m != end_m || it_d != end_d; ++it_m, ++it_d) {
123 ✗ const std::shared_ptr<ImpulseItem>& m_i = it_m->second;
124 ✗ if (m_i->active) {
125 ✗ const std::shared_ptr<ImpulseDataAbstract>& d_i = it_d->second;
126 ✗ assert_pretty(it_m->first == it_d->first,
127 "it doesn't match the impulse name between model and data ("
128 << it_m->first << " != " << it_d->first << ")");
129
130 ✗ m_i->impulse->calcDiff(d_i, x);
131 ✗ const std::size_t nc_i = m_i->impulse->get_nc();
132 ✗ data->dv0_dq.block(nc, 0, nc_i, nv) = d_i->dv0_dq;
133 ✗ nc += nc_i;
134 }
135 }
136 ✗ }
137
138 template <typename Scalar>
139 ✗ void ImpulseModelMultipleTpl<Scalar>::updateVelocity(
140 const std::shared_ptr<ImpulseDataMultiple>& data,
141 const VectorXs& vnext) const {
142 ✗ if (static_cast<std::size_t>(vnext.size()) != state_->get_nv()) {
143 ✗ throw_pretty(
144 "Invalid argument: " << "vnext has wrong dimension (it should be " +
145 std::to_string(state_->get_nv()) + ")");
146 }
147 ✗ data->vnext = vnext;
148 ✗ }
149
150 template <typename Scalar>
151 ✗ void ImpulseModelMultipleTpl<Scalar>::updateForce(
152 const std::shared_ptr<ImpulseDataMultiple>& data, const VectorXs& force) {
153 ✗ if (static_cast<std::size_t>(force.size()) != nc_) {
154 ✗ throw_pretty(
155 "Invalid argument: " << "force has wrong dimension (it should be " +
156 std::to_string(nc_) + ")");
157 }
158 ✗ if (static_cast<std::size_t>(data->impulses.size()) != impulses_.size()) {
159 ✗ throw_pretty("Invalid argument: "
160 << "it doesn't match the number of impulse datas and models");
161 }
162
163 ✗ for (ForceIterator it = data->fext.begin(); it != data->fext.end(); ++it) {
164 ✗ *it = pinocchio::ForceTpl<Scalar>::Zero();
165 }
166
167 ✗ std::size_t nc = 0;
168 ✗ typename ImpulseModelContainer::iterator it_m, end_m;
169 ✗ typename ImpulseDataContainer::iterator it_d, end_d;
170 ✗ for (it_m = impulses_.begin(), end_m = impulses_.end(),
171 ✗ it_d = data->impulses.begin(), end_d = data->impulses.end();
172 ✗ it_m != end_m || it_d != end_d; ++it_m, ++it_d) {
173 ✗ const std::shared_ptr<ImpulseItem>& m_i = it_m->second;
174 ✗ const std::shared_ptr<ImpulseDataAbstract>& d_i = it_d->second;
175 ✗ assert_pretty(it_m->first == it_d->first,
176 "it doesn't match the impulse name between data and model");
177 ✗ if (m_i->active) {
178 ✗ const std::size_t nc_i = m_i->impulse->get_nc();
179 const Eigen::VectorBlock<const VectorXs, Eigen::Dynamic> force_i =
180 ✗ force.segment(nc, nc_i);
181 ✗ m_i->impulse->updateForce(d_i, force_i);
182 ✗ const pinocchio::JointIndex joint =
183 ✗ state_->get_pinocchio()->frames[d_i->frame].parentJoint;
184 ✗ data->fext[joint] = d_i->fext;
185 ✗ nc += nc_i;
186 } else {
187 ✗ m_i->impulse->setZeroForce(d_i);
188 }
189 }
190 ✗ }
191
192 template <typename Scalar>
193 ✗ void ImpulseModelMultipleTpl<Scalar>::updateVelocityDiff(
194 const std::shared_ptr<ImpulseDataMultiple>& data,
195 const MatrixXs& dvnext_dx) const {
196 ✗ if (static_cast<std::size_t>(dvnext_dx.rows()) != state_->get_nv() ||
197 ✗ static_cast<std::size_t>(dvnext_dx.cols()) != state_->get_ndx()) {
198 ✗ throw_pretty(
199 "Invalid argument: " << "dvnext_dx has wrong dimension (it should be " +
200 std::to_string(state_->get_nv()) + "," +
201 std::to_string(state_->get_ndx()) + ")");
202 }
203 ✗ data->dvnext_dx = dvnext_dx;
204 ✗ }
205
206 template <typename Scalar>
207 ✗ void ImpulseModelMultipleTpl<Scalar>::updateForceDiff(
208 const std::shared_ptr<ImpulseDataMultiple>& data,
209 const MatrixXs& df_dx) const {
210 ✗ const std::size_t ndx = state_->get_ndx();
211 ✗ if (static_cast<std::size_t>(df_dx.rows()) != nc_ ||
212 ✗ static_cast<std::size_t>(df_dx.cols()) != ndx) {
213 ✗ throw_pretty("Invalid argument: "
214 << "df_dx has wrong dimension (it should be " +
215 std::to_string(nc_) + "," + std::to_string(ndx) + ")");
216 }
217 ✗ if (static_cast<std::size_t>(data->impulses.size()) != impulses_.size()) {
218 ✗ throw_pretty("Invalid argument: "
219 << "it doesn't match the number of impulse datas and models");
220 }
221
222 ✗ std::size_t nc = 0;
223 ✗ typename ImpulseModelContainer::const_iterator it_m, end_m;
224 ✗ typename ImpulseDataContainer::const_iterator it_d, end_d;
225 ✗ for (it_m = impulses_.begin(), end_m = impulses_.end(),
226 ✗ it_d = data->impulses.begin(), end_d = data->impulses.end();
227 ✗ it_m != end_m || it_d != end_d; ++it_m, ++it_d) {
228 ✗ const std::shared_ptr<ImpulseItem>& m_i = it_m->second;
229 ✗ const std::shared_ptr<ImpulseDataAbstract>& d_i = it_d->second;
230 ✗ assert_pretty(it_m->first == it_d->first,
231 "it doesn't match the impulse name between data and model");
232 ✗ if (m_i->active) {
233 ✗ const std::size_t nc_i = m_i->impulse->get_nc();
234 const Eigen::Block<const MatrixXs> df_dx_i =
235 ✗ df_dx.block(nc, 0, nc_i, ndx);
236 ✗ m_i->impulse->updateForceDiff(d_i, df_dx_i);
237 ✗ nc += nc_i;
238 } else {
239 ✗ m_i->impulse->setZeroForceDiff(d_i);
240 }
241 }
242 ✗ }
243
244 template <typename Scalar>
245 ✗ void ImpulseModelMultipleTpl<Scalar>::updateRneaDiff(
246 const std::shared_ptr<ImpulseDataMultiple>& data,
247 pinocchio::DataTpl<Scalar>& pinocchio) const {
248 ✗ if (static_cast<std::size_t>(data->impulses.size()) !=
249 ✗ this->get_impulses().size()) {
250 ✗ throw_pretty("Invalid argument: "
251 << "it doesn't match the number of impulse datas and models");
252 }
253 ✗ typename ImpulseModelContainer::const_iterator it_m, end_m;
254 ✗ typename ImpulseDataContainer::const_iterator it_d, end_d;
255 ✗ for (it_m = impulses_.begin(), end_m = impulses_.end(),
256 ✗ it_d = data->impulses.begin(), end_d = data->impulses.end();
257 ✗ it_m != end_m || it_d != end_d; ++it_m, ++it_d) {
258 ✗ const std::shared_ptr<ImpulseItem>& m_i = it_m->second;
259 ✗ const std::shared_ptr<ImpulseDataAbstract>& d_i = it_d->second;
260 ✗ assert_pretty(it_m->first == it_d->first,
261 "it doesn't match the impulse name between data and model");
262 ✗ if (m_i->active) {
263 ✗ switch (m_i->impulse->get_type()) {
264 ✗ case pinocchio::ReferenceFrame::LOCAL:
265 ✗ break;
266 ✗ case pinocchio::ReferenceFrame::WORLD:
267 case pinocchio::ReferenceFrame::LOCAL_WORLD_ALIGNED:
268 ✗ pinocchio.dtau_dq += d_i->dtau_dq;
269 ✗ break;
270 }
271 }
272 }
273 ✗ }
274
275 template <typename Scalar>
276 std::shared_ptr<ImpulseDataMultipleTpl<Scalar> >
277 ✗ ImpulseModelMultipleTpl<Scalar>::createData(
278 pinocchio::DataTpl<Scalar>* const data) {
279 return std::allocate_shared<ImpulseDataMultiple>(
280 ✗ Eigen::aligned_allocator<ImpulseDataMultiple>(), this, data);
281 }
282
283 template <typename Scalar>
284 template <typename NewScalar>
285 ✗ ImpulseModelMultipleTpl<NewScalar> ImpulseModelMultipleTpl<Scalar>::cast()
286 const {
287 typedef ImpulseModelMultipleTpl<NewScalar> ReturnType;
288 typedef StateMultibodyTpl<NewScalar> StateType;
289 typedef ImpulseItemTpl<NewScalar> ImpulseType;
290 ✗ ReturnType ret(
291 ✗ std::make_shared<StateType>(state_->template cast<NewScalar>()));
292 ✗ typename ImpulseModelContainer::const_iterator it_m, end_m;
293 ✗ for (it_m = impulses_.begin(), end_m = impulses_.end(); it_m != end_m;
294 ✗ ++it_m) {
295 ✗ const std::string name = it_m->first;
296 ✗ const ImpulseType& m_i = it_m->second->template cast<NewScalar>();
297 ✗ ret.addImpulse(name, m_i.impulse, m_i.active);
298 }
299 ✗ return ret;
300 ✗ }
301
302 template <typename Scalar>
303 const std::shared_ptr<StateMultibodyTpl<Scalar> >&
304 ✗ ImpulseModelMultipleTpl<Scalar>::get_state() const {
305 ✗ return state_;
306 }
307
308 template <typename Scalar>
309 const typename ImpulseModelMultipleTpl<Scalar>::ImpulseModelContainer&
310 ✗ ImpulseModelMultipleTpl<Scalar>::get_impulses() const {
311 ✗ return impulses_;
312 }
313
314 template <typename Scalar>
315 ✗ std::size_t ImpulseModelMultipleTpl<Scalar>::get_nc() const {
316 ✗ return nc_;
317 }
318
319 template <typename Scalar>
320 ✗ std::size_t ImpulseModelMultipleTpl<Scalar>::get_nc_total() const {
321 ✗ return nc_total_;
322 }
323
324 template <typename Scalar>
325 ✗ const std::set<std::string>& ImpulseModelMultipleTpl<Scalar>::get_active_set()
326 const {
327 ✗ return active_set_;
328 }
329
330 template <typename Scalar>
331 ✗ const std::set<std::string>& ImpulseModelMultipleTpl<Scalar>::get_inactive_set()
332 const {
333 ✗ return inactive_set_;
334 }
335
336 template <typename Scalar>
337 ✗ bool ImpulseModelMultipleTpl<Scalar>::getImpulseStatus(
338 const std::string& name) const {
339 ✗ typename ImpulseModelContainer::const_iterator it = impulses_.find(name);
340 ✗ if (it != impulses_.end()) {
341 ✗ return it->second->active;
342 } else {
343 std::cerr << "Warning: we couldn't get the status of the " << name
344 ✗ << " impulse item, it doesn't exist." << std::endl;
345 ✗ return false;
346 }
347 }
348
349 template <class Scalar>
350 ✗ std::ostream& operator<<(std::ostream& os,
351 const ImpulseModelMultipleTpl<Scalar>& model) {
352 ✗ const auto& active = model.get_active_set();
353 ✗ const auto& inactive = model.get_inactive_set();
354 ✗ os << "ImpulseModelMultiple:" << std::endl;
355 ✗ os << " Active:" << std::endl;
356 ✗ for (std::set<std::string>::const_iterator it = active.begin();
357 ✗ it != active.end(); ++it) {
358 const std::shared_ptr<
359 ✗ typename ImpulseModelMultipleTpl<Scalar>::ImpulseItem>& impulse_item =
360 ✗ model.get_impulses().find(*it)->second;
361 ✗ if (it != --active.end()) {
362 ✗ os << " " << *it << ": " << *impulse_item << std::endl;
363 } else {
364 ✗ os << " " << *it << ": " << *impulse_item << std::endl;
365 }
366 }
367 ✗ os << " Inactive:" << std::endl;
368 ✗ for (std::set<std::string>::const_iterator it = inactive.begin();
369 ✗ it != inactive.end(); ++it) {
370 const std::shared_ptr<
371 ✗ typename ImpulseModelMultipleTpl<Scalar>::ImpulseItem>& impulse_item =
372 ✗ model.get_impulses().find(*it)->second;
373 ✗ if (it != --inactive.end()) {
374 ✗ os << " " << *it << ": " << *impulse_item << std::endl;
375 } else {
376 ✗ os << " " << *it << ": " << *impulse_item;
377 }
378 }
379 ✗ return os;
380 }
381
382 } // namespace crocoddyl
383