GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: unittest/test_multiple_impulses.cpp Lines: 317 375 84.5 %
Date: 2024-02-13 11:12:33 Branches: 545 1178 46.3 %

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
}