fmu_impl.hpp
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 #ifndef CASADI_FMU_IMPL_HPP
26 #define CASADI_FMU_IMPL_HPP
27 
28 #include "fmu.hpp"
29 #include "importer.hpp"
30 #include "shared_object.hpp"
31 #include "resource.hpp"
32 
34 
35 namespace casadi {
36 
37 // Memory for event iteration
38 struct EventMemory {
39  bool discrete_states_need_update;
40  bool terminate_simulation;
41  bool nominals_of_continuous_states_changed;
42  bool values_of_continuous_states_changed;
43  bool next_event_time_defined;
44  double next_event_time;
45 };
46 
47 // Forward declarations
48 class DaeBuilderInternal;
49 class FmuFunction;
50 struct FmuMemory;
51 struct InputStruct;
52 
61 class CASADI_EXPORT FmuInternal : public SharedObjectInternal {
62  friend class Fmu;
63  public:
64  // Constructor
65  FmuInternal(const std::string& name,
66  const std::vector<std::string>& scheme_in, const std::vector<std::string>& scheme_out,
67  const std::map<std::string, std::vector<size_t>>& scheme, const std::vector<std::string>& aux);
68 
70  ~FmuInternal() override;
71 
72  // Initialize
73  virtual void init(const DaeBuilderInternal* dae);
74 
75  // Set C API functions
76  virtual void load_functions() = 0;
77 
78  // Enter initialization mode
79  virtual int enter_initialization_mode(void* instance) const = 0;
80 
81  // Exit initialization mode
82  virtual int exit_initialization_mode(void* instance) const = 0;
83 
84  // Enter continuous-time mode
85  virtual int enter_continuous_time_mode(void* instance) const = 0;
86 
87  // Update discrete states
88  virtual int update_discrete_states(void* instance, EventMemory* eventmem) const = 0;
89 
90  virtual int get_derivatives(void* instance, double* derivatives, size_t nx) const = 0;
91 
92  // Set current time
93  virtual int set_time(void* instance, double t) const = 0;
94 
95  // Set real values
96  virtual int set_real(void* instance, const unsigned int* vr, size_t n_vr,
97  const double* values, size_t n_values) const = 0;
98 
99  // Get/evaluate real values
100  virtual int get_real(void* instance, const unsigned int* vr, size_t n_vr,
101  double* values, size_t n_values, FmuMemory* m = nullptr) const = 0;
102 
103  // Forward mode AD
104  virtual int get_directional_derivative(void* instance, const unsigned int* vr_out, size_t n_out,
105  const unsigned int* vr_in, size_t n_in, const double* seed, size_t n_seed,
106  double* sensitivity, size_t n_sensitivity) const = 0;
107 
108  // Reverse mode AD
109  virtual int get_adjoint_derivative(void* instance, const unsigned int* vr_out, size_t n_out,
110  const unsigned int* vr_in, size_t n_in, const double* seed, size_t n_seed,
111  double* sensitivity, size_t n_sensitivity) const;
112 
113  // Copy values set in DaeBuilder to FMU
114  virtual int set_values(void* instance) const = 0;
115 
116  // Retrieve auxilliary variables from FMU
117  virtual int get_aux(void* instance) = 0;
118 
119  // Finalize
120  virtual void finalize();
121 
125  void disp(std::ostream& stream, bool more) const override;
126 
130  size_t n_in() const { return iind_.size();}
131 
135  size_t n_out() const { return oind_.size();}
136 
137  // Index lookup for input
138  size_t index_in(const std::string& n) const;
139 
140  // Index lookup for output
141  size_t index_out(const std::string& n) const;
142 
143  // Get Jacobian sparsity for a subset of inputs and outputs
144  Sparsity jac_sparsity(const std::vector<size_t>& osub, const std::vector<size_t>& isub) const;
145 
146  // Get Hessian sparsity for a subset of inputs
147  Sparsity hess_sparsity(const std::vector<size_t>& r, const std::vector<size_t>& c) const;
148 
150 
153  std::vector<double> all_nominal_in(size_t i) const;
154  std::vector<double> all_nominal_out(size_t i) const;
156 
157  // Print description of an input
158  std::string desc_in(FmuMemory* m, size_t id, bool more = true) const;
159 
160  // Name of system, per the FMI specification
161  virtual std::string system_infix() const = 0;
162 
163  // DLL suffix, per the FMI specification
164  static std::string dll_suffix();
165 
166  // Compile the C sources in the DaeBuilder::export_fmu map into a shared library;
167  // returns the map augmented with the amalgamation source and the compiled binary.
168  // opts: compiler, compiler_options, include_dirs.
169  static Dict compile_fmu(const std::string& name, const Dict& files, const Dict& opts);
170 
171  // Pack a {local_file -> archive path} map into a single .fmu at 'path', then remove
172  // the local files. Returns the .fmu path.
173  static std::string pack_fmu(const Dict& files, const std::string& path);
174 
175  // Load an FMI function
176  template<typename T>
177  T* load_function(const std::string& symname);
178 
179  // Iteration to update discrete states
180  int discrete_states_iter(void* instance) const;
181 
185  virtual int init_mem(FmuMemory* m) const;
186 
190  virtual FmuMemory* alloc_mem(const FmuFunction& f) const = 0;
191 
195  virtual void free_mem(void *mem) const = 0;
196 
197  // New memory object
198  virtual void* instantiate() const = 0;
199 
200  // Free FMU instance
201  virtual void free_instance(void* c) const = 0;
202 
203  // Set value
204  void set(FmuMemory* m, size_t ind, const double* value) const;
205 
206  // Request the calculation of a variable
207  void request(FmuMemory* m, size_t ind) const;
208 
209  // Pass values to the FMU
210  int set_all(FmuMemory* m, const double* values, size_t n_values) const;
211 
212  // Get values from the FMU
213  int get_all(FmuMemory* m, double* values, size_t n_values) const;
214 
215  // Calculate all requested variables
216  int eval(FmuMemory* m) const;
217 
218  // Get a calculated variable
219  void get(FmuMemory* m, size_t id, double* value) const;
220 
221  // Set forward seeds
222  void set_fwd(FmuMemory* m, casadi_int nseed,
223  const casadi_int* id, const double* v) const;
224 
225  // Set all forward seeds for a single input
226  void set_fwd(FmuMemory* m, size_t ind, const double* v) const;
227 
228  // Request the calculation of forward sensitivities
229  void request_fwd(FmuMemory* m, casadi_int nsens, const casadi_int* id,
230  const casadi_int* wrt_id) const;
231 
232  // Request the calculation of all forward sensitivities for an output
233  void request_fwd(FmuMemory* m, casadi_int ind) const;
234 
235  // Calculate forward directional derivatives
236  int eval_fwd(FmuMemory* m, bool independent_seeds) const;
237 
238  // Calculate forward directional derivatives using AD
239  int eval_ad(FmuMemory* m) const;
240 
241  // Calculate forward directional derivatives using FD
242  int eval_fd(FmuMemory* m, bool independent_seeds) const;
243 
244  // Get forward sensitivities
245  void get_fwd(FmuMemory* m, casadi_int nsens,
246  const casadi_int* id, double* v) const;
247 
248  // Get the forward sensitivities for a single output
249  void get_fwd(FmuMemory* m, size_t ind, double* v) const;
250 
251  // Set adjoint seeds
252  void set_adj(FmuMemory* m, casadi_int nseed,
253  const casadi_int* id, const double* v) const;
254 
255  // Set all adjoint seeds for a single output
256  void set_adj(FmuMemory* m, size_t ind, const double* v) const;
257 
258  // Request the calculation of adjoint sensitivities
259  void request_adj(FmuMemory* m, casadi_int nsens, const casadi_int* id,
260  const casadi_int* wrt_id) const;
261 
262  // Request the calculation of all adjoint sensitivities for an input
263  void request_adj(FmuMemory* m, casadi_int ind) const;
264 
265  // Calculate adjoint sensitivities
266  int eval_adj(FmuMemory* m) const;
267 
268  // Get adjoint sensitivities
269  void get_adj(FmuMemory* m, casadi_int nsens,
270  const casadi_int* id, double* v) const;
271 
272  // Get the adjoint sensitivities for a single input
273  void get_adj(FmuMemory* m, size_t ind, double* v) const;
274 
275  // Gather forward sensitivities
276  void gather_fwd(FmuMemory* m) const;
277 
278  // Gather adjoint sensitivities
279  void gather_adj(FmuMemory* m) const;
280 
281  // Gather user inputs and outputs
282  void gather_io(FmuMemory* m) const;
283 
287  virtual void get_stats(FmuMemory* m, Dict* stats,
288  const std::vector<std::string>& name_in, const InputStruct* in) const = 0;
289 
290  void serialize(SerializingStream& s) const;
291 
292  virtual void serialize_type(SerializingStream& s) const;
293  virtual void serialize_body(SerializingStream& s) const;
294 
295  static FmuInternal* deserialize(DeserializingStream& s);
296 
297  protected:
298  explicit FmuInternal(DeserializingStream& s);
299 
300  // Resource holding unzipped data (notably DLL)
301  // Must come before li_, because of destructor order
302  Resource resource_;
303 
305  std::string name_;
306 
307  // IO scheme
308  std::vector<std::string> scheme_in_, scheme_out_;
309  std::map<std::string, std::vector<size_t>> scheme_;
310 
311  // Auxilliary outputs
312  std::vector<std::string> aux_;
313 
314  // Path to the FMU resource directory
315  std::string resource_loc_;
316 
317  // Tolerance
318  double fmutol_;
319 
320  // Instance name
321  std::string instance_name_;
322 
323  // GUID / instantiation_token
324  std::string instantiation_token_;
325 
326  // Logging?
327  bool logging_on_;
328 
329  // Number of event indicators
330  casadi_int number_of_event_indicators_;
331 
332  // Does the FMU declare analytic derivatives support?
333  bool provides_directional_derivatives_, provides_adjoint_derivatives_;
334 
335  // Does the FMU declare restrictions on instantiation?
336  bool can_be_instantiated_only_once_per_process_;
337 
338  // Start time
339  double start_time_;
340 
342  Importer li_;
343 
344  // Mapping from scheme variable to and from FMU variable indices
345  std::vector<size_t> iind_, iind_map_, oind_, oind_map_;
346 
347  // Is there an independent variable?
348  bool has_independent_;
349 
350  // Corresponding value reference
351  unsigned int independent_vr_;
352 
353  // Meta information about the input/output variable subsets
354  std::vector<double> nominal_in_, nominal_out_;
355  std::vector<double> min_in_, min_out_;
356  std::vector<double> max_in_, max_out_;
357  std::vector<std::string> vn_in_, vn_out_;
358  std::vector<unsigned int> vr_in_, vr_out_;
359 
360  // Numerical values for inputs
361  std::vector<double> value_in_;
362 
363  // Reduced space indices for all inputs and outputs
364  std::vector<std::vector<size_t>> ired_, ored_;
365 
366  // Sparsity pattern for extended Jacobian, Hessian
367  Sparsity jac_sp_, hess_sp_;
368 
369  mutable bool warning_fired_discrete_states_need_update_;
370  mutable bool warning_fired_terminate_simulation_;
371  mutable bool warning_fired_nominals_of_continuous_states_changed_;
372  mutable bool warning_fired_values_of_continuous_states_changed_;
373  mutable bool warning_fired_next_event_time_defined_;
374 
375  size_t nx_;
376  // Instead of set_real+get_real, do set_real+get_real+get_derivatives+get_real
377  bool do_evaluation_dance_;
378 };
379 
380 template<typename T>
381 T* FmuInternal::load_function(const std::string& symname) {
382  // Load the function
383  signal_t f = li_.get_function(symname);
384  // Ensure that it was found
385  casadi_assert(f != nullptr, "Cannot retrieve '" + symname + "'");
386  // Return function with the right type
387  return reinterpret_cast<T*>(f);
388 }
389 
390 } // namespace casadi
391 
393 
394 #endif // CASADI_FMU_IMPL_HPP
The casadi namespace.
Definition: archiver.hpp:32
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.