GCC Code Coverage Report


Directory: ./
File: bindings/python/crocoddyl/multibody/impulses/multiple-impulses.cpp
Date: 2025-03-26 19:23:43
Exec Total Coverage
Lines: 50 52 96.2%
Branches: 118 236 50.0%

Line Branch Exec Source
1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (C) 2019-2025, LAAS-CNRS, University of Edinburgh,
5 // Heriot-Watt University
6 // Copyright note valid unless otherwise stated in individual files.
7 // All rights reserved.
8 ///////////////////////////////////////////////////////////////////////////////
9
10 #include "crocoddyl/multibody/impulses/multiple-impulses.hpp"
11
12 #include <functional>
13 #include <map>
14 #include <memory>
15 #include <string>
16 #include <utility>
17
18 #include "python/crocoddyl/multibody/multibody.hpp"
19 #include "python/crocoddyl/utils/map-converter.hpp"
20
21 namespace crocoddyl {
22 namespace python {
23
24 template <typename Model>
25 struct ImpulseItemVisitor : public bp::def_visitor<ImpulseItemVisitor<Model>> {
26 template <class PyClass>
27 40 void visit(PyClass& cl) const {
28
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
40 cl.def_readwrite("name", &Model::name, "impulse name")
29
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
40 .add_property(
30 "impulse",
31 bp::make_getter(&Model::impulse,
32 bp::return_value_policy<bp::return_by_value>()),
33 "impulse model")
34
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
40 .def_readwrite("active", &Model::active, "impulse status")
35
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
40 .def(CopyableVisitor<Model>());
36 40 }
37 };
38
39 template <typename Model>
40 struct ImpulseModelMultipleVisitor
41 : public bp::def_visitor<ImpulseModelMultipleVisitor<Model>> {
42
1/2
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
64 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(ImpulseModelMultiple_addImpulse_wrap,
43 Model::addImpulse, 2, 3)
44 template <class PyClass>
45 40 void visit(PyClass& cl) const {
46 120 cl.def(
47 "addImpulse", &Model::addImpulse,
48
1/2
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
40 ImpulseModelMultiple_addImpulse_wrap(
49 bp::args("self", "name", "impulse", "active"),
50 "Add an impulse item.\n\n"
51 ":param name: impulse name\n"
52 ":param impulse: impulse model\n"
53 ":param active: True if the impulse is activated (default true)"))
54
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 .def("removeImpulse", &Model::removeImpulse, bp::args("self", "name"),
55 "Remove an impulse item.\n\n"
56 ":param name: impulse name")
57
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 .def("changeImpulseStatus", &Model::changeImpulseStatus,
58 bp::args("self", "name", "active"),
59 "Change the impulse status.\n\n"
60 ":param name: impulse name\n"
61 ":param active: impulse status (true for active and false for "
62 "inactive)")
63
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 .def("calc", &Model::calc, bp::args("self", "data", "x"),
64 "Compute the impulse Jacobian and drift.\n\n"
65 "The rigid impulse model throught acceleration-base holonomic "
66 "constraint of the impulse frame placement.\n"
67 ":param data: impulse data\n"
68 ":param x: state point (dim. state.nx)")
69
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 .def("calcDiff", &Model::calcDiff, bp::args("self", "data", "x"),
70 "Compute the derivatives of the impulse holonomic constraint.\n\n"
71 "The rigid impulse model throught acceleration-base holonomic "
72 "constraint of the impulse frame placement. It assumes that calc "
73 "has been run first.\n"
74 ":param data: impulse data\n"
75 ":param x: state point (dim. state.nx)")
76
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 .def("updateVelocity", &Model::updateVelocity,
77 bp::args("self", "data", "vnext"),
78 "Update the system velocity after impulse.\n\n"
79 ":param data: impulse data\n"
80 ":param vnext: velocity after impulse (dimension nv)")
81
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 .def("updateForce", &Model::updateForce,
82 bp::args("self", "data", "force"),
83 "Update the spatial impulse defined in frame coordinate.\n\n"
84 ":param data: impulse data\n"
85 ":param force: force vector (dimension ni)")
86
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 .def("updateVelocityDiff", &Model::updateVelocityDiff,
87 bp::args("self", "data", "dvnext_dx"),
88 "Update the Jacobian of the system velocity after impulse.\n\n"
89 ":param data: impulse data\n"
90 ":param dvnext_dx: Jacobian of the impulse velocity (dimension "
91 "nv*ndx)")
92
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 .def("updateForceDiff", &Model::updateForceDiff,
93 bp::args("self", "data", "df_dx"),
94 "Update the Jacobian of the spatial impulse defined in frame "
95 "coordinate.\n\n"
96 ":param data: impulse data\n"
97 ":param df_dx: Jacobian of the impulse force (dimension ni*ndx)")
98
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 .def("updateRneaDiff", &Model::updateRneaDiff,
99 bp::args("self", "data", "pinocchio"),
100 "Update the RNEA derivative dtau_dq by by adding the skew term "
101 "(necessary for impulses expressed in LOCAL_WORLD_ALIGNED / "
102 "WORLD).\n\n"
103 ":param data: impulse data\n"
104 ":param pinocchio: Pinocchio data")
105
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 .def("createData", &Model::createData,
106 bp::with_custodian_and_ward_postcall<0, 2>(),
107 bp::args("self", "data"),
108 "Create the total impulse data.\n\n"
109 ":param data: Pinocchio data\n"
110 ":return total impulse data.")
111
3/6
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
40 .add_property(
112 "impulses",
113 bp::make_function(&Model::get_impulses,
114 40 bp::return_value_policy<bp::return_by_value>()),
115 "stack of impulses")
116
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
40 .add_property(
117 "state",
118 bp::make_function(&Model::get_state,
119 40 bp::return_value_policy<bp::return_by_value>()),
120 "state of the multibody system")
121
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 .add_property("nc", bp::make_function(&Model::get_nc),
122 "dimension of the active impulse vector")
123
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
80 .add_property("nc_total", bp::make_function(&Model::get_nc_total),
124 "dimension of the total impulse vector")
125
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
40 .add_property(
126 "active_set",
127 bp::make_function(&Model::get_active_set,
128 40 bp::return_value_policy<bp::return_by_value>()),
129 "set of names of active impulse items")
130
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
40 .add_property(
131 "inactive_set",
132 bp::make_function(&Model::get_inactive_set,
133 40 bp::return_value_policy<bp::return_by_value>()),
134 "set of names of inactive impulse items")
135
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
40 .def("getImpulseStatus", &Model::getImpulseStatus,
136 bp::args("self", "name"),
137 "Return the impulse status of a given impulse name.\n\n"
138 ":param name: impulse name");
139 40 }
140 };
141
142 template <typename Data>
143 struct ImpulseDataMultipleVisitor
144 : public bp::def_visitor<ImpulseDataMultipleVisitor<Data>> {
145 template <class PyClass>
146 40 void visit(PyClass& cl) const {
147
3/6
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
40 cl.add_property(
148 40 "Jc", bp::make_getter(&Data::Jc, bp::return_internal_reference<>()),
149 bp::make_setter(&Data::Jc),
150 "Jacobian for all impulses (active and inactive)")
151
3/6
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
80 .add_property(
152 "dv0_dq",
153 40 bp::make_getter(&Data::dv0_dq, bp::return_internal_reference<>()),
154 bp::make_setter(&Data::dv0_dq),
155 "Jacobian of the previous impulse velocity (active and inactive)")
156
3/6
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
80 .add_property(
157 "vnext",
158 40 bp::make_getter(&Data::vnext, bp::return_internal_reference<>()),
159 bp::make_setter(&Data::vnext), "impulse system velocity")
160
3/6
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
80 .add_property("dvnext_dx",
161 bp::make_getter(&Data::dvnext_dx,
162 40 bp::return_internal_reference<>()),
163 bp::make_setter(&Data::dvnext_dx),
164 "Jacobian of the impulse system velocity")
165
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
40 .add_property(
166 "impulses",
167 bp::make_getter(&Data::impulses,
168 40 bp::return_value_policy<bp::return_by_value>()),
169 "stack of impulses data")
170
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
40 .def_readwrite("fext", &Data::fext, "external spatial forces");
171 40 }
172 };
173
174 #define CROCODDYL_IMPULSE_ITEM_PYTHON_BINDINGS(Scalar) \
175 typedef ImpulseItemTpl<Scalar> Model; \
176 typedef Model::ImpulseModelAbstract ImpulseModel; \
177 typedef std::shared_ptr<Model> ImpulseItemPtr; \
178 typedef ImpulseDataAbstractTpl<Scalar> ImpulseData; \
179 typedef std::shared_ptr<ImpulseData> ImpulseDataPtr; \
180 StdMapPythonVisitor< \
181 std::string, ImpulseItemPtr, std::less<std::string>, \
182 std::allocator<std::pair<const std::string, ImpulseItemPtr>>, \
183 true>::expose("StdMap_ImpulseItem"); \
184 StdMapPythonVisitor< \
185 std::string, ImpulseDataPtr, std::less<std::string>, \
186 std::allocator<std::pair<const std::string, ImpulseDataPtr>>, \
187 true>::expose("StdMap_ImpulseData"); \
188 bp::register_ptr_to_python<std::shared_ptr<Model>>(); \
189 bp::class_<Model>( \
190 "ImpulseItem", "Describe a impulse item.\n\n", \
191 bp::init<std::string, std::shared_ptr<ImpulseModel>, \
192 bp::optional<bool>>( \
193 bp::args("self", "name", "impulse", "active"), \
194 "Initialize the impulse item.\n\n" \
195 ":param name: impulse name\n" \
196 ":param impulse: impulse model\n" \
197 ":param active: True if the impulse is activated (default true)")) \
198 .def(ImpulseItemVisitor<Model>()) \
199 .def(CastVisitor<Model>()) \
200 .def(PrintableVisitor<Model>()) \
201 .def(CopyableVisitor<Model>());
202
203 #define CROCODDYL_IMPULSE_MODEL_MULTIPLE_PYTHON_BINDINGS(Scalar) \
204 typedef ImpulseModelMultipleTpl<Scalar> Model; \
205 typedef Model::StateMultibody State; \
206 bp::register_ptr_to_python<std::shared_ptr<Model>>(); \
207 bp::class_<Model>("ImpulseModelMultiple", \
208 bp::init<std::shared_ptr<State>>( \
209 bp::args("self", "state"), \
210 "Initialize the multiple impulse model.\n\n" \
211 ":param state: state of the multibody system")) \
212 .def(ImpulseModelMultipleVisitor<Model>()) \
213 .def(CastVisitor<Model>()) \
214 .def(PrintableVisitor<Model>()) \
215 .def(CopyableVisitor<Model>());
216
217 #define CROCODDYL_IMPULSE_DATA_MULTIPLE_PYTHON_BINDINGS(Scalar) \
218 typedef ImpulseDataMultipleTpl<Scalar> Data; \
219 typedef ImpulseModelMultipleTpl<Scalar> Model; \
220 typedef pinocchio::DataTpl<Scalar> PinocchioData; \
221 bp::register_ptr_to_python<std::shared_ptr<Data>>(); \
222 bp::class_<Data>( \
223 "ImpulseDataMultiple", "Data class for multiple impulses.\n\n", \
224 bp::init<Model*, PinocchioData*>( \
225 bp::args("self", "model", "data"), \
226 "Create multi-impulse data.\n\n" \
227 ":param model: multi-impulse model\n" \
228 ":param data: Pinocchio data")[bp::with_custodian_and_ward< \
229 1, 2, bp::with_custodian_and_ward<1, 3>>()]) \
230 .def(ImpulseDataMultipleVisitor<Data>()) \
231 .def(CopyableVisitor<Data>());
232
233 10 void exposeImpulseMultiple() {
234
29/58
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 10 times.
✗ Branch 10 not taken.
✓ Branch 17 taken 10 times.
✗ Branch 18 not taken.
✓ Branch 21 taken 10 times.
✗ Branch 22 not taken.
✓ Branch 24 taken 10 times.
✗ Branch 25 not taken.
✓ Branch 33 taken 10 times.
✗ Branch 34 not taken.
✓ Branch 36 taken 10 times.
✗ Branch 37 not taken.
✓ Branch 39 taken 10 times.
✗ Branch 40 not taken.
✓ Branch 42 taken 10 times.
✗ Branch 43 not taken.
✓ Branch 45 taken 10 times.
✗ Branch 46 not taken.
✓ Branch 48 taken 10 times.
✗ Branch 49 not taken.
✓ Branch 54 taken 10 times.
✗ Branch 55 not taken.
✓ Branch 57 taken 10 times.
✗ Branch 58 not taken.
✓ Branch 60 taken 10 times.
✗ Branch 61 not taken.
✓ Branch 66 taken 10 times.
✗ Branch 67 not taken.
✓ Branch 70 taken 10 times.
✗ Branch 71 not taken.
✓ Branch 73 taken 10 times.
✗ Branch 74 not taken.
✓ Branch 81 taken 10 times.
✗ Branch 82 not taken.
✓ Branch 85 taken 10 times.
✗ Branch 86 not taken.
✓ Branch 88 taken 10 times.
✗ Branch 89 not taken.
✓ Branch 95 taken 10 times.
✗ Branch 96 not taken.
✓ Branch 98 taken 10 times.
✗ Branch 99 not taken.
✓ Branch 101 taken 10 times.
✗ Branch 102 not taken.
✓ Branch 104 taken 10 times.
✗ Branch 105 not taken.
✓ Branch 107 taken 10 times.
✗ Branch 108 not taken.
✓ Branch 110 taken 10 times.
✗ Branch 111 not taken.
✓ Branch 113 taken 10 times.
✗ Branch 114 not taken.
✓ Branch 116 taken 10 times.
✗ Branch 117 not taken.
20 CROCODDYL_PYTHON_SCALARS(CROCODDYL_IMPULSE_ITEM_PYTHON_BINDINGS)
235
17/34
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 10 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 10 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 10 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 10 times.
✗ Branch 19 not taken.
✓ Branch 24 taken 10 times.
✗ Branch 25 not taken.
✓ Branch 27 taken 10 times.
✗ Branch 28 not taken.
✓ Branch 30 taken 10 times.
✗ Branch 31 not taken.
✓ Branch 35 taken 10 times.
✗ Branch 36 not taken.
✓ Branch 38 taken 10 times.
✗ Branch 39 not taken.
✓ Branch 41 taken 10 times.
✗ Branch 42 not taken.
✓ Branch 44 taken 10 times.
✗ Branch 45 not taken.
✓ Branch 47 taken 10 times.
✗ Branch 48 not taken.
✓ Branch 50 taken 10 times.
✗ Branch 51 not taken.
✓ Branch 53 taken 10 times.
✗ Branch 54 not taken.
✓ Branch 56 taken 10 times.
✗ Branch 57 not taken.
20 CROCODDYL_PYTHON_SCALARS(CROCODDYL_IMPULSE_MODEL_MULTIPLE_PYTHON_BINDINGS)
236
15/30
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 10 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 10 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 10 times.
✗ Branch 16 not taken.
✓ Branch 21 taken 10 times.
✗ Branch 22 not taken.
✓ Branch 24 taken 10 times.
✗ Branch 25 not taken.
✓ Branch 27 taken 10 times.
✗ Branch 28 not taken.
✓ Branch 32 taken 10 times.
✗ Branch 33 not taken.
✓ Branch 35 taken 10 times.
✗ Branch 36 not taken.
✓ Branch 38 taken 10 times.
✗ Branch 39 not taken.
✓ Branch 41 taken 10 times.
✗ Branch 42 not taken.
✓ Branch 44 taken 10 times.
✗ Branch 45 not taken.
✓ Branch 47 taken 10 times.
✗ Branch 48 not taken.
✓ Branch 50 taken 10 times.
✗ Branch 51 not taken.
20 CROCODDYL_PYTHON_SCALARS(CROCODDYL_IMPULSE_DATA_MULTIPLE_PYTHON_BINDINGS)
237 10 }
238
239 } // namespace python
240 } // namespace crocoddyl
241