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