GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/////////////////////////////////////////////////////////////////////////////// |
||
2 |
// BSD 3-Clause License |
||
3 |
// |
||
4 |
// Copyright (C) 2019-2021, LAAS-CNRS, New York University, Max Planck |
||
5 |
// Gesellschaft, |
||
6 |
// INRIA |
||
7 |
// Copyright note valid unless otherwise stated in individual files. |
||
8 |
// All rights reserved. |
||
9 |
/////////////////////////////////////////////////////////////////////////////// |
||
10 |
|||
11 |
#define BOOST_TEST_NO_MAIN |
||
12 |
#define BOOST_TEST_ALTERNATIVE_INIT_API |
||
13 |
|||
14 |
#include <pinocchio/algorithm/frames.hpp> |
||
15 |
#include <pinocchio/algorithm/kinematics-derivatives.hpp> |
||
16 |
|||
17 |
#include "factory/impulse.hpp" |
||
18 |
#include "unittest_common.hpp" |
||
19 |
|||
20 |
using namespace boost::unit_test; |
||
21 |
using namespace crocoddyl::unittest; |
||
22 |
|||
23 |
//----------------------------------------------------------------------------// |
||
24 |
|||
25 |
/** |
||
26 |
* These methods modify the return type of the model function in |
||
27 |
* order to use the boost::execution_monitor::execute method which catch the |
||
28 |
* assert signal |
||
29 |
*/ |
||
30 |
int calc(crocoddyl::ImpulseModelMultiple& model, |
||
31 |
boost::shared_ptr<crocoddyl::ImpulseDataMultiple> data, |
||
32 |
Eigen::VectorXd& dx) { |
||
33 |
model.calc(data, dx); |
||
34 |
return 0; |
||
35 |
} |
||
36 |
|||
37 |
int calcDiff(crocoddyl::ImpulseModelMultiple& model, |
||
38 |
boost::shared_ptr<crocoddyl::ImpulseDataMultiple> data, |
||
39 |
Eigen::VectorXd& dx) { |
||
40 |
model.calcDiff(data, dx); |
||
41 |
return 0; |
||
42 |
} |
||
43 |
|||
44 |
int updateForce(crocoddyl::ImpulseModelMultiple& model, |
||
45 |
boost::shared_ptr<crocoddyl::ImpulseDataMultiple> data, |
||
46 |
Eigen::VectorXd& dx) { |
||
47 |
model.updateForce(data, dx); |
||
48 |
return 0; |
||
49 |
} |
||
50 |
|||
51 |
int updateVelocityDiff(crocoddyl::ImpulseModelMultiple& model, |
||
52 |
boost::shared_ptr<crocoddyl::ImpulseDataMultiple> data, |
||
53 |
const Eigen::MatrixXd& dvnext_dx) { |
||
54 |
model.updateVelocityDiff(data, dvnext_dx); |
||
55 |
return 0; |
||
56 |
} |
||
57 |
|||
58 |
int updateForceDiff(crocoddyl::ImpulseModelMultiple& model, |
||
59 |
boost::shared_ptr<crocoddyl::ImpulseDataMultiple> data, |
||
60 |
const Eigen::MatrixXd& df_dx) { |
||
61 |
model.updateForceDiff(data, df_dx); |
||
62 |
return 0; |
||
63 |
} |
||
64 |
|||
65 |
//----------------------------------------------------------------------------// |
||
66 |
|||
67 |
1 |
void test_constructor() { |
|
68 |
// Setup the test |
||
69 |
✓✗ | 2 |
StateModelFactory state_factory; |
70 |
crocoddyl::ImpulseModelMultiple model( |
||
71 |
2 |
boost::static_pointer_cast<crocoddyl::StateMultibody>( |
|
72 |
✓✗ | 1 |
state_factory.create( |
73 |
2 |
StateModelTypes::StateMultibody_RandomHumanoid))); |
|
74 |
|||
75 |
// Run the print function |
||
76 |
✓✗ | 2 |
std::ostringstream tmp; |
77 |
✓✗ | 1 |
tmp << model; |
78 |
|||
79 |
// Test the initial size of the map |
||
80 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
1 |
BOOST_CHECK(model.get_impulses().size() == 0); |
81 |
1 |
} |
|
82 |
|||
83 |
1 |
void test_addImpulse() { |
|
84 |
// Setup the test |
||
85 |
✓✗ | 2 |
StateModelFactory state_factory; |
86 |
crocoddyl::ImpulseModelMultiple model( |
||
87 |
2 |
boost::static_pointer_cast<crocoddyl::StateMultibody>( |
|
88 |
✓✗ | 1 |
state_factory.create( |
89 |
2 |
StateModelTypes::StateMultibody_RandomHumanoid))); |
|
90 |
|||
91 |
// add an active impulse |
||
92 |
boost::shared_ptr<crocoddyl::ImpulseModelAbstract> rand_impulse_1 = |
||
93 |
✓✗ | 2 |
create_random_impulse(); |
94 |
✓✗✓✗ |
1 |
model.addImpulse("random_impulse_1", rand_impulse_1); |
95 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
1 |
BOOST_CHECK(model.get_nc() == rand_impulse_1->get_nc()); |
96 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
1 |
BOOST_CHECK(model.get_nc_total() == rand_impulse_1->get_nc()); |
97 |
|||
98 |
// add an inactive impulse |
||
99 |
boost::shared_ptr<crocoddyl::ImpulseModelAbstract> rand_impulse_2 = |
||
100 |
✓✗ | 2 |
create_random_impulse(); |
101 |
✓✗✓✗ |
1 |
model.addImpulse("random_impulse_2", rand_impulse_2, false); |
102 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
1 |
BOOST_CHECK(model.get_nc() == rand_impulse_1->get_nc()); |
103 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
1 |
BOOST_CHECK(model.get_nc_total() == |
104 |
rand_impulse_1->get_nc() + rand_impulse_2->get_nc()); |
||
105 |
|||
106 |
// change the random impulse 2 status |
||
107 |
✓✗✓✗ |
1 |
model.changeImpulseStatus("random_impulse_2", true); |
108 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
1 |
BOOST_CHECK(model.get_nc() == |
109 |
rand_impulse_1->get_nc() + rand_impulse_2->get_nc()); |
||
110 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
1 |
BOOST_CHECK(model.get_nc_total() == |
111 |
rand_impulse_1->get_nc() + rand_impulse_2->get_nc()); |
||
112 |
|||
113 |
// change the random impulse 1 status |
||
114 |
✓✗✓✗ |
1 |
model.changeImpulseStatus("random_impulse_1", false); |
115 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
1 |
BOOST_CHECK(model.get_nc() == rand_impulse_2->get_nc()); |
116 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
1 |
BOOST_CHECK(model.get_nc_total() == |
117 |
rand_impulse_1->get_nc() + rand_impulse_2->get_nc()); |
||
118 |
1 |
} |
|
119 |
|||
120 |
1 |
void test_addImpulse_error_message() { |
|
121 |
// Setup the test |
||
122 |
✓✗ | 2 |
StateModelFactory state_factory; |
123 |
crocoddyl::ImpulseModelMultiple model( |
||
124 |
2 |
boost::static_pointer_cast<crocoddyl::StateMultibody>( |
|
125 |
✓✗ | 1 |
state_factory.create( |
126 |
2 |
StateModelTypes::StateMultibody_RandomHumanoid))); |
|
127 |
|||
128 |
// create an impulse object |
||
129 |
boost::shared_ptr<crocoddyl::ImpulseModelAbstract> rand_impulse = |
||
130 |
✓✗ | 2 |
create_random_impulse(); |
131 |
|||
132 |
// add twice the same impulse object to the container |
||
133 |
✓✗✓✗ |
1 |
model.addImpulse("random_impulse", rand_impulse); |
134 |
|||
135 |
// test error message when we add a duplicate impulse |
||
136 |
✓✗ | 2 |
CaptureIOStream capture_ios; |
137 |
✓✗ | 1 |
capture_ios.beginCapture(); |
138 |
✓✗✓✗ |
1 |
model.addImpulse("random_impulse", rand_impulse); |
139 |
✓✗ | 1 |
capture_ios.endCapture(); |
140 |
✓✗ | 2 |
std::stringstream expected_buffer; |
141 |
expected_buffer << "Warning: we couldn't add the random_impulse impulse " |
||
142 |
✓✗ | 1 |
"item, it already existed." |
143 |
✓✗ | 1 |
<< std::endl; |
144 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
1 |
BOOST_CHECK(capture_ios.str() == expected_buffer.str()); |
145 |
|||
146 |
// test error message when we change the impulse status of an inexistent |
||
147 |
// impulse |
||
148 |
✓✗ | 1 |
capture_ios.beginCapture(); |
149 |
✓✗✓✗ |
1 |
model.changeImpulseStatus("no_exist_impulse", true); |
150 |
✓✗ | 1 |
capture_ios.endCapture(); |
151 |
✓✗ | 1 |
expected_buffer.clear(); |
152 |
expected_buffer << "Warning: we couldn't change the status of the " |
||
153 |
✓✗ | 1 |
"no_exist_impulse impulse item, it doesn't exist." |
154 |
✓✗ | 1 |
<< std::endl; |
155 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
1 |
BOOST_CHECK(capture_ios.str() == expected_buffer.str()); |
156 |
1 |
} |
|
157 |
|||
158 |
1 |
void test_removeImpulse() { |
|
159 |
// Setup the test |
||
160 |
✓✗ | 2 |
StateModelFactory state_factory; |
161 |
crocoddyl::ImpulseModelMultiple model( |
||
162 |
2 |
boost::static_pointer_cast<crocoddyl::StateMultibody>( |
|
163 |
✓✗ | 1 |
state_factory.create( |
164 |
2 |
StateModelTypes::StateMultibody_RandomHumanoid))); |
|
165 |
|||
166 |
// add an active impulse |
||
167 |
boost::shared_ptr<crocoddyl::ImpulseModelAbstract> rand_impulse = |
||
168 |
✓✗ | 2 |
create_random_impulse(); |
169 |
✓✗✓✗ |
1 |
model.addImpulse("random_impulse", rand_impulse); |
170 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
1 |
BOOST_CHECK(model.get_nc() == rand_impulse->get_nc()); |
171 |
|||
172 |
// remove the impulse |
||
173 |
✓✗✓✗ |
1 |
model.removeImpulse("random_impulse"); |
174 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
1 |
BOOST_CHECK(model.get_nc() == 0); |
175 |
1 |
} |
|
176 |
|||
177 |
1 |
void test_removeImpulse_error_message() { |
|
178 |
// Setup the test |
||
179 |
✓✗ | 2 |
StateModelFactory state_factory; |
180 |
crocoddyl::ImpulseModelMultiple model( |
||
181 |
2 |
boost::static_pointer_cast<crocoddyl::StateMultibody>( |
|
182 |
✓✗ | 1 |
state_factory.create( |
183 |
2 |
StateModelTypes::StateMultibody_RandomHumanoid))); |
|
184 |
|||
185 |
// remove a none existing impulse form the container, we expect a cout message |
||
186 |
// here |
||
187 |
✓✗ | 2 |
CaptureIOStream capture_ios; |
188 |
✓✗ | 1 |
capture_ios.beginCapture(); |
189 |
✓✗✓✗ |
1 |
model.removeImpulse("random_impulse"); |
190 |
✓✗ | 1 |
capture_ios.endCapture(); |
191 |
|||
192 |
// Test that the error message is sent. |
||
193 |
✓✗ | 2 |
std::stringstream expected_buffer; |
194 |
expected_buffer << "Warning: we couldn't remove the random_impulse impulse " |
||
195 |
✓✗ | 1 |
"item, it doesn't exist." |
196 |
✓✗ | 1 |
<< std::endl; |
197 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
1 |
BOOST_CHECK(capture_ios.str() == expected_buffer.str()); |
198 |
1 |
} |
|
199 |
|||
200 |
1 |
void test_calc() { |
|
201 |
// Setup the test |
||
202 |
✓✗ | 2 |
StateModelFactory state_factory; |
203 |
crocoddyl::ImpulseModelMultiple model( |
||
204 |
2 |
boost::static_pointer_cast<crocoddyl::StateMultibody>( |
|
205 |
✓✗ | 1 |
state_factory.create( |
206 |
2 |
StateModelTypes::StateMultibody_RandomHumanoid))); |
|
207 |
// create the corresponding data object |
||
208 |
1 |
pinocchio::Model& pinocchio_model = *model.get_state()->get_pinocchio().get(); |
|
209 |
✓✗ | 2 |
pinocchio::Data pinocchio_data(*model.get_state()->get_pinocchio().get()); |
210 |
|||
211 |
// create and add some impulse objects |
||
212 |
2 |
std::vector<boost::shared_ptr<crocoddyl::ImpulseModelAbstract> > models; |
|
213 |
2 |
std::vector<boost::shared_ptr<crocoddyl::ImpulseDataAbstract> > datas; |
|
214 |
✓✓ | 6 |
for (std::size_t i = 0; i < 5; ++i) { |
215 |
✓✗ | 10 |
std::ostringstream os; |
216 |
✓✗✓✗ |
5 |
os << "random_impulse_" << i; |
217 |
const boost::shared_ptr<crocoddyl::ImpulseModelAbstract>& m = |
||
218 |
✓✗ | 5 |
create_random_impulse(); |
219 |
✓✗✓✗ |
5 |
model.addImpulse(os.str(), m); |
220 |
✓✗ | 5 |
models.push_back(m); |
221 |
✓✗✓✗ |
5 |
datas.push_back(m->createData(&pinocchio_data)); |
222 |
} |
||
223 |
|||
224 |
// create the data of the multiple-impulses |
||
225 |
boost::shared_ptr<crocoddyl::ImpulseDataMultiple> data = |
||
226 |
✓✗ | 2 |
model.createData(&pinocchio_data); |
227 |
|||
228 |
// compute the multiple contact data for the case when all impulses are |
||
229 |
// defined as active |
||
230 |
✓✗ | 2 |
Eigen::VectorXd x1 = model.get_state()->rand(); |
231 |
✓✗✓✗ |
1 |
crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data, |
232 |
x1); |
||
233 |
✓✗✓✗ |
1 |
model.calc(data, x1); |
234 |
|||
235 |
// check that only the Jacobian has been filled |
||
236 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✓ |
1 |
BOOST_CHECK(!data->Jc.isZero()); |
237 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✓ |
1 |
BOOST_CHECK(data->dv0_dq.isZero()); |
238 |
|||
239 |
// check Jc against single impulse computations |
||
240 |
1 |
std::size_t ni = 0; |
|
241 |
1 |
const std::size_t nv = model.get_state()->get_nv(); |
|
242 |
✓✓ | 6 |
for (std::size_t i = 0; i < 5; ++i) { |
243 |
5 |
const std::size_t ni_i = models[i]->get_nc(); |
|
244 |
✓✗✓✗ |
5 |
models[i]->calc(datas[i], x1); |
245 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
5 |
BOOST_CHECK(data->Jc.block(ni, 0, ni_i, nv) == datas[i]->Jc); |
246 |
5 |
ni += ni_i; |
|
247 |
} |
||
248 |
1 |
ni = 0; |
|
249 |
|||
250 |
// compute the multiple impulse data for the case when the first three |
||
251 |
// impulses are defined as active |
||
252 |
✓✗✓✗ |
1 |
model.changeImpulseStatus("random_impulse_3", false); |
253 |
✓✗✓✗ |
1 |
model.changeImpulseStatus("random_impulse_4", false); |
254 |
✓✗ | 2 |
Eigen::VectorXd x2 = model.get_state()->rand(); |
255 |
✓✗✓✗ |
1 |
crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data, |
256 |
x2); |
||
257 |
✓✗✓✗ |
1 |
model.calc(data, x2); |
258 |
✓✓ | 6 |
for (std::size_t i = 0; i < 5; ++i) { |
259 |
5 |
const std::size_t ni_i = models[i]->get_nc(); |
|
260 |
✓✓ | 5 |
if (i < 3) { // we need to update data because this impulses are active |
261 |
✓✗✓✗ |
3 |
models[i]->calc(datas[i], x2); |
262 |
} |
||
263 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
5 |
BOOST_CHECK(data->Jc.block(ni, 0, ni_i, nv) == datas[i]->Jc); |
264 |
5 |
ni += ni_i; |
|
265 |
} |
||
266 |
1 |
} |
|
267 |
|||
268 |
1 |
void test_calc_diff() { |
|
269 |
// Setup the test |
||
270 |
✓✗ | 2 |
StateModelFactory state_factory; |
271 |
crocoddyl::ImpulseModelMultiple model( |
||
272 |
2 |
boost::static_pointer_cast<crocoddyl::StateMultibody>( |
|
273 |
✓✗ | 1 |
state_factory.create( |
274 |
2 |
StateModelTypes::StateMultibody_RandomHumanoid))); |
|
275 |
|||
276 |
// create the corresponding data object |
||
277 |
1 |
pinocchio::Model& pinocchio_model = *model.get_state()->get_pinocchio().get(); |
|
278 |
✓✗ | 2 |
pinocchio::Data pinocchio_data(*model.get_state()->get_pinocchio().get()); |
279 |
|||
280 |
// create and add some impulse objects |
||
281 |
2 |
std::vector<boost::shared_ptr<crocoddyl::ImpulseModelAbstract> > models; |
|
282 |
2 |
std::vector<boost::shared_ptr<crocoddyl::ImpulseDataAbstract> > datas; |
|
283 |
✓✓ | 6 |
for (std::size_t i = 0; i < 5; ++i) { |
284 |
✓✗ | 10 |
std::ostringstream os; |
285 |
✓✗✓✗ |
5 |
os << "random_impulse_" << i; |
286 |
const boost::shared_ptr<crocoddyl::ImpulseModelAbstract>& m = |
||
287 |
✓✗ | 5 |
create_random_impulse(); |
288 |
✓✗✓✗ |
5 |
model.addImpulse(os.str(), m); |
289 |
✓✗ | 5 |
models.push_back(m); |
290 |
✓✗✓✗ |
5 |
datas.push_back(m->createData(&pinocchio_data)); |
291 |
} |
||
292 |
|||
293 |
// create the data of the multiple-impulses |
||
294 |
boost::shared_ptr<crocoddyl::ImpulseDataMultiple> data = |
||
295 |
✓✗ | 2 |
model.createData(&pinocchio_data); |
296 |
|||
297 |
// compute the multiple contact data for the case when all impulses are |
||
298 |
// defined as active |
||
299 |
✓✗ | 2 |
Eigen::VectorXd x1 = model.get_state()->rand(); |
300 |
✓✗✓✗ |
1 |
crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data, |
301 |
x1); |
||
302 |
✓✗✓✗ |
1 |
model.calc(data, x1); |
303 |
✓✗✓✗ |
1 |
model.calcDiff(data, x1); |
304 |
|||
305 |
// Check that nothing has been computed and that all value are initialized to |
||
306 |
// 0 |
||
307 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✓ |
1 |
BOOST_CHECK(!data->Jc.isZero()); |
308 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✓ |
1 |
BOOST_CHECK(!data->dv0_dq.isZero()); |
309 |
|||
310 |
// check Jc against single impulse computations |
||
311 |
1 |
std::size_t ni = 0; |
|
312 |
1 |
const std::size_t nv = model.get_state()->get_nv(); |
|
313 |
✓✓ | 6 |
for (std::size_t i = 0; i < 5; ++i) { |
314 |
5 |
const std::size_t ni_i = models[i]->get_nc(); |
|
315 |
✓✗✓✗ |
5 |
models[i]->calc(datas[i], x1); |
316 |
✓✗✓✗ |
5 |
models[i]->calcDiff(datas[i], x1); |
317 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
5 |
BOOST_CHECK(data->Jc.block(ni, 0, ni_i, nv) == datas[i]->Jc); |
318 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
5 |
BOOST_CHECK(data->dv0_dq.block(ni, 0, ni_i, nv) == datas[i]->dv0_dq); |
319 |
5 |
ni += ni_i; |
|
320 |
} |
||
321 |
1 |
ni = 0; |
|
322 |
|||
323 |
// compute the multiple impulse data for the case when the first three |
||
324 |
// impulses are defined as active |
||
325 |
✓✗✓✗ |
1 |
model.changeImpulseStatus("random_impulse_3", false); |
326 |
✓✗✓✗ |
1 |
model.changeImpulseStatus("random_impulse_4", false); |
327 |
✓✗ | 2 |
Eigen::VectorXd x2 = model.get_state()->rand(); |
328 |
✓✗✓✗ |
1 |
crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data, |
329 |
x2); |
||
330 |
✓✗✓✗ |
1 |
model.calc(data, x2); |
331 |
✓✗✓✗ |
1 |
model.calcDiff(data, x2); |
332 |
✓✓ | 6 |
for (std::size_t i = 0; i < 5; ++i) { |
333 |
5 |
const std::size_t ni_i = models[i]->get_nc(); |
|
334 |
✓✓ | 5 |
if (i < 3) { // we need to update data because this impulses are active |
335 |
✓✗✓✗ |
3 |
models[i]->calc(datas[i], x2); |
336 |
✓✗✓✗ |
3 |
models[i]->calcDiff(datas[i], x2); |
337 |
} |
||
338 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
5 |
BOOST_CHECK(data->Jc.block(ni, 0, ni_i, nv) == datas[i]->Jc); |
339 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
5 |
BOOST_CHECK(data->dv0_dq.block(ni, 0, ni_i, nv) == datas[i]->dv0_dq); |
340 |
5 |
ni += ni_i; |
|
341 |
} |
||
342 |
1 |
} |
|
343 |
|||
344 |
1 |
void test_calc_diff_no_recalc() { |
|
345 |
// Setup the test |
||
346 |
✓✗ | 2 |
StateModelFactory state_factory; |
347 |
crocoddyl::ImpulseModelMultiple model( |
||
348 |
2 |
boost::static_pointer_cast<crocoddyl::StateMultibody>( |
|
349 |
✓✗ | 1 |
state_factory.create( |
350 |
2 |
StateModelTypes::StateMultibody_RandomHumanoid))); |
|
351 |
|||
352 |
// create the corresponding data object |
||
353 |
1 |
pinocchio::Model& pinocchio_model = *model.get_state()->get_pinocchio().get(); |
|
354 |
✓✗ | 2 |
pinocchio::Data pinocchio_data(*model.get_state()->get_pinocchio().get()); |
355 |
|||
356 |
// create and add some impulse objects |
||
357 |
2 |
std::vector<boost::shared_ptr<crocoddyl::ImpulseModelAbstract> > models; |
|
358 |
2 |
std::vector<boost::shared_ptr<crocoddyl::ImpulseDataAbstract> > datas; |
|
359 |
✓✓ | 6 |
for (std::size_t i = 0; i < 5; ++i) { |
360 |
✓✗ | 10 |
std::ostringstream os; |
361 |
✓✗✓✗ |
5 |
os << "random_impulse_" << i; |
362 |
const boost::shared_ptr<crocoddyl::ImpulseModelAbstract>& m = |
||
363 |
✓✗ | 5 |
create_random_impulse(); |
364 |
✓✗✓✗ |
5 |
model.addImpulse(os.str(), m); |
365 |
✓✗ | 5 |
models.push_back(m); |
366 |
✓✗✓✗ |
5 |
datas.push_back(m->createData(&pinocchio_data)); |
367 |
} |
||
368 |
|||
369 |
// create the data of the multiple-impulses |
||
370 |
boost::shared_ptr<crocoddyl::ImpulseDataMultiple> data = |
||
371 |
✓✗ | 2 |
model.createData(&pinocchio_data); |
372 |
|||
373 |
// compute the multiple contact data for the case when all impulses are |
||
374 |
// defined as active |
||
375 |
✓✗ | 2 |
Eigen::VectorXd x1 = model.get_state()->rand(); |
376 |
✓✗✓✗ |
1 |
crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data, |
377 |
x1); |
||
378 |
✓✗✓✗ |
1 |
model.calcDiff(data, x1); |
379 |
|||
380 |
// Check that nothing has been computed and that all value are initialized to |
||
381 |
// 0 |
||
382 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✓ |
1 |
BOOST_CHECK(data->Jc.isZero()); |
383 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✓ |
1 |
BOOST_CHECK(!data->dv0_dq.isZero()); |
384 |
|||
385 |
// check Jc against single impulse computations |
||
386 |
1 |
std::size_t ni = 0; |
|
387 |
1 |
const std::size_t nv = model.get_state()->get_nv(); |
|
388 |
✓✓ | 6 |
for (std::size_t i = 0; i < 5; ++i) { |
389 |
5 |
const std::size_t ni_i = models[i]->get_nc(); |
|
390 |
✓✗✓✗ |
5 |
models[i]->calcDiff(datas[i], x1); |
391 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
5 |
BOOST_CHECK(data->Jc.block(ni, 0, ni_i, nv).isZero()); |
392 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
5 |
BOOST_CHECK(data->dv0_dq.block(ni, 0, ni_i, nv) == datas[i]->dv0_dq); |
393 |
5 |
ni += ni_i; |
|
394 |
} |
||
395 |
1 |
ni = 0; |
|
396 |
|||
397 |
// compute the multiple impulse data for the case when the first three |
||
398 |
// impulses are defined as active |
||
399 |
✓✗✓✗ |
1 |
model.changeImpulseStatus("random_impulse_3", false); |
400 |
✓✗✓✗ |
1 |
model.changeImpulseStatus("random_impulse_4", false); |
401 |
✓✗ | 2 |
Eigen::VectorXd x2 = model.get_state()->rand(); |
402 |
✓✗✓✗ |
1 |
crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data, |
403 |
x2); |
||
404 |
✓✗✓✗ |
1 |
model.calcDiff(data, x2); |
405 |
✓✓ | 6 |
for (std::size_t i = 0; i < 5; ++i) { |
406 |
5 |
const std::size_t ni_i = models[i]->get_nc(); |
|
407 |
✓✓ | 5 |
if (i < 3) { // we need to update data because this impulses are active |
408 |
✓✗✓✗ |
3 |
models[i]->calcDiff(datas[i], x2); |
409 |
} |
||
410 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
5 |
BOOST_CHECK(data->Jc.block(ni, 0, ni_i, nv).isZero()); |
411 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
5 |
BOOST_CHECK(data->dv0_dq.block(ni, 0, ni_i, nv) == datas[i]->dv0_dq); |
412 |
5 |
ni += ni_i; |
|
413 |
} |
||
414 |
1 |
} |
|
415 |
|||
416 |
1 |
void test_updateForce() { |
|
417 |
// Setup the test |
||
418 |
✓✗ | 2 |
StateModelFactory state_factory; |
419 |
crocoddyl::ImpulseModelMultiple model( |
||
420 |
2 |
boost::static_pointer_cast<crocoddyl::StateMultibody>( |
|
421 |
✓✗ | 1 |
state_factory.create( |
422 |
2 |
StateModelTypes::StateMultibody_RandomHumanoid))); |
|
423 |
|||
424 |
// create the corresponding data object |
||
425 |
1 |
pinocchio::Model& pinocchio_model = *model.get_state()->get_pinocchio().get(); |
|
426 |
✓✗ | 2 |
pinocchio::Data pinocchio_data(*model.get_state()->get_pinocchio().get()); |
427 |
|||
428 |
// create and add some impulse objects |
||
429 |
✓✓ | 6 |
for (unsigned i = 0; i < 5; ++i) { |
430 |
✓✗ | 5 |
std::ostringstream os; |
431 |
✓✗✓✗ |
5 |
os << "random_impulse_" << i; |
432 |
✓✗✓✗ ✓✗ |
5 |
model.addImpulse(os.str(), create_random_impulse()); |
433 |
} |
||
434 |
|||
435 |
// create the data of the multiple-impulses |
||
436 |
boost::shared_ptr<crocoddyl::ImpulseDataMultiple> data = |
||
437 |
✓✗ | 2 |
model.createData(&pinocchio_data); |
438 |
|||
439 |
// Compute the jacobian and check that the impulse model fetch it. |
||
440 |
✓✗ | 2 |
Eigen::VectorXd x = model.get_state()->rand(); |
441 |
✓✗✓✗ |
1 |
crocoddyl::unittest::updateAllPinocchio(&pinocchio_model, &pinocchio_data, x); |
442 |
|||
443 |
// create random forces |
||
444 |
✓✗✓✗ |
2 |
Eigen::VectorXd forces = Eigen::VectorXd::Random(model.get_nc()); |
445 |
|||
446 |
// update forces |
||
447 |
✓✗ | 1 |
model.updateForce(data, forces); |
448 |
|||
449 |
// Check that nothing has been computed and that all value are initialized to |
||
450 |
// 0 |
||
451 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✓ |
1 |
BOOST_CHECK(data->Jc.isZero()); |
452 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✓ |
1 |
BOOST_CHECK(data->dv0_dq.isZero()); |
453 |
1 |
crocoddyl::ImpulseModelMultiple::ImpulseDataContainer::iterator it_d, end_d; |
|
454 |
6 |
for (it_d = data->impulses.begin(), end_d = data->impulses.end(); |
|
455 |
✓✓ | 11 |
it_d != end_d; ++it_d) { |
456 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
5 |
BOOST_CHECK(!it_d->second->f.toVector().isZero()); |
457 |
} |
||
458 |
1 |
} |
|
459 |
|||
460 |
1 |
void test_updateVelocityDiff() { |
|
461 |
// Setup the test |
||
462 |
✓✗ | 2 |
StateModelFactory state_factory; |
463 |
crocoddyl::ImpulseModelMultiple model( |
||
464 |
2 |
boost::static_pointer_cast<crocoddyl::StateMultibody>( |
|
465 |
✓✗ | 1 |
state_factory.create( |
466 |
2 |
StateModelTypes::StateMultibody_RandomHumanoid))); |
|
467 |
|||
468 |
// create the corresponding data object |
||
469 |
✓✗ | 2 |
pinocchio::Data pinocchio_data(*model.get_state()->get_pinocchio().get()); |
470 |
|||
471 |
// create and add some impulse objects |
||
472 |
✓✓ | 6 |
for (unsigned i = 0; i < 5; ++i) { |
473 |
✓✗ | 5 |
std::ostringstream os; |
474 |
✓✗✓✗ |
5 |
os << "random_impulse_" << i; |
475 |
✓✗✓✗ ✓✗ |
5 |
model.addImpulse(os.str(), create_random_impulse()); |
476 |
} |
||
477 |
|||
478 |
// create the data of the multiple-impulses |
||
479 |
boost::shared_ptr<crocoddyl::ImpulseDataMultiple> data = |
||
480 |
✓✗ | 2 |
model.createData(&pinocchio_data); |
481 |
|||
482 |
// create the velocity diff |
||
483 |
✓✗ | 1 |
Eigen::MatrixXd dvnext_dx = Eigen::MatrixXd::Random( |
484 |
✓✗ | 3 |
model.get_state()->get_nv(), model.get_state()->get_ndx()); |
485 |
|||
486 |
// call the update |
||
487 |
✓✗ | 1 |
model.updateVelocityDiff(data, dvnext_dx); |
488 |
|||
489 |
// Test |
||
490 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
1 |
BOOST_CHECK((data->dvnext_dx - dvnext_dx).isZero(1e-9)); |
491 |
1 |
} |
|
492 |
|||
493 |
void test_updateForceDiff() { |
||
494 |
// Setup the test |
||
495 |
StateModelFactory state_factory; |
||
496 |
crocoddyl::ImpulseModelMultiple model( |
||
497 |
boost::static_pointer_cast<crocoddyl::StateMultibody>( |
||
498 |
state_factory.create( |
||
499 |
StateModelTypes::StateMultibody_RandomHumanoid))); |
||
500 |
|||
501 |
// create the corresponding data object |
||
502 |
pinocchio::Data pinocchio_data(*model.get_state()->get_pinocchio().get()); |
||
503 |
|||
504 |
// create and add some impulse objects |
||
505 |
for (unsigned i = 0; i < 5; ++i) { |
||
506 |
std::ostringstream os; |
||
507 |
os << "random_impulse_" << i; |
||
508 |
model.addImpulse(os.str(), create_random_impulse()); |
||
509 |
} |
||
510 |
|||
511 |
// create the data of the multiple-impulses |
||
512 |
boost::shared_ptr<crocoddyl::ImpulseDataMultiple> data = |
||
513 |
model.createData(&pinocchio_data); |
||
514 |
|||
515 |
// create force diff |
||
516 |
Eigen::MatrixXd df_dx = |
||
517 |
Eigen::MatrixXd::Random(model.get_nc(), model.get_state()->get_nv()); |
||
518 |
|||
519 |
// call update force diff |
||
520 |
model.updateForceDiff(data, df_dx); |
||
521 |
|||
522 |
// Test |
||
523 |
crocoddyl::ImpulseModelMultiple::ImpulseDataContainer::iterator it_d, end_d; |
||
524 |
for (it_d = data->impulses.begin(), end_d = data->impulses.end(); |
||
525 |
it_d != end_d; ++it_d) { |
||
526 |
BOOST_CHECK(!it_d->second->df_dx.isZero()); |
||
527 |
} |
||
528 |
} |
||
529 |
|||
530 |
void test_assert_updateForceDiff_assert_mismatch_model_data() { |
||
531 |
// Setup the test |
||
532 |
StateModelFactory state_factory; |
||
533 |
crocoddyl::ImpulseModelMultiple model1( |
||
534 |
boost::static_pointer_cast<crocoddyl::StateMultibody>( |
||
535 |
state_factory.create( |
||
536 |
StateModelTypes::StateMultibody_RandomHumanoid))); |
||
537 |
crocoddyl::ImpulseModelMultiple model2( |
||
538 |
boost::static_pointer_cast<crocoddyl::StateMultibody>( |
||
539 |
state_factory.create( |
||
540 |
StateModelTypes::StateMultibody_RandomHumanoid))); |
||
541 |
|||
542 |
// create the corresponding data object |
||
543 |
pinocchio::Data pinocchio_data(*model1.get_state()->get_pinocchio().get()); |
||
544 |
|||
545 |
// create and add some impulse objects |
||
546 |
std::vector<boost::shared_ptr<ImpulseModelFactory> > impulse_factories; |
||
547 |
for (unsigned i = 0; i < 5; ++i) { |
||
548 |
boost::shared_ptr<crocoddyl::ImpulseModelAbstract> rand_impulse = |
||
549 |
create_random_impulse(); |
||
550 |
{ |
||
551 |
std::ostringstream os; |
||
552 |
os << "random_impulse1_" << i; |
||
553 |
model1.addImpulse(os.str(), rand_impulse); |
||
554 |
} |
||
555 |
{ |
||
556 |
std::ostringstream os; |
||
557 |
os << "random_impulse2_" << i; |
||
558 |
model2.addImpulse(os.str(), rand_impulse); |
||
559 |
} |
||
560 |
} |
||
561 |
|||
562 |
// create the data of the multiple-impulses |
||
563 |
boost::shared_ptr<crocoddyl::ImpulseDataMultiple> data1 = |
||
564 |
model1.createData(&pinocchio_data); |
||
565 |
boost::shared_ptr<crocoddyl::ImpulseDataMultiple> data2 = |
||
566 |
model2.createData(&pinocchio_data); |
||
567 |
|||
568 |
// create force diff |
||
569 |
Eigen::MatrixXd df_dx = |
||
570 |
Eigen::MatrixXd::Random(model1.get_nc(), model1.get_state()->get_nv()); |
||
571 |
|||
572 |
// call that trigger assert |
||
573 |
std::string error_message = |
||
574 |
GetErrorMessages(boost::bind(&updateForceDiff, model1, data2, df_dx)); |
||
575 |
|||
576 |
// expected error message content |
||
577 |
std::string function_name = |
||
578 |
"void crocoddyl::ImpulseModelMultiple::updateForceDiff(" |
||
579 |
"const boost::shared_ptr<crocoddyl::ImpulseDataMultiple>&," |
||
580 |
" const MatrixXd&) const"; |
||
581 |
std::string assert_argument = |
||
582 |
"it_m->first == it_d->first && \"it doesn't match" |
||
583 |
" the impulse name between data and model\""; |
||
584 |
|||
585 |
// Perform the checks |
||
586 |
#ifndef __APPLE__ |
||
587 |
BOOST_CHECK(error_message.find(function_name) != std::string::npos); |
||
588 |
#endif |
||
589 |
BOOST_CHECK(error_message.find(assert_argument) != std::string::npos); |
||
590 |
} |
||
591 |
|||
592 |
1 |
void test_get_impulses() { |
|
593 |
// Setup the test |
||
594 |
✓✗ | 2 |
StateModelFactory state_factory; |
595 |
crocoddyl::ImpulseModelMultiple model( |
||
596 |
2 |
boost::static_pointer_cast<crocoddyl::StateMultibody>( |
|
597 |
✓✗ | 1 |
state_factory.create( |
598 |
2 |
StateModelTypes::StateMultibody_RandomHumanoid))); |
|
599 |
|||
600 |
// create the corresponding data object |
||
601 |
✓✗ | 2 |
pinocchio::Data pinocchio_data(*model.get_state()->get_pinocchio().get()); |
602 |
|||
603 |
// create and add some impulse objects |
||
604 |
✓✓ | 6 |
for (unsigned i = 0; i < 5; ++i) { |
605 |
✓✗ | 5 |
std::ostringstream os; |
606 |
✓✗✓✗ |
5 |
os << "random_impulse_" << i; |
607 |
✓✗✓✗ ✓✗ |
5 |
model.addImpulse(os.str(), create_random_impulse()); |
608 |
} |
||
609 |
|||
610 |
// get the impulses |
||
611 |
const crocoddyl::ImpulseModelMultiple::ImpulseModelContainer& impulses = |
||
612 |
1 |
model.get_impulses(); |
|
613 |
|||
614 |
// test |
||
615 |
1 |
crocoddyl::ImpulseModelMultiple::ImpulseModelContainer::const_iterator it_m, |
|
616 |
1 |
end_m; |
|
617 |
unsigned i; |
||
618 |
✓✓ | 6 |
for (i = 0, it_m = impulses.begin(), end_m = impulses.end(); it_m != end_m; |
619 |
5 |
++it_m, ++i) { |
|
620 |
✓✗ | 10 |
std::ostringstream os; |
621 |
✓✗✓✗ |
5 |
os << "random_impulse_" << i; |
622 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✓ |
5 |
BOOST_CHECK(it_m->first == os.str()); |
623 |
} |
||
624 |
1 |
} |
|
625 |
|||
626 |
1 |
void test_get_nc() { |
|
627 |
// Setup the test |
||
628 |
✓✗ | 2 |
StateModelFactory state_factory; |
629 |
crocoddyl::ImpulseModelMultiple model( |
||
630 |
2 |
boost::static_pointer_cast<crocoddyl::StateMultibody>( |
|
631 |
✓✗ | 1 |
state_factory.create( |
632 |
2 |
StateModelTypes::StateMultibody_RandomHumanoid))); |
|
633 |
|||
634 |
// create the corresponding data object |
||
635 |
✓✗ | 2 |
pinocchio::Data pinocchio_data(*model.get_state()->get_pinocchio().get()); |
636 |
|||
637 |
// create and add some impulse objects |
||
638 |
✓✓ | 6 |
for (unsigned i = 0; i < 5; ++i) { |
639 |
✓✗ | 5 |
std::ostringstream os; |
640 |
✓✗✓✗ |
5 |
os << "random_impulse_" << i; |
641 |
✓✗✓✗ ✓✗ |
5 |
model.addImpulse(os.str(), create_random_impulse()); |
642 |
} |
||
643 |
|||
644 |
// compute ni |
||
645 |
1 |
std::size_t ni = 0; |
|
646 |
1 |
crocoddyl::ImpulseModelMultiple::ImpulseModelContainer::const_iterator it_m, |
|
647 |
1 |
end_m; |
|
648 |
6 |
for (it_m = model.get_impulses().begin(), end_m = model.get_impulses().end(); |
|
649 |
✓✓ | 6 |
it_m != end_m; ++it_m) { |
650 |
5 |
ni += it_m->second->impulse->get_nc(); |
|
651 |
} |
||
652 |
|||
653 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✓ |
1 |
BOOST_CHECK(ni == model.get_nc()); |
654 |
1 |
} |
|
655 |
|||
656 |
//----------------------------------------------------------------------------// |
||
657 |
|||
658 |
1 |
void register_unit_tests() { |
|
659 |
1 |
framework::master_test_suite().add( |
|
660 |
✓✗✓✗ ✓✗✓✗ |
1 |
BOOST_TEST_CASE(boost::bind(&test_constructor))); |
661 |
1 |
framework::master_test_suite().add( |
|
662 |
✓✗✓✗ ✓✗✓✗ |
1 |
BOOST_TEST_CASE(boost::bind(&test_addImpulse))); |
663 |
1 |
framework::master_test_suite().add( |
|
664 |
✓✗✓✗ ✓✗✓✗ |
1 |
BOOST_TEST_CASE(boost::bind(&test_addImpulse_error_message))); |
665 |
1 |
framework::master_test_suite().add( |
|
666 |
✓✗✓✗ ✓✗✓✗ |
1 |
BOOST_TEST_CASE(boost::bind(&test_removeImpulse))); |
667 |
1 |
framework::master_test_suite().add( |
|
668 |
✓✗✓✗ ✓✗✓✗ |
1 |
BOOST_TEST_CASE(boost::bind(&test_removeImpulse_error_message))); |
669 |
✓✗✓✗ ✓✗✓✗ |
1 |
framework::master_test_suite().add(BOOST_TEST_CASE(boost::bind(&test_calc))); |
670 |
1 |
framework::master_test_suite().add( |
|
671 |
✓✗✓✗ ✓✗✓✗ |
1 |
BOOST_TEST_CASE(boost::bind(&test_calc_diff))); |
672 |
1 |
framework::master_test_suite().add( |
|
673 |
✓✗✓✗ ✓✗✓✗ |
1 |
BOOST_TEST_CASE(boost::bind(&test_calc_diff_no_recalc))); |
674 |
1 |
framework::master_test_suite().add( |
|
675 |
✓✗✓✗ ✓✗✓✗ |
1 |
BOOST_TEST_CASE(boost::bind(&test_updateForce))); |
676 |
1 |
framework::master_test_suite().add( |
|
677 |
✓✗✓✗ ✓✗✓✗ |
1 |
BOOST_TEST_CASE(boost::bind(&test_updateVelocityDiff))); |
678 |
1 |
framework::master_test_suite().add( |
|
679 |
✓✗✓✗ ✓✗✓✗ |
1 |
BOOST_TEST_CASE(boost::bind(&test_get_impulses))); |
680 |
1 |
framework::master_test_suite().add( |
|
681 |
✓✗✓✗ ✓✗✓✗ |
1 |
BOOST_TEST_CASE(boost::bind(&test_get_nc))); |
682 |
1 |
} |
|
683 |
|||
684 |
1 |
bool init_function() { |
|
685 |
1 |
register_unit_tests(); |
|
686 |
1 |
return true; |
|
687 |
} |
||
688 |
|||
689 |
1 |
int main(int argc, char** argv) { |
|
690 |
1 |
return ::boost::unit_test::unit_test_main(&init_function, argc, argv); |
|
691 |
} |
Generated by: GCOVR (Version 4.2) |