- 3.0.2 core module.
DynamicsLinearizerADCG.h
Go to the documentation of this file.
1 /**********************************************************************************************************************
2 This file is part of the Control Toolbox (https://github.com/ethz-adrl/control-toolbox), copyright by ETH Zurich.
3 Licensed under the BSD-2 license (see LICENSE file in main directory)
4 **********************************************************************************************************************/
5 #pragma once
6 
7 #ifdef CPPADCG
8 #ifdef CPPAD
9 
12 
13 namespace ct {
14 namespace core {
15 
17 
28 template <size_t STATE_DIM, size_t CONTROL_DIM, typename SCALAR, typename TIME>
29 class DynamicsLinearizerADCG : public internal::DynamicsLinearizerADBase<STATE_DIM, CONTROL_DIM, SCALAR, TIME>
30 {
31 public:
32  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
33 
34  typedef internal::DynamicsLinearizerADBase<STATE_DIM, CONTROL_DIM, SCALAR, TIME> Base;
35 
36  typedef typename Base::OUT_SCALAR OUT_SCALAR;
37 
38  typedef typename Base::state_vector_t state_vector_t;
39  typedef typename Base::control_vector_t control_vector_t;
40 
41  typedef typename Base::state_matrix_t state_matrix_t;
42  typedef typename Base::state_control_matrix_t state_control_matrix_t;
43 
44  typedef typename Base::dynamics_fct_t dynamics_fct_t;
45 
47 
52  DynamicsLinearizerADCG(dynamics_fct_t dyn, bool cacheJac = true)
53  : Base(dyn),
54  dynamics_fct_(dyn),
55  dFdx_(state_matrix_t::Zero()),
56  dFdu_(state_control_matrix_t::Zero()),
57  x_at_cache_(state_vector_t::Random()),
58  u_at_cache_(control_vector_t::Random()),
59  jitLibName_(""),
60  compiled_(false),
61  cacheJac_(cacheJac),
62  maxTempVarCountState_(0),
63  maxTempVarCountControl_(0)
64  {
65  }
66 
68  DynamicsLinearizerADCG(const DynamicsLinearizerADCG& rhs)
69  : Base(rhs.dynamics_fct_),
70  dynamics_fct_(rhs.dynamics_fct_),
71  dFdx_(rhs.dFdx_),
72  dFdu_(rhs.dFdu_),
73  x_at_cache_(rhs.x_at_cache_),
74  u_at_cache_(rhs.u_at_cache_),
75  jitLibName_(rhs.jitLibName_),
76  compiled_(rhs.compiled_),
77  cacheJac_(rhs.cacheJac_),
78  maxTempVarCountState_(rhs.maxTempVarCountState_),
79  maxTempVarCountControl_(rhs.maxTempVarCountControl_)
80  {
81  if (compiled_)
82  {
83  dynamicLib_ = internal::CGHelpers::loadDynamicLibCppad<OUT_SCALAR>(jitLibName_);
84  model_ = std::shared_ptr<CppAD::cg::GenericModel<OUT_SCALAR>>(
85  dynamicLib_->model("DynamicsLinearizerADCG" + jitLibName_));
86  }
87  }
88 
90 
98  const state_matrix_t& getDerivativeState(const state_vector_t& x,
99  const control_vector_t& u,
100  const OUT_SCALAR t = 0.0)
101  {
102  if (!compiled_)
103  throw std::runtime_error(
104  "Called getDerivativeState on ADCodegenLinearizer before compiling. Call 'compile()' before");
105 
106  // if jacobian is not supposed to be cached or if values change, recompute it
107  if (!cacheJac_ || (x != x_at_cache_ || u != u_at_cache_))
108  computeJacobian(x, u);
109 
110  return dFdx_;
111  }
112 
114 
122  const state_control_matrix_t& getDerivativeControl(const state_vector_t& x,
123  const control_vector_t& u,
124  const OUT_SCALAR t = 0.0)
125  {
126  if (!compiled_)
127  throw std::runtime_error(
128  "Called getDerivativeState on ADCodegenLinearizer before compiling. Call 'compile()' before");
129 
130  // if jacobian is not supposed to be cached or if values change, recompute it
131  if (!cacheJac_ || (x != x_at_cache_ || u != u_at_cache_))
132  computeJacobian(x, u);
133 
134  return dFdu_;
135  }
136 
138 
144  void compileJIT(const std::string& libName = "DynamicsLinearizerADCG", bool verbose = false)
145  {
146  if (compiled_)
147  return;
148 
149  struct timespec ts;
150  clock_gettime(CLOCK_MONOTONIC, &ts);
151 
152  // assigning a unique identifier to the library in order to avoid race conditions in JIT
153  std::string uniqueID =
154  std::to_string(std::hash<std::thread::id>()(std::this_thread::get_id())) + "_" + std::to_string(ts.tv_nsec);
155 
156  jitLibName_ = libName + uniqueID;
157 
158  CppAD::cg::ModelCSourceGen<OUT_SCALAR> cgen(this->f_, "DynamicsLinearizerADCG" + jitLibName_);
159  cgen.setCreateJacobian(true);
160  CppAD::cg::ModelLibraryCSourceGen<OUT_SCALAR> libcgen(cgen);
161  std::string tempDir = "cppad_temp" + uniqueID;
162  if (verbose)
163  {
164  std::cout << "Starting to compile " << jitLibName_ << " library ..." << std::endl;
165  std::cout << "In temporary directory " << tempDir << std::endl;
166  }
167 
168  // compile source code
169  CppAD::cg::DynamicModelLibraryProcessor<OUT_SCALAR> p(libcgen, jitLibName_);
170  compiler_.setTemporaryFolder(tempDir);
171  dynamicLib_ = std::shared_ptr<CppAD::cg::DynamicLib<OUT_SCALAR>>(p.createDynamicLibrary(compiler_));
172 
173  model_ = std::shared_ptr<CppAD::cg::GenericModel<OUT_SCALAR>>(
174  dynamicLib_->model("DynamicsLinearizerADCG" + jitLibName_));
175 
176  compiled_ = true;
177 
178  if (verbose)
179  std::cout << "Successfully compiled " << jitLibName_ << std::endl;
180  }
181 
183 
196  void generateCode(std::string& codeJacA, std::string& codeJacB, bool useReverse = false, bool ignoreZero = true)
197  {
198  this->sparsityA_.clearWork(); //clears the cppad sparsity work possibly done before
199  size_t jacDimension = STATE_DIM * STATE_DIM;
200  codeJacA = internal::CGHelpers::generateJacobianSource<typename SCALAR::value_type, OUT_SCALAR>(this->f_,
201  this->sparsityA_, jacDimension, maxTempVarCountState_, useReverse, ignoreZero, "jac", "x_in", "vX_",
202  Base::getOutScalarType());
203 
204  this->sparsityB_.clearWork();
205  jacDimension = STATE_DIM * CONTROL_DIM;
206  codeJacB = internal::CGHelpers::generateJacobianSource<typename SCALAR::value_type, OUT_SCALAR>(this->f_,
207  this->sparsityB_, jacDimension, maxTempVarCountControl_, useReverse, ignoreZero, "jac", "x_in", "vU_",
208  Base::getOutScalarType());
209  }
210 
212  void getMaxTempVarCount(size_t& maxTempVarCountState, size_t& maxTempVarCountControl) const
213  {
214  maxTempVarCountState = maxTempVarCountState_;
215  maxTempVarCountControl = maxTempVarCountControl_;
216  }
217 
219  const std::shared_ptr<CppAD::cg::DynamicLib<OUT_SCALAR>> getDynamicLib() const { return dynamicLib_; }
220 protected:
222 
227  void computeJacobian(const state_vector_t& x, const control_vector_t& u)
228  {
229  // copy to dynamic type due to requirements by cppad
230  Eigen::Matrix<OUT_SCALAR, Eigen::Dynamic, 1> input(STATE_DIM + CONTROL_DIM);
231  input << x, u;
232 
233  Eigen::Matrix<OUT_SCALAR, Eigen::Dynamic, 1> jac(Base::FullJac_entries);
234 
235  jac = model_->Jacobian(input);
236 
237  Eigen::Map<Eigen::Matrix<OUT_SCALAR, STATE_DIM + CONTROL_DIM, STATE_DIM>> out(jac.data());
238 
239  dFdx_ = out.template topRows<STATE_DIM>().transpose();
240  dFdu_ = out.template bottomRows<CONTROL_DIM>().transpose();
241 
242  x_at_cache_ = x;
243  u_at_cache_ = u;
244  }
245 
246 
247  dynamics_fct_t dynamics_fct_;
248 
249  state_matrix_t dFdx_;
250  state_control_matrix_t dFdu_;
251 
252  state_vector_t x_at_cache_;
253  control_vector_t u_at_cache_;
254 
255  std::string jitLibName_;
256  bool compiled_;
257  bool cacheJac_;
258  CppAD::cg::GccCompiler<OUT_SCALAR> compiler_;
259 
260  std::shared_ptr<CppAD::cg::DynamicLib<OUT_SCALAR>> dynamicLib_;
261  std::shared_ptr<CppAD::cg::GenericModel<OUT_SCALAR>> model_;
262 
263  size_t maxTempVarCountState_;
264  size_t maxTempVarCountControl_;
265 };
266 
267 } // namespace core
268 } // namespace ct
269 
270 #endif
271 #endif
Eigen::Matrix< double, nControls, 1 > control_vector_t
const bool verbose
Definition: JacobianCGTest.h:19
Eigen::Matrix< double, nStates, nStates > state_matrix_t
Eigen::Matrix< double, nStates, 1 > state_vector_t