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  // Platform tuple (<arch>-<os>) per the FMI 3 specification, Section 2.5.1.4.1.
167  // Pure platform detection, so also available when compiled without WITH_FMI3
168  // (needed for FMU export, which always uses the FMI 3 binaries layout).
169  static std::string fmi3_dll_infix();
170 
171  // Compile the C sources in the DaeBuilder::export_fmu map into a shared library;
172  // returns the map augmented with the amalgamation source and the compiled binary.
173  // opts: compiler, compiler_options, include_dirs.
174  static Dict compile_fmu(const std::string& name, const Dict& files, const Dict& opts);
175 
176  // Pack a {local_file -> archive path} map into a single .fmu at 'path', then remove
177  // the local files. Returns the .fmu path.
178  static std::string pack_fmu(const Dict& files, const std::string& path);
179 
180  // Load an FMI function
181  template<typename T>
182  T* load_function(const std::string& symname);
183 
184  // Iteration to update discrete states
185  int discrete_states_iter(void* instance) const;
186 
190  virtual int init_mem(FmuMemory* m) const;
191 
195  virtual FmuMemory* alloc_mem(const FmuFunction& f) const = 0;
196 
200  virtual void free_mem(void *mem) const = 0;
201 
202  // New memory object
203  virtual void* instantiate() const = 0;
204 
205  // Free FMU instance
206  virtual void free_instance(void* c) const = 0;
207 
208  // Set value
209  void set(FmuMemory* m, size_t ind, const double* value) const;
210 
211  // Request the calculation of a variable
212  void request(FmuMemory* m, size_t ind) const;
213 
214  // Pass values to the FMU
215  int set_all(FmuMemory* m, const double* values, size_t n_values) const;
216 
217  // Get values from the FMU
218  int get_all(FmuMemory* m, double* values, size_t n_values) const;
219 
220  // Calculate all requested variables
221  int eval(FmuMemory* m) const;
222 
223  // Get a calculated variable
224  void get(FmuMemory* m, size_t id, double* value) const;
225 
226  // Set forward seeds
227  void set_fwd(FmuMemory* m, casadi_int nseed,
228  const casadi_int* id, const double* v) const;
229 
230  // Set all forward seeds for a single input
231  void set_fwd(FmuMemory* m, size_t ind, const double* v) const;
232 
233  // Request the calculation of forward sensitivities
234  void request_fwd(FmuMemory* m, casadi_int nsens, const casadi_int* id,
235  const casadi_int* wrt_id) const;
236 
237  // Request the calculation of all forward sensitivities for an output
238  void request_fwd(FmuMemory* m, casadi_int ind) const;
239 
240  // Calculate forward directional derivatives
241  int eval_fwd(FmuMemory* m, bool independent_seeds) const;
242 
243  // Calculate forward directional derivatives using AD
244  int eval_ad(FmuMemory* m) const;
245 
246  // Calculate forward directional derivatives using FD
247  int eval_fd(FmuMemory* m, bool independent_seeds) const;
248 
249  // Get forward sensitivities
250  void get_fwd(FmuMemory* m, casadi_int nsens,
251  const casadi_int* id, double* v) const;
252 
253  // Get the forward sensitivities for a single output
254  void get_fwd(FmuMemory* m, size_t ind, double* v) const;
255 
256  // Set adjoint seeds
257  void set_adj(FmuMemory* m, casadi_int nseed,
258  const casadi_int* id, const double* v) const;
259 
260  // Set all adjoint seeds for a single output
261  void set_adj(FmuMemory* m, size_t ind, const double* v) const;
262 
263  // Request the calculation of adjoint sensitivities
264  void request_adj(FmuMemory* m, casadi_int nsens, const casadi_int* id,
265  const casadi_int* wrt_id) const;
266 
267  // Request the calculation of all adjoint sensitivities for an input
268  void request_adj(FmuMemory* m, casadi_int ind) const;
269 
270  // Calculate adjoint sensitivities
271  int eval_adj(FmuMemory* m) const;
272 
273  // Get adjoint sensitivities
274  void get_adj(FmuMemory* m, casadi_int nsens,
275  const casadi_int* id, double* v) const;
276 
277  // Get the adjoint sensitivities for a single input
278  void get_adj(FmuMemory* m, size_t ind, double* v) const;
279 
280  // Gather forward sensitivities
281  void gather_fwd(FmuMemory* m) const;
282 
283  // Gather adjoint sensitivities
284  void gather_adj(FmuMemory* m) const;
285 
286  // Gather user inputs and outputs
287  void gather_io(FmuMemory* m) const;
288 
292  virtual void get_stats(FmuMemory* m, Dict* stats,
293  const std::vector<std::string>& name_in, const InputStruct* in) const = 0;
294 
295  void serialize(SerializingStream& s) const;
296 
297  virtual void serialize_type(SerializingStream& s) const;
298  virtual void serialize_body(SerializingStream& s) const;
299 
300  static FmuInternal* deserialize(DeserializingStream& s);
301 
302  protected:
303  explicit FmuInternal(DeserializingStream& s);
304 
305  // Resource holding unzipped data (notably DLL)
306  // Must come before li_, because of destructor order
307  Resource resource_;
308 
310  std::string name_;
311 
312  // IO scheme
313  std::vector<std::string> scheme_in_, scheme_out_;
314  std::map<std::string, std::vector<size_t>> scheme_;
315 
316  // Auxilliary outputs
317  std::vector<std::string> aux_;
318 
319  // Path to the FMU resource directory
320  std::string resource_loc_;
321 
322  // Tolerance
323  double fmutol_;
324 
325  // Instance name
326  std::string instance_name_;
327 
328  // GUID / instantiation_token
329  std::string instantiation_token_;
330 
331  // Logging?
332  bool logging_on_;
333 
334  // Number of event indicators
335  casadi_int number_of_event_indicators_;
336 
337  // Does the FMU declare analytic derivatives support?
338  bool provides_directional_derivatives_, provides_adjoint_derivatives_;
339 
340  // Does the FMU declare restrictions on instantiation?
341  bool can_be_instantiated_only_once_per_process_;
342 
343  // Start time
344  double start_time_;
345 
347  Importer li_;
348 
349  // Mapping from scheme variable to and from FMU variable indices
350  std::vector<size_t> iind_, iind_map_, oind_, oind_map_;
351 
352  // Is there an independent variable?
353  bool has_independent_;
354 
355  // Corresponding value reference
356  unsigned int independent_vr_;
357 
358  // Meta information about the input/output variable subsets
359  std::vector<double> nominal_in_, nominal_out_;
360  std::vector<double> min_in_, min_out_;
361  std::vector<double> max_in_, max_out_;
362  std::vector<std::string> vn_in_, vn_out_;
363  std::vector<unsigned int> vr_in_, vr_out_;
364 
365  // Numerical values for inputs
366  std::vector<double> value_in_;
367 
368  // Reduced space indices for all inputs and outputs
369  std::vector<std::vector<size_t>> ired_, ored_;
370 
371  // Sparsity pattern for extended Jacobian, Hessian
372  Sparsity jac_sp_, hess_sp_;
373 
374  mutable bool warning_fired_discrete_states_need_update_;
375  mutable bool warning_fired_terminate_simulation_;
376  mutable bool warning_fired_nominals_of_continuous_states_changed_;
377  mutable bool warning_fired_values_of_continuous_states_changed_;
378  mutable bool warning_fired_next_event_time_defined_;
379 
380  size_t nx_;
381  // Instead of set_real+get_real, do set_real+get_real+get_derivatives+get_real
382  bool do_evaluation_dance_;
383 };
384 
385 template<typename T>
386 T* FmuInternal::load_function(const std::string& symname) {
387  // Load the function
388  signal_t f = li_.get_function(symname);
389  // Ensure that it was found
390  casadi_assert(f != nullptr, "Cannot retrieve '" + symname + "'");
391  // Return function with the right type
392  return reinterpret_cast<T*>(f);
393 }
394 
395 } // namespace casadi
396 
398 
399 #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.