collocation.cpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
6  * KU Leuven. All rights reserved.
7  * Copyright (C) 2011-2014 Greg Horn
8  *
9  * CasADi is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 3 of the License, or (at your option) any later version.
13  *
14  * CasADi is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with CasADi; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 
26 #include "collocation.hpp"
27 #include "casadi/core/polynomial.hpp"
28 #include "casadi/core/casadi_misc.hpp"
29 
30 namespace casadi {
31 
32  extern "C"
33  int CASADI_INTEGRATOR_COLLOCATION_EXPORT
34  casadi_register_integrator_collocation(Integrator::Plugin* plugin) {
35  plugin->creator = Collocation::creator;
36  plugin->name = "collocation";
37  plugin->doc = Collocation::meta_doc.c_str();
38  plugin->version = CASADI_VERSION;
39  plugin->options = &Collocation::options_;
40  plugin->deserialize = &Collocation::deserialize;
41  return 0;
42  }
43 
44  extern "C"
45  void CASADI_INTEGRATOR_COLLOCATION_EXPORT casadi_load_integrator_collocation() {
47  }
48 
49  Collocation::Collocation(const std::string& name, const Function& dae,
50  double t0, const std::vector<double>& tout)
51  : ImplicitFixedStepIntegrator(name, dae, t0, tout) {
52  }
53 
55  }
56 
59  {{"interpolation_order",
60  {OT_INT,
61  "Order of the interpolating polynomials"}},
62  {"collocation_scheme",
63  {OT_STRING,
64  "Collocation scheme: radau|legendre"}}
65  }
66  };
67 
68  void Collocation::init(const Dict& opts) {
69  // Default options
70  deg_ = 3;
71  collocation_scheme_ = "radau";
72 
73  // Read options
74  for (auto&& op : opts) {
75  if (op.first=="interpolation_order") {
76  deg_ = op.second;
77  } else if (op.first=="collocation_scheme") {
78  collocation_scheme_ = op.second.to_string();
79  }
80  }
81 
82  // Call the base class init
84  }
85 
86  MX Collocation::algebraic_state_init(const MX& x0, const MX& z0) const {
87  MX ret = vertcat(x0, z0);
88  return repmat(ret, deg_);
89  }
91  return Z(Slice(Z.size1()-nz_, Z.size1()));
92  }
93 
95  // Continuous-time dynamics, forward problem
96  Function f = get_function("dae");
97 
98  // All collocation time points
99  std::vector<double> tau_root = collocation_points(deg_, collocation_scheme_);
100  tau_root.insert(tau_root.begin(), 0);
101 
102  // Coefficients of the collocation equation
103  std::vector<std::vector<double> > C(deg_ + 1, std::vector<double>(deg_ + 1, 0));
104 
105  // Coefficients of the continuity equation
106  std::vector<double> D(deg_ + 1, 0);
107 
108  // Coefficients of the quadratures
109  std::vector<double> B(deg_ + 1, 0);
110 
111  // For all collocation points
112  for (casadi_int j = 0; j < deg_ + 1; ++j) {
113 
114  // Construct Lagrange polynomials to get the polynomial basis at the collocation point
115  Polynomial p = 1;
116  for (casadi_int r = 0; r < deg_+1; ++r) {
117  if (r!=j) {
118  p *= Polynomial(-tau_root[r], 1) / (tau_root[j] - tau_root[r]);
119  }
120  }
121 
122  // Evaluate the polynomial at the final time to get the
123  // coefficients of the continuity equation
124  if (collocation_scheme_=="radau") {
125  D[j] = j==deg_ ? 1 : 0;
126  } else {
127  D[j] = p(1.0);
128  }
129 
130  // Evaluate the time derivative of the polynomial at all collocation points to
131  // get the coefficients of the continuity equation
132  Polynomial dp = p.derivative();
133  for (casadi_int r = 0; r < deg_ + 1; ++r) {
134  C[j][r] = dp(tau_root[r]);
135  }
136 
137  // Integrate polynomial to get the coefficients of the quadratures
138  Polynomial ip = p.anti_derivative();
139  B[j] = ip(1.0);
140  }
141 
142  // Symbolic inputs
143  MX t0 = MX::sym("t0", f.sparsity_in(DYN_T));
144  MX h = MX::sym("h");
145  MX x0 = MX::sym("x0", f.sparsity_in(DYN_X));
146  MX p = MX::sym("p", f.sparsity_in(DYN_P));
147  MX u = MX::sym("u", f.sparsity_in(DYN_U));
148 
149  // Implicitly defined variables (z and x)
150  MX v = MX::sym("v", deg_ * (nx1_ + nz1_));
151  std::vector<casadi_int> v_offset(1, 0);
152  for (casadi_int d = 0; d < deg_; ++d) {
153  v_offset.push_back(v_offset.back() + nx1_);
154  v_offset.push_back(v_offset.back() + nz1_);
155  }
156  std::vector<MX> vv = vertsplit(v, v_offset);
157  std::vector<MX>::const_iterator vv_it = vv.begin();
158 
159  // Collocated states
160  std::vector<MX> x(deg_ + 1), z(deg_ + 1);
161  for (casadi_int d = 1; d <= deg_; ++d) {
162  x[d] = *vv_it++;
163  z[d] = *vv_it++;
164  }
165  casadi_assert_dev(vv_it == vv.end());
166 
167  // Collocation time points
168  std::vector<MX> tt(deg_ + 1);
169  for (casadi_int d = 0; d <= deg_; ++d) {
170  tt[d] = t0 + h * tau_root[d];
171  }
172 
173  // Equations that implicitly define v
174  std::vector<MX> eq;
175 
176  // Quadratures
177  MX qf = MX::zeros(nq1_);
178 
179  // End state
180  MX xf = D[0] * x0;
181 
182  // For all collocation points
183  for (casadi_int j = 1; j < deg_ + 1; ++j) {
184 
185  // Evaluate the DAE
186  std::vector<MX> f_arg(DYN_NUM_IN);
187  f_arg[DYN_T] = tt[j];
188  f_arg[DYN_P] = p;
189  f_arg[DYN_U] = u;
190  f_arg[DYN_X] = x[j];
191  f_arg[DYN_Z] = z[j];
192  std::vector<MX> f_res = f(f_arg);
193 
194  // Get an expression for the state derivative at the collocation point
195  MX xp_j = C[0][j] * x0;
196  for (casadi_int r = 1; r < deg_ + 1; ++r) {
197  xp_j += C[r][j] * x[r];
198  }
199 
200  // Add collocation equation
201  eq.push_back(vec(h * f_res[DYN_ODE] - xp_j));
202 
203  // Add the algebraic conditions
204  eq.push_back(vec(f_res[DYN_ALG]));
205 
206  // Add contribution to the final state
207  xf += D[j] * x[j];
208 
209  // Add contribution to quadratures
210  qf += (B[j] * h) * f_res[DYN_QUAD];
211  }
212 
213  // Form forward discrete time dynamics
214  std::vector<MX> F_in(STEP_NUM_IN);
215  F_in[STEP_T] = t0;
216  F_in[STEP_H] = h;
217  F_in[STEP_X0] = x0;
218  F_in[STEP_P] = p;
219  F_in[STEP_U] = u;
220  F_in[STEP_V0] = v;
221  std::vector<MX> F_out(STEP_NUM_OUT);
222  F_out[STEP_XF] = xf;
223  F_out[STEP_VF] = vertcat(eq);
224  F_out[STEP_QF] = qf;
225  Function F("implicit_step", F_in, F_out,
226  {"t", "h", "x0", "v0", "p", "u"}, {"xf", "vf", "qf"});
227  set_function(F, F.name(), true);
228  }
229 
230  void Collocation::reset(IntegratorMemory* mem, bool first_call) const {
231  auto m = static_cast<FixedStepMemory*>(mem);
232 
233  // Reset the base classes
234  ImplicitFixedStepIntegrator::reset(mem, first_call);
235 
236  if (first_call) {
237  // Initial guess for v (only non-augmented system part)
238  double* v = m->v;
239  for (casadi_int d = 0; d < deg_; ++d) {
240  casadi_copy(m->x, nx1_, v);
241  v += nx1_;
242  casadi_copy(m->z, nz1_, v);
243  v += nz1_;
244  }
245  }
246  }
247 
249  s.version("Collocation", 2);
250  s.unpack("Collocation::deg", deg_);
251  s.unpack("Collocation::collocation_scheme", collocation_scheme_);
252  }
253 
256  s.version("Collocation", 2);
257  s.pack("Collocation::deg", deg_);
258  s.pack("Collocation::collocation_scheme", collocation_scheme_);
259  }
260 
261 } // namespace casadi
Collocation(const std::string &name, const Function &dae, double t0, const std::vector< double > &tout)
Constructor.
Definition: collocation.cpp:49
void setup_step() override
Setup step functions.
Definition: collocation.cpp:94
MX algebraic_state_output(const MX &Z) const override
Definition: collocation.cpp:90
void reset(IntegratorMemory *mem, bool first_call) const override
Reset the forward solver at the start or after an event.
void init(const Dict &opts) override
Initialize stage.
Definition: collocation.cpp:68
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize into MX.
static Integrator * creator(const std::string &name, const Function &dae, double t0, const std::vector< double > &tout)
Create a new integrator.
Definition: collocation.hpp:65
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
std::string collocation_scheme_
static const std::string meta_doc
A documentation string.
~Collocation() override
Destructor.
Definition: collocation.cpp:54
MX algebraic_state_init(const MX &x0, const MX &z0) const override
Definition: collocation.cpp:86
static const Options options_
Options.
Definition: collocation.hpp:81
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
void reset(IntegratorMemory *mem, bool first_call) const override
Reset the forward solver at the start or after an event.
Function object.
Definition: function.hpp:60
const Sparsity & sparsity_in(casadi_int ind) const
Get sparsity of a given input.
Definition: function.cpp:1015
static MX sym(const std::string &name, casadi_int nrow=1, casadi_int ncol=1)
Create an nrow-by-ncol symbolic primitive.
static MX zeros(casadi_int nrow=1, casadi_int ncol=1)
Create a dense matrix or a matrix with specified sparsity with all entries zero.
void init(const Dict &opts) override
Initialize stage.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
static const Options options_
Options.
MX - Matrix expression.
Definition: mx.hpp:92
void set_function(const Function &fcn, const std::string &fname, bool jit=false)
std::vector< std::string > get_function() const override
Get list of dependency functions.
static void registerPlugin(const Plugin &plugin, bool needs_lock=true)
Register an integrator in the factory.
Helper class for differentiating and integrating polynomials.
Definition: polynomial.hpp:39
Polynomial anti_derivative() const
Create a new polynomial for the anti-derivative (primitive function)
Definition: polynomial.cpp:149
Polynomial derivative() const
Create a new polynomial for the derivative.
Definition: polynomial.cpp:141
Helper class for Serialization.
void version(const std::string &name, int v)
void pack(const Sparsity &e)
Serializes an object to the output stream.
Class representing a Slice.
Definition: slice.hpp:48
The casadi namespace.
Definition: archiver.cpp:28
void CASADI_INTEGRATOR_COLLOCATION_EXPORT casadi_load_integrator_collocation()
Definition: collocation.cpp:45
@ STEP_H
Step size.
@ STEP_T
Current time.
@ STEP_U
Controls.
@ STEP_X0
State vector.
@ STEP_P
Parameter.
@ STEP_NUM_IN
Number of arguments.
@ STEP_V0
Dependent variables.
@ STEP_XF
State vector at next time.
@ STEP_QF
Quadrature state contribution.
@ STEP_VF
Dependent variables at next time.
@ STEP_NUM_OUT
Number of arguments.
void casadi_copy(const T1 *x, casadi_int n, T1 *y)
COPY: y <-x.
@ DYN_NUM_IN
Definition: integrator.hpp:196
int CASADI_INTEGRATOR_COLLOCATION_EXPORT casadi_register_integrator_collocation(Integrator::Plugin *plugin)
Definition: collocation.cpp:34
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
std::vector< double > collocation_points(casadi_int order, const std::string &scheme)
Obtain collocation points of specific order and scheme.
Options metadata for a class.
Definition: options.hpp:40