mbs_dirdyn.py 53.5 KB
Newer Older
1
2
# -*- coding: utf-8 -*-
"""
3
Module to handle direct dynamics simulations on Multibody systems.
4

5
6
7
8
9
10
Summary
-------
Define the class MbsDirdyn based on the MbsDirdyn structure of MBsysC. This
class has the functions required to manipulate the direct dynamic module. This
includes setting the options, running an(or multiple) analysis and freeing the
memory.
11
"""
12
13
14
# MBsysC version: 1.13.0
# Author: Robotran Team
# (c) Universite catholique de Louvain, 2019
15
16
17

import os
import imp
18
import ctypes
19
20
21

import numpy as np

22
23
24
25
26
# importing MbsysPy functions
from ..mbs_utilities import bytes_to_str
from ..mbs_utilities import str_to_bytes
from ..mbs_utilities import mbs_warning
from ..mbs_utilities import mbs_error
27
28

# importing libraries
29
from .._mbsysc_loader.loadlibs import libmodules
30

31
32
33
# importing utilities function
from ..mbs_utilities import callback_undefined

Louis Beauloye's avatar
Louis Beauloye committed
34
35
36
37
38
39
40
# importing function handler
from .._mbs_function_handler import assign_user_fct_to_None
from .._mbs_function_handler import assign_symb_fct_to_None
from .._mbs_function_handler import __unassign_user_fct_2__
from .._mbs_function_handler import __unassign_symb_fct_2__
from .._mbs_function_handler import __assign_user_to_undefined__
from .._mbs_function_handler import __assign_symb_to_undefined__
Louis Beauloye's avatar
Louis Beauloye committed
41
42
from .._mbs_function_handler import __load_symbolic_fct_2__
from .._mbs_function_handler import __load_user_fct_2__
Louis Beauloye's avatar
Louis Beauloye committed
43

44
# importing wrapping function
45
46
47
48
49
50
51
52
53
from .._mbsysc_loader.callback import user_cons_hJ_wrap
from .._mbsysc_loader.callback import user_cons_jdqd_wrap
from .._mbsysc_loader.callback import user_dirdyn_init_wrap
from .._mbsysc_loader.callback import user_dirdyn_loop_wrap
from .._mbsysc_loader.callback import user_dirdyn_finish_wrap

from .._mbsysc_loader.callback import mbs_cons_hJ_wrap
from .._mbsysc_loader.callback import mbs_cons_jdqd_wrap
from .._mbsysc_loader.callback import mbs_dirdyna_wrap
54
55


56
# =============================================================================
57
# Global parameter of the current module
58
# =============================================================================
59
__DEBUG__ = False
60
61
62
__MODULE_DIR__ = os.path.dirname(os.path.abspath(__file__))


63
# =============================================================================
64
# Defining Python MbsDirdyn class
65
# =============================================================================
66
67

class MbsDirdyn(object):
68
    """
69
70
    Class of the direct dynamic module.

71
72
    Attributes
    ----------
73
    dt: double
74
        Current integration step size.
75
    mbs: MbsData
76
        Instance of MbsData related to the analysis.
77
    results: MbsResult
78
        Instance of MbsResult containing the results of the direct dynamics analysis.
79
80
    symbolic_path: str
        Path to the folder containing the symbolic functions(python modules)
81
        to be loaded.
82
    tsim: double
83
        Current simulation time.
84
85
86
    user_path: str
        Path to the folder containing the user functions(python modules) to be loaded.

87
88
89
90
91
92
    Examples
    --------
    >>> mbs_data = MBsysPy.MbsData("../dataR/ExampleProject.mbs")
    >>> mbs_dirdyn = MBsysPy.MbsDirdyn(mbs_data)
    >>> mbs_dirdyn.set_options(t0 = 5, tf = 10)
    >>> mbs_dirdyn.get_options("t0", "tf")
93
    (5.0, 10.0)
94
    >>> results = mbs_dirdyn.run()
95

96
    """
97

98
    def __init__(self, mbs, user_path=None, symbolic_path=None):
99
100
101
102
103
        """
        Create an instance of the MbsDirdyn class for the provided MbsData instance.

        Parameters
        ----------
104
        mbs: MbsData
105
            Instance of MbsData related to the analysis.
106
107
108
        user_path: str or None, optionnal
            The path to the folder containing the user functions. If not provided
           ('None') the path is retrieved from the MbsData instance 'mbs'.
109
            default is None
110
111
112
        symbolic_path: str or None, optionnal
            The path to the folder containing the symbolic functions. If not
            provided('None') the path is retrieved from the MbsData instance 'mbs'.
113
            default is None
114

115
116
        Returns
        -------
117
        MbsDirdyn: self
118
119
            A MbsDirdyn instance.
        """
120
121
122
        if __DEBUG__:
            print("DEBUG>>  Creating MbsDirdyn struct for " + mbs.mbs_name + "' MBS.")

123
        self.mbs_dirdyn_ptr = libmodules.mbs_new_dirdyn(mbs.mbs_data_ptr)
124
125
126
        if __DEBUG__:
            print("DEBUG>>  MbsDirdyn structure loaded")

127
128
        self.mbs = mbs

129
130
131
        if __DEBUG__:
            print("DEBUG>>  MbsDirdyn created.")

132
        # Path to user function used by partitionning module
133
        self.user_path = self.mbs.user_path
134
135
        if user_path is not None:
            project_path = bytes_to_str(self.mbs.project_path)
136
137
138
            user_path = os.path.join(project_path, user_path)
            # Error handeling
            if not os.path.isdir(user_path):
139
140
141
                print('The user function directory for direct dynamic module does not exist: "' + user_path + '"')
                print('The current root folder is: "' + os.getcwd() + '"')
                print('The following directory is used instead: "' + self.user_path + '".')
142
143
144
145
            else:
                self.user_path = user_path
        # Path to user function used by partitionning modue
        self.symbolic_path = self.mbs.symbolic_path
146
        if symbolic_path is not None:
147
            project_path = bytes_to_str(self.mbs.project_path)
148
149
150
            symbolic_path = os.path.join(project_path, symbolic_path)
            # Error handeling
            if not os.path.isdir(symbolic_path):
Louis Beauloye's avatar
Louis Beauloye committed
151
                print('The symbolic function directory for direct dynamic module does not exist: "' + symbolic_path + '"')
152
153
                print('The current root folder is: "' + os.getcwd() + '"')
                print('The following directory is used instead: "' + self.symbolic_path + '".')
154
155
            else:
                self.symbolic_path = symbolic_path
156

157
        # dictionary containing the pointers to avoid garbage collecting
158
159
        self.ptrs_to_user_fcts = dict()
        self.ptrs_to_symb_fcts = dict()
160

161
        # Storing project function pointer
Louis Beauloye's avatar
Louis Beauloye committed
162
163
164
165
        self.user_fun_list = ['cons_hJ', 'cons_jdqd', 'derivative', 'DrivenJoints', 'ExtForces', 'JointForces',
                              'LinkForces', 'Link3DForces', 'dirdyn_init', 'dirdyn_loop', 'dirdyn_finish']
        self.symb_fun_list = ['accelred', 'cons_hJ', 'cons_jdqd', 'invdyna', 'dirdyna', 'extforces', 'gensensor',
                              'link', 'link3D', 'sensor']
Louis Beauloye's avatar
Louis Beauloye committed
166
        assign_user_fct_to_None(self, self.user_fun_list)
Louis Beauloye's avatar
Louis Beauloye committed
167
168
        if self.mbs.opt_load_c < 2:
            __assign_user_to_undefined__(self.mbs, self.user_fun_list)
Louis Beauloye's avatar
Louis Beauloye committed
169
        assign_symb_fct_to_None(self, self.symb_fun_list)
Louis Beauloye's avatar
Louis Beauloye committed
170
171
        if self.mbs.opt_load_c < 1:
            __assign_symb_to_undefined__(self.mbs, self.symb_fun_list)
Louis Beauloye's avatar
Louis Beauloye committed
172
173
174
175
176
177
178
179
180
        # self.user_cons_hJ = None
        # self.user_cons_jdqd = None
        # self.user_dirdyn_init = None
        # self.user_dirdyn_loop = None
        # self.user_dirdyn_finish = None
        # self.mbs_cons_hJ = None
        # self.mbs_cons_jdqd = None
        # self.mbs_invdyna = None
        # self.mbs_dirdyna = None
181

182
183
        # Storing Results
        self.results = MbsResult(self.mbs)
Louis Beauloye's avatar
Louis Beauloye committed
184
        self.store_results = True
185

186
        # Exposing some memory
187
188
189
        if __DEBUG__:
            print("DEBUG>>  Exposing MbsDirdyn fields.")

190
191
        # Constraints
        self._h = self._Jac = self._jdqd = None
192
193
194
195
        if self.mbs.Ncons > 0:
            self._h = np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.mbs_aux.contents.h, (self.mbs.Ncons + 1,))
            self._Jac = np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.mbs_aux.contents.Jac[0], (self.mbs.Ncons + 1, self.mbs.njoint + 1))
            self._jdqd = np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.mbs_aux.contents.jdqd, (self.mbs.Ncons + 1,))
196
        self._huserc = self._Juserc = self._jdqduserc = None
197
198
199
200
        if self.mbs.Nuserc > 0:
            self._huserc = np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.mbs_aux.contents.huserc, (self.mbs.Nuserc + 1,))
            self._Juserc = np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.mbs_aux.contents.Juserc[0], (self.mbs.Nuserc + 1, self.mbs.njoint + 1))
            self._jdqduserc = np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.mbs_aux.contents.jdqduserc, (self.mbs.Nuserc + 1,))
201
        # Fields from equation of motion
202
203
204
205
        self._M = np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.mbs_aux.contents.M[0], (self.mbs.njoint + 1, self.mbs.njoint + 1))
        self._c = np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.mbs_aux.contents.c, (self.mbs.njoint + 1,))
        self._F = np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.mbs_aux.contents.F, (self.mbs.njoint + 1,))

206
        # Loading user function
207
        if self.mbs.opt_load_c < 2:
208
209
210
            if __DEBUG__:
                print("DEBUG>>  Loading user functions")

211
            self.__load_user_fct__(self.user_path)
212
        # Loading symbolic function
213
        if self.mbs.opt_load_c < 1:
214
215
216
            if __DEBUG__:
                print("DEBUG>>  Loading symbolic functions")

217
            self.__load_symbolic_fct__(self.symbolic_path)
218
219

    def __str__(self):
220
221
222
223
        """Return str(self)."""
        if __DEBUG__:
            print("DEBUG>>  start of __str")

224
        return "MbsDirdyn instance has nothing to be printed from C library!"
225

226
    def __load_user_fct__(self, user_path):
227
        """
228
        Load user function where some args depend on MbsDirdyn module.
229
230
231
232

        Load the user functions in which some of the arguments are
        dependent of MbsDirdyn module instance. The functions will be
        assigned to the MbsData instance when the 'run' functions is called
233
        and unassigned at the end.
234
235
236
237
238
239
240

        The loader user functions are:
         - user_cons_hJ(from user_cons_hJ.py)
         - user_cons_jdqd(from user_cons_jdqd.py)
         - user_dirdyn_init(from user_dirdyn.py)
         - user_dirdyn_loop(from user_dirdyn.py)
         - user_dirdyn_finish(from user_dirdyn.py)
241
242
243

        Parameters
        ----------
244
        user_path: str
245
            The path to the folder containing the user functions.
246
        """
Louis Beauloye's avatar
Louis Beauloye committed
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
        __load_user_fct_2__(self.mbs, __MODULE_DIR__, self.user_fun_list, user_path)
        # template_path = os.path.join(__MODULE_DIR__, '../templates/user')

        # # cons_hJ
        # user_file = "user_cons_hJ.py"
        # path = os.path.abspath(os.path.join(user_path, user_file))
        # if not os.path.isfile(path):
        #     if __DEBUG__:
        #         print("DEBUG>>  file '" + user_file + "' not found in folder '" + os.path.dirname(path))

        #     path = os.path.abspath(os.path.join(template_path, user_file))
        # module = imp.load_source(user_file[:-3], path)
        # self.user_cons_hJ = module.user_cons_hJ

        # # cons_jdqd
        # user_file = "user_cons_jdqd.py"
        # path = os.path.abspath(os.path.join(user_path, user_file))
        # if not os.path.isfile(path):
        #     if __DEBUG__:
        #         print("DEBUG>>  file '" + user_file + "' not found in folder '" + os.path.dirname(path))

        #     path = os.path.abspath(os.path.join(template_path, user_file))
        # module = imp.load_source(user_file[:-3], path)
        # self.user_cons_jdqd = module.user_cons_jdqd

        # # user_dirdyn
        # user_file = "user_dirdyn.py"
        # path = os.path.abspath(os.path.join(user_path, user_file))
        # if not os.path.isfile(path):
        #     print("file '" + user_file + "' not found in folder '" + os.path.dirname(path))
        #     path = os.path.abspath(os.path.join(template_path, user_file))
        # else:
        #     if __DEBUG__:
        #         print("DEBUG>>  loading file '" + user_file + "' in folder '" + os.path.dirname(path))

        # module = imp.load_source(user_file[:-3], path)
        # self.user_dirdyn_init = module.user_dirdyn_init
        # self.user_dirdyn_loop = module.user_dirdyn_loop
        # self.user_dirdyn_finish = module.user_dirdyn_finish
286
        return
287

288
    def __load_symbolic_fct__(self, symbolic_path):
289
        """
290
        Load symbolic function where some args depend on MbsDirdyn module.
291
292
293
294

        Load the symb functions in which some of the arguments are
        dependent of MbsDirdyn module instance. The functions will be
        assigned to the MbsData instance when the 'run' functions is called
295
        and unassigned at the end.
296
297
298
299
300
301

        The loader user functions are:
         - cons_hJ(from mbs_cons_hJ_MBSNAME.py)
         - cons_jdqd(from mbs_cons_jdqd_MBSNAME.py)
         - dirdyna(from mbs_dirdyna_MBSNAME.py)
         - invdyna(from mbs_invdyna_MBSNAME.py)
302
303
304

        Parameters
        ----------
305
        symbolic_path: str
306
            The path to the folder containing the symbolic functions.
307
        """
Louis Beauloye's avatar
Louis Beauloye committed
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
        __load_symbolic_fct_2__(self.mbs, __MODULE_DIR__, self.symb_fun_list, symbolic_path)

        # mbs_name = self.mbs.mbs_name
        # template_path = os.path.join(__MODULE_DIR__, '../templates/symbolic')
        # # mbs_cons_hJ
        # symb_file = "mbs_cons_hJ_" + mbs_name + ".py"
        # path = os.path.abspath(os.path.join(symbolic_path, symb_file))
        # if not os.path.isfile(path):
        #     if __DEBUG__:
        #         print("DEBUG>>  file '" + symb_file + "' not found in folder '" + os.path.dirname(path))

        #     symb_file = "mbs_cons_hJ_PRJ.py"
        #     path = os.path.abspath(os.path.join(template_path, symb_file))
        # module = imp.load_source(symb_file[:-3], path)
        # self.mbs_cons_hJ = module.cons_hJ

        # # mbs_cons_jdqd
        # symb_file = "mbs_cons_jdqd_" + mbs_name + ".py"
        # path = os.path.abspath(os.path.join(symbolic_path, symb_file))
        # if not os.path.isfile(path):
        #     if __DEBUG__:
        #         print("DEBUG>>  file '" + symb_file + "' not found in folder '" + os.path.dirname(path))

        #     symb_file = "mbs_cons_jdqd_PRJ.py"
        #     path = os.path.abspath(os.path.join(template_path, symb_file))
        # module = imp.load_source(symb_file[:-3], path)
        # self.mbs_cons_jdqd = module.cons_jdqd

        # # dirdyna
        # symb_file = "mbs_dirdyna_" + mbs_name + ".py"
        # path = os.path.abspath(os.path.join(symbolic_path, symb_file))
        # if not os.path.isfile(path):
        #     if __DEBUG__:
        #         print("DEBUG>>  file '" + symb_file + "' not found in folder '" + os.path.dirname(path))

        #     symb_file = "mbs_dirdyna_PRJ.py"
        #     path = os.path.abspath(os.path.join(template_path, symb_file))
        # module = imp.load_source(symb_file[:-3], path)
        # self.mbs_dirdyna = module.dirdyna
347

348
        return
349

350
    def __assign_user_fct__(self):
351
352
353
354
355
356
        """
        Assign all user functions if some args are in MbsDirdyn instance.

        Assign and wrap python user function where some args depend on MbsDirdyn
        module. Store the functions in the MbsData instance and assign the
        pointer of functions in the C structure.
357
358
        """
        # cons_hJ
359
        self.ptrs_to_user_fcts["user_cons_hJ"] = user_cons_hJ_wrap(lambda h, Jac, mbs, tsim: self.user_cons_hJ(self._huserc, self._Juserc, self.mbs, tsim))
360
        self.mbs.user_cons_hJ = self.user_cons_hJ
361
        self.mbs.mbs_data_ptr.contents.user_cons_hJ = self.ptrs_to_user_fcts["user_cons_hJ"]
362

363
        # cons_jdqd
364
        self.ptrs_to_user_fcts["user_cons_jdqd"] = user_cons_jdqd_wrap(lambda jdqd, mbs, tsim: self.user_cons_jdqd(self._jdqduserc, self.mbs))
365
        self.mbs.user_cons_jdqd = self.user_cons_jdqd
366
        self.mbs.mbs_data_ptr.contents.user_cons_jdqd = self.ptrs_to_user_fcts["user_cons_jdqd"]
367
368

        # user_dirdyn
369
370
371
        self.ptrs_to_user_fcts["user_dirdyn_init"] = user_dirdyn_init_wrap(lambda mbs, dd: self.mbs.user_dirdyn_init(self.mbs, self))
        self.ptrs_to_user_fcts["user_dirdyn_loop"] = user_dirdyn_loop_wrap(lambda mbs, dd: self.mbs.user_dirdyn_loop(self.mbs, self))
        self.ptrs_to_user_fcts["user_dirdyn_finish"] = user_dirdyn_finish_wrap(lambda mbs, dd: self.mbs.user_dirdyn_finish(self.mbs, self))
372
        self.mbs.user_dirdyn_init = self.user_dirdyn_init
373
        self.mbs.mbs_data_ptr.contents.user_dirdyn_init = self.ptrs_to_user_fcts["user_dirdyn_init"]
374
        self.mbs.user_dirdyn_loop = self.user_dirdyn_loop
375
        self.mbs.mbs_data_ptr.contents.user_dirdyn_loop = self.ptrs_to_user_fcts["user_dirdyn_loop"]
376
        self.mbs.user_dirdyn_finish = self.user_dirdyn_finish
377
        self.mbs.mbs_data_ptr.contents.user_dirdyn_finish = self.ptrs_to_user_fcts["user_dirdyn_finish"]
Louis Beauloye's avatar
Louis Beauloye committed
378

379
        return
380

381
    def __assign_symbolic_fct__(self):
382
383
384
385
386
        """
        Assign all symbolic functions if some args are in MbsDirdyn instance.

        Assign and wrap python symbolic function where some args depend
        on MbsDirdyn module. Store the functions in the MbsData instance
387
        and assign the pointer of functions in the C structure
388
389
        """
        # mbs_cons_hJ
390
        self.ptrs_to_symb_fcts["mbs_cons_hJ"] = mbs_cons_hJ_wrap(lambda h, Jac, mbs, tsim: self.mbs_cons_hJ(self._h, self._Jac, self.mbs))
391
        self.mbs.mbs_cons_hJ = self.mbs_cons_hJ
392
        self.mbs.mbs_data_ptr.contents.mbs_cons_hJ = self.ptrs_to_symb_fcts["mbs_cons_hJ"]
393

394
        # mbs_cons_jdqd
395
        self.ptrs_to_symb_fcts["mbs_cons_jdqd"] = mbs_cons_jdqd_wrap(lambda jdqd, mbs, tsim: self.mbs_cons_jdqd(self._jdqd, self.mbs))
396
        self.mbs.mbs_cons_jdqd = self.mbs_cons_jdqd
397
        self.mbs.mbs_data_ptr.contents.mbs_cons_jdqd = self.ptrs_to_symb_fcts["mbs_cons_jdqd"]
398

399
        # dirdyna
400
        self.ptrs_to_symb_fcts["mbs_dirdyna"] = mbs_dirdyna_wrap(lambda M, c, mbs, tsim: self.mbs_dirdyna(self._M, self._c, self.mbs, tsim))
401
        self.mbs.mbs_dirdyna = self.mbs_dirdyna
402
        self.mbs.mbs_data_ptr.contents.mbs_dirdyna = self.ptrs_to_symb_fcts["mbs_dirdyna"]
403

404
        return
405
406

    # Callback function for function with advanced arguments
407
    def __callback_mbs_cons_hJ(self, fun, h, Jac):
408
409
410
411
412
413
414
        if __DEBUG__:
            print("DEBUG>>  callback_mbs_cons_hJ")

        __h = np.ctypeslib.as_array(h, (self.mbs.Ncons + 1,))
        __Jac = np.ctypeslib.as_array(Jac[0], (self.mbs.Ncons + 1, self.mbs.njoint + 1))
        fun(__h, __Jac, self.mbs)

415
    def __unassign_user_fct__(self):
416
        """Unassign user function where some args depend on MbsDirdyn module."""
417
        self.ptrs_to_user_fcts.clear()
418

Louis Beauloye's avatar
Louis Beauloye committed
419
420
421
422
423
424
425
426
427
428
429
        __unassign_user_fct_2__(self.mbs, self.user_fun_list)
        # self.mbs.user_cons_hJ = None
        # self.mbs.mbs_data_ptr.contents.user_cons_hJ = user_cons_hJ_wrap(lambda h, Jac, mbs, tsim: callback_undefined("user_cons_hJ"))
        # self.mbs.user_cons_jdqd = None
        # self.mbs.mbs_data_ptr.contents.user_cons_jdqd = user_cons_jdqd_wrap(lambda h, Jac, mbs, tsim: callback_undefined("user_cons_jdqd"))
        # self.mbs.user_dirdyn_init = None
        # self.mbs.mbs_data_ptr.contents.user_dirdyn_init = user_dirdyn_init_wrap(lambda mbs, dd: callback_undefined("user_dirdyn_init"))
        # self.mbs.user_dirdyn_loop = None
        # self.mbs.mbs_data_ptr.contents.user_dirdyn_loop = user_dirdyn_loop_wrap(lambda mbs, dd: callback_undefined("user_dirdyn_loop"))
        # self.mbs.user_dirdyn_finish = None
        # self.mbs.mbs_data_ptr.contents.user_dirdyn_finish = user_dirdyn_finish_wrap(lambda mbs, dd: callback_undefined("user_dirdyn_finish"))
430

431
    def __unassign_symbolic_fct__(self):
432
        """Unassign symbolic function where some args depend on MbsDirdyn module."""
433
        self.ptrs_to_symb_fcts.clear()
434

Louis Beauloye's avatar
Louis Beauloye committed
435
436
437
438
439
440
441
        __unassign_symb_fct_2__(self.mbs, self.symb_fun_list)
        # self.mbs.mbs_cons_hJ = None
        # self.mbs.mbs_data_ptr.contents.mbs_cons_hJ = mbs_cons_hJ_wrap(lambda h, Jac, mbs, tsim: callback_undefined("mbs_cons_hJ"))
        # self.mbs.mbs_cons_jdqd = None
        # self.mbs.mbs_data_ptr.contents.mbs_cons_jdqd = mbs_cons_jdqd_wrap(lambda jdqd, mbs, tsim: callback_undefined("mbs_cons_jdqd"))
        # self.mbs.mbs_dirdyna = None
        # self.mbs.mbs_data_ptr.contents.mbs_dirdyna = mbs_dirdyna_wrap(lambda M, c, mbs, tsim: callback_undefined("mbs_dirdyna"))
442

443
    def __del__(self):
444
        """Delete the object by freeing the C-related memory."""
445
        libmodules.mbs_delete_dirdyn(self.mbs_dirdyn_ptr, self.mbs.mbs_data_ptr)
446
447
448
        if __DEBUG__:
            print("DEBUG>>  MbsDirdyn pointer deleted.")

449
    def run(self):
Louis Beauloye's avatar
Louis Beauloye committed
450
        """
451
452
453
454
455
        Run a direct dynamics analysis.

        Options can be setted with the function 'set_options()' before calling
        this function. Options can be retrieved with the function 'get_options()'.

456
457
        Results are stored in the field 'results' if the options 'store_results'
        is set to True.
458

459
460
        Returns
        -------
461
        self.results: MbsResult
462
            The MbsResults containing the results of the analysis.
463
        """
464
        # Assing required user functions
465
466
467
        if self.mbs.opt_load_c < 2:
            self.__assign_user_fct__()
            self.mbs.__assign_user_fct__()
468

469
        # Assing required symbolic functions
470
471
472
        if self.mbs.opt_load_c < 1:
            self.__assign_symbolic_fct__()
            self.mbs.__assign_symb_fct__()
473
474

        if not self.store_results:
475
476
            libmodules.mbs_run_dirdyn(self.mbs_dirdyn_ptr, self.mbs.mbs_data_ptr)
        else:
477
478
479
            # Save2file forced to 1 because if buffers don't have the complete,
            # they are loaded from files
            self.set_options(save2file=1)
480
481
            libmodules.mbs_dirdyn_init(self.mbs_dirdyn_ptr, self.mbs.mbs_data_ptr)
            libmodules.mbs_dirdyn_loop(self.mbs_dirdyn_ptr, self.mbs.mbs_data_ptr)
482
483

            # Results(buffer) memory is kept BUT FILES WILL BE WRITTEN LATER
484
485
            if self.get_options("save2file"):
                size1 = self.mbs_dirdyn_ptr.contents.buffers[0].contents.index
486
487
                if size1 == 0:
                    size1 = self.mbs_dirdyn_ptr.contents.buffers[0].contents.size
488
489
490
491
                size2 = self.mbs_dirdyn_ptr.contents.buffers[0].contents.nx + 1

                # array are initialized to the time pointer so as to start index of joints at 1(we have to ensure contiguity between t and x in buffers ! ! !)
                self.results.q = np.copy(np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.buffers[0].contents.tx, (size1, size2)))
492
                # get time array from the q buffer
493
                self.results.t = self.results.q[:, 0]
494
495
                if not self.results.t[0] == self.get_options("t0"):
                    print("The beginning of the integration is not available in the buffer.\n The complete results have to be loaded from files.")
496
                    filename = bytes_to_str(ctypes.string_at(self.mbs_dirdyn_ptr.contents.buffers[0].contents.filename))
497
                    self.results.load_results_from_file(filename, module=6)
498
                # get qd and qdd buffer
499
500
501
502
                self.results.qd = np.copy(np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.buffers[1].contents.tx, (size1, size2)))
                self.results.qdd = np.copy(np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.buffers[2].contents.tx, (size1, size2)))
                size2 = self.mbs_dirdyn_ptr.contents.buffers[3].contents.nx + 1
                self.results.Qq = np.copy(np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.buffers[3].contents.tx, (size1, size2)))
503
                buffer_id = 4
504
                if self.mbs.Nux:
505
506
507
                    size2 = self.mbs_dirdyn_ptr.contents.buffers[buffer_id].contents.nx + 1
                    self.results.ux = np.copy(np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.buffers[buffer_id].contents.tx, (size1, size2)))
                    self.results.uxd = np.copy(np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.buffers[buffer_id + 1].contents.tx, (size1, size2)))
508
509
                    buffer_id = buffer_id + 2
                if self.mbs.Nlink:
510
511
512
513
                    size2 = self.mbs_dirdyn_ptr.contents.buffers[buffer_id].contents.nx + 1
                    self.results.Z = np.copy(np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.buffers[buffer_id].contents.tx, (size1, size2)))
                    self.results.Zd = np.copy(np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.buffers[buffer_id + 1].contents.tx, (size1, size2)))
                    self.results.Fl = np.copy(np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.buffers[buffer_id + 2].contents.tx, (size1, size2)))
514
515
                    buffer_id = buffer_id + 3
                if self.mbs.nqc:
516
517
                    size2 = self.mbs_dirdyn_ptr.contents.buffers[buffer_id].contents.nx + 1
                    self.results.Qc = np.copy(np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.buffers[buffer_id].contents.tx, (size1, size2)))
518
519
                    buffer_id = buffer_id + 1
                if self.mbs.nhu:
520
521
522
                    size2 = self.mbs_dirdyn_ptr.contents.buffers[buffer_id].contents.nx + 1
                    self.results.Lambda = np.copy(np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.buffers[buffer_id].contents.tx, (size1, size2)))

523
524
525
                if self.mbs_dirdyn_ptr.contents.user_buffer.contents.nx:
                    size = self.mbs_dirdyn_ptr.contents.user_buffer.contents.index
                    nbOutput = self.mbs_dirdyn_ptr.contents.user_buffer.contents.nx
526
                    for i in range(nbOutput):
527
                        user_out = np.copy(np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.user_buffer.contents.X[i], (1, size)))
528
                        name = bytes_to_str(self.mbs_dirdyn_ptr.contents.user_buffer.contents.names[i])
529
                        self.results.outputs[name] = user_out[0]
530

531
            libmodules.mbs_dirdyn_finish(self.mbs_dirdyn_ptr, self.mbs.mbs_data_ptr)
532

533
        # Anassign user functions
534
535
536
        if self.mbs.opt_load_c < 2:
            self.__unassign_user_fct__()
            self.mbs.__unassign_user_fct__()
537

538
        # Anassing required symbolic functions
539
540
541
        if self.mbs.opt_load_c < 1:
            self.__unassign_symbolic_fct__()
            self.mbs.__unassign_symb_fct__()
542

Louis Beauloye's avatar
Louis Beauloye committed
543
        return self.results
544

545
546
    def set_options(self, **kwargs):
        """
547
        Set the specified options for Dirdyn module.
548

549
550
        Parameters
        ----------
551
        t0: float
552
553
            Initial time of the simulation.
            default is 0.0
554
        tf: float
555
556
            Final time of the simulation
            default is 5.0
557
        dt0: float
558
            Initial value of the integration step size. For fixed-step integrator
559
           (ie. RK4, Euler explicit...) this is the time step for the whole simulation.
560
            default is 0.001
561
562
        save2file: int
            Determine whether results are written to files on disk(in resultsR folder):
563
             - 1: results are saved
564
             - 0: results are not saved
565
            default is 1
566
        resfilename: str
567
568
            The keyword used for determining the name of result files.
            default is 'dirdyn'
569
        respath: str
570
            Path in which result file are saved. This is the full path or the
571
            relative path. The folder must exist.
572
            default is the 'resultsR/' folder of the project
573
        animpath: str
574
            Path in which animation file is saved. This is the full path or the
575
            relative path. The folder must exist.
576
            default is the 'animationR/' folder of the project
577
578
        save_anim: int
            1 to save the animation file, if 'save2file' is set to 1. Set to 0
579
580
            to not save the animation file.
            default is 1
581
        save_visu: int
582
            Unused options as realtime is deactivated is MBsysPy.
583
            1 to save the visualizazion file(as it appears in 'user_realtime_visu.c'),
584
585
            if 'save2file' is set to 1. Set to O to not save the visualization.
            default is 0
586
        framerate: int
587
588
            number of frame per second for the animation file.
            default is 1000
589
        saveperiod: int
590
            The number of time steps between two buffer records.
591
592
            default is 1(every time step are recorded)
        max_save_user: int
593
594
            The maximal number of user variables saved.
            default is 12
595
596
        buffersize: int
            The number of time step that can be recorded in the buffer. Results
597
598
599
600
            are written to disk when the buffer is full. Writing to disk is slow.
            If set to -1, it computes the buffer size for saving results only once
            at the end according to dt0, t0 and tf.
            default is -1
601
        realtime: int
602
603
            Unused options as realtime is deactivated is MBsysPy.
            1 to activate to real-time features, 0 to deactivate them.
604
            default = 0
605
        accelred: int
606
607
            1 to use accelred, 0 otherwise.
            default is 0
608
        flag_compute_Qc: int
609
610
611
612
613
            If 1 it computes the forces/torques applied in each driven joints in
            order to follow the specified trajectory. Otherwhise the forces/torques
            are only computed in the joints specified in the option 'compute_Qc'.
            Setting the option to 0 speeds up the computation.
            default is 1
614
        compute_all_uxd: int
615
616
617
            If 1 the user derivative are computed during the analysis. Otherwhise
            If set to 0, they are not computed.
            default is 1
618
        compute_Qc: numpy.ndarray
619
            If option "flag_compute_Qc' is set to 0, the vector allows to select
620
            the(driven) joints on which the force/torque required to follow the
621
            trajectory will be computed.
622
            The shape of the array is '(mbs.njoint + 1)', for example with
623
624
625
            'compute_Qc = numpy.array([mbs.njoint 1 0 0 1 0])', we will compute
            Qc(1) and Qc(4) only, on a mbs made of 5 joints.
            compute_Qc[0] is always mbs.njoint
626
627
628
            default is an array full of zero(no forces computation)
        integrator: str
            Set integrator to use, available value:
629
             - "RK4": explicit Runge–Kutta method order 4
630
                      fixed stepsize
631
             - "Dopri5": explicit Runge–Kutta method of order(4)5
632
633
634
635
636
637
638
639
640
641
                         adaptative stepsize
             - "Rosenbrock": implicit fourth-order Rosenbrock
                             adaptative stepsize
                             for stiff problems
             - "EulerEx": Euler explicit method
                          fixed stepsize
             - "Eulaire": Modified Euler explicit method
                          fixed stepsize
             - "EulerIm": Euler implicit method
                          fixed stepsize
642
643
644
                          for stiff problems
             - "WMethods":  Implicit Euler extented to two stages
                            for stiff problems
645
646
             - "Bader": Semi-implicit midpoint rule method
                        adaptative stepsize
647
                        for stiff problems
648
            default is "RK4"
649
        verbose: int
650
651
652
            Set to 1 to get messages related to adaptive stepsize integrator. To
            disable message set to 0.
            default is 1
653
        flag_stop_stiff: int
654
655
656
            For adaptive stepsize integrator, set at 1 to stop integration if the
            systems become too stiff. Set it at 0 to continue integration.
            default is 0
657
        flag_precise_dynamics: int
658
659
            Flag to set which values are saved in the output files. This only
            changes the value save to the output files not the simulation results.
660
661

            If set at 1, the direct dynamics(constraint solving, computation of
662
            the generalized acceleration) will be done at the beginning of each
663
            time step of integration. The output files will be exact, but the
664
            computation will be a little slower.
665
            If set at 0, the output file will contains the value(constraint
666
667
668
669
670
            solution anf the generalized acceleration) of the last computation
            of the integrator. The values may be the one used for an internal step
            of the integrator, but the computation is a little faster.

            default is 1
671
        flag_waypoint: int
672
            If set to 1, the integrator will be forced to give a solution at the
673
            specified time interval('delta_t_wp'). If set to 0, the solution
674
675
            will be given at every computed time-step.
            default is 0
676
677
678
679
        flag_solout_wp: int
            Only used if 'flag_waypoint' is 1. In that case if set to 1, the
            integration results will only contains the value at the specified
            time interval('delta_t_wp'). Otherwhise the solution will contain
680
681
            all the timesteps and the waypoints.
            default is 0
682
683
        delta_t_wp: float
            Time interval between two waypoints [s], unused if 'flag_waypoint'
684
685
            is set to 0.
            default is 1.0e-3
686
        nmax: int
687
688
            maximal number of steps for adaptative stepsize integrators.
            default is 1e9
689
        toler: float
690
691
            mixed error tolerances for some adaptative stepsize integrators.
            default is 1.0e-3
692
        rtoler: float
693
694
            relative error tolerances for some adaptative stepsize integrators.
            default is 1.0e-3
695
        atoler: float
696
697
            absolute error tolerances for some adaptative stepsize integrators.
            default is 1.0e-6
698
        dt_max: float
699
700
            maximal time step [s] for some adaptative stepsize integrators.
            default is 1.0e-3
701
702
        n_freeze: int
            number of time step when the jacobian is freezed(computed once at
703
704
            the start of the n_freeze time steps) for implicit integrators.
            default is 0
705
706
        show_failed_closure: int
            If set to 1, an animation of the Newton-Raphson procedure is generated
707
708
            if the closure fails.
            default is 0
709
        store_results: boolean
710
711
            If set to 1, a copy of the results is done.
            default is 1
712
713
714
715
716
717
718
719
720
721
722
        """
        for key, value in kwargs.items():
            if key == "t0":
                self.mbs_dirdyn_ptr.contents.options.contents.t0 = value
            elif key == "tf":
                self.mbs_dirdyn_ptr.contents.options.contents.tf = value
            elif key == "dt0":
                self.mbs_dirdyn_ptr.contents.options.contents.dt0 = value
            elif key == "save2file":
                self.mbs_dirdyn_ptr.contents.options.contents.save2file = value
            elif key == "resfilename":
723
                self.mbs_dirdyn_ptr.contents.options.contents.resfilename = str_to_bytes(value)
724
            elif key == "respath":
725
                self.mbs_dirdyn_ptr.contents.options.contents.respath = str_to_bytes(value)
726
            elif key == "animpath":
727
                self.mbs_dirdyn_ptr.contents.options.contents.animpath = str_to_bytes(value)
728
729
730
731
732
733
734
            elif key == "save_anim":
                self.mbs_dirdyn_ptr.contents.options.contents.save_anim = value
            elif key == "save_visu":
                self.mbs_dirdyn_ptr.contents.options.contents.save_visu = value
            elif key == "framerate":
                self.mbs_dirdyn_ptr.contents.options.contents.framerate = value
            elif key == "saveperiod":
735
                self.mbs_dirdyn_ptr.contents.options.contents.saveperiod = value
736
737
738
739
740
            elif key == "max_save_user":
                self.mbs_dirdyn_ptr.contents.options.contents.max_save_user = value
            elif key == "buffersize":
                self.mbs_dirdyn_ptr.contents.options.contents.buffersize = value
            elif key == "realtime":
741
                if value != 0:
742
                    mbs_warning('Realtime option is not working with pre-compiled'
743
                                'libraries(as included in Pip package)!')
744
745
746
                    if self.mbs.opt_load_c < 2:
                        mbs_error('Realtime simulation requires to provide a C-compiled'
                                  'libraries of the user functions!')
747

748
749
750
751
752
                self.mbs_dirdyn_ptr.contents.options.contents.realtime = value
            elif key == "accelred":
                self.mbs_dirdyn_ptr.contents.options.contents.accelred = value
            elif key == "flag_compute_Qc":
                self.mbs_dirdyn_ptr.contents.options.contents.flag_compute_Qc = value
Louis Beauloye's avatar
Louis Beauloye committed
753
754
            elif key == "compute_all_uxd":
                self.mbs_dirdyn_ptr.contents.options.contents.compute_all_uxd = value
755
            elif key == "compute_Qc":
756
757
                if(type(value) is np.ndarray) or(type(value) is list):
                    if np.size(value) == self.mbs.mbs_data_ptr.contents.njoint + 1:
758
                        for i, val in enumerate(value[1:]):
759
                            self.mbs_dirdyn_ptr.contents.options.contents.compute_Qc[i + 1] = val
760
                    else:
761
                        print(">>DIRDYN>>  The size of compute_Qc is not consistent with njoint")
762
                else:
763
                    print(">>DIRDYN>>  The specified value for compute_Qc is not a list or a np.array")
764
            elif key == "integrator":
765
                if(type(value) is int) and(value >= 0 and value <= 8):
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
                    self.mbs_dirdyn_ptr.contents.options.contents.integrator = value
                elif type(value) is str:
                    if value == "RK4":
                        self.mbs_dirdyn_ptr.contents.options.contents.integrator = 0
                    elif value == "Dopri5":
                        self.mbs_dirdyn_ptr.contents.options.contents.integrator = 1
                    elif value == "Rosenbrock":
                        self.mbs_dirdyn_ptr.contents.options.contents.integrator = 2
                    elif value == "EulerEx":
                        self.mbs_dirdyn_ptr.contents.options.contents.integrator = 3
                    elif value == "Eulaire":
                        self.mbs_dirdyn_ptr.contents.options.contents.integrator = 4
                    elif value == "EulerIm":
                        self.mbs_dirdyn_ptr.contents.options.contents.integrator = 5
                    elif value == "Bader":
                        self.mbs_dirdyn_ptr.contents.options.contents.integrator = 6
                    elif value == "WMethods":
                        self.mbs_dirdyn_ptr.contents.options.contents.integrator = 7
                    elif value == "Custom":
                        self.mbs_dirdyn_ptr.contents.options.contents.integrator = 8
                    else:
                        print(">>DIRDYN>>  " + value + " is not an integrator")
                else:
                    print(">>DIRDYN>>  " + value + " is not an integrator")
            elif key == "verbose":
                self.mbs_dirdyn_ptr.contents.options.contents.verbose = value
            elif key == "flag_stop_stiff":
                self.mbs_dirdyn_ptr.contents.options.contents.flag_stop_stiff = value
            elif key == "flag_precise_dynamics":
                self.mbs_dirdyn_ptr.contents.options.contents.flag_precise_dynamics = value
            elif key == "flag_waypoint":
                self.mbs_dirdyn_ptr.contents.options.contents.flag_waypoint = value
            elif key == "flag_solout_wp":
799
                self.mbs_dirdyn_ptr.contents.options.contents.flag_solout_wp = value
800
801
802
803
804
805
806
807
808
809
810
811
812
813
            elif key == "delta_t_wp":
                self.mbs_dirdyn_ptr.contents.options.contents.delta_t_wp = value
            elif key == "nmax":
                self.mbs_dirdyn_ptr.contents.options.contents.nmax = value
            elif key == "toler":
                self.mbs_dirdyn_ptr.contents.options.contents.toler = value
            elif key == "rtoler":
                self.mbs_dirdyn_ptr.contents.options.contents.rtoler = value
            elif key == "atoler":
                self.mbs_dirdyn_ptr.contents.options.contents.atoler = value
            elif key == "dt_max":
                self.mbs_dirdyn_ptr.contents.options.contents.dt_max = value
            elif key == "n_freeze":
                self.mbs_dirdyn_ptr.contents.options.contents.n_freeze = value
Louis Beauloye's avatar
Louis Beauloye committed
814
815
            elif key == "show_failed_closure":
                self.mbs_dirdyn_ptr.contents.options.contents.show_failed_closure = value
Louis Beauloye's avatar
Louis Beauloye committed
816
817
            elif key == "store_results":
                self.store_results = value
818
            else:
819
820
                print(">>DIRDYN>>  The option " + key + " is not defined in this module")

821
822
    def get_options(self, *args):
        """
823
824
        Get the specified options for Dirdyn module.

825
826
        Parameters
        ----------
827
        The different options specifed in the documentation of 'set_options()'
828

829
830
        Returns
        -------
831
        The value of the different options specifed in the documentation of 'set_options()'
832
833
834
835
836
837
838
839
840
841
842
843
        """
        options = []
        for key in args:
            if key == "t0":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.t0)
            elif key == "tf":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.tf)
            elif key == "dt0":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.dt0)
            elif key == "save2file":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.save2file)
            elif key == "resfilename":
844
                options.append(bytes_to_str(ctypes.string_at(self.mbs_dirdyn_ptr.contents.options.contents.resfilename)))
845
            elif key == "respath":
846
                options.append(bytes_to_str(ctypes.string_at(self.mbs_dirdyn_ptr.contents.options.contents.respath)))
847
            elif key == "animpath":
848
                options.append(bytes_to_str(ctypes.string_at(self.mbs_dirdyn_ptr.contents.options.contents.animpath)))
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
            elif key == "save_anim":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.save_anim)
            elif key == "save_visu":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.save_visu)
            elif key == "framerate":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.framerate)
            elif key == "saveperiod":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.saveperiod)
            elif key == "max_save_user":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.max_save_user)
            elif key == "buffersize":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.buffersize)
            elif key == "realtime":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.realtime)
            elif key == "accelred":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.accelred)
            elif key == "flag_compute_Qc":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.flag_compute_Qc)
Louis Beauloye's avatar
Louis Beauloye committed
867
868
            elif key == "compute_all_uxd":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.compute_all_uxd)
869
            elif key == "compute_Qc":
870
                compute_Qc_py = np.ctypeslib.as_array(self.mbs_dirdyn_ptr.contents.options.contents.compute_Qc, (self.mbs.mbs_data_ptr.contents.njoint + 1,))
871
872
873
874
875
876
877
878
879
                options.append(compute_Qc_py)
            elif key == "integrator":
                if self.mbs_dirdyn_ptr.contents.options.contents.integrator == 0:
                    options.append("RK4")
                elif self.mbs_dirdyn_ptr.contents.options.contents.integrator == 1:
                    options.append("Dopri5")
                elif self.mbs_dirdyn_ptr.contents.options.contents.integrator == 2:
                    options.append("Rosenbrock")
                elif self.mbs_dirdyn_ptr.contents.options.contents.integrator == 3:
880
                    options.append("EulerEx")
881
                elif self.mbs_dirdyn_ptr.contents.options.contents.integrator == 4:
882
                    options.append("Eulaire")
883
                elif self.mbs_dirdyn_ptr.contents.options.contents.integrator == 5:
884
                    options.append("EulerIm")
885
886
887
                elif self.mbs_dirdyn_ptr.contents.options.contents.integrator == 6:
                    options.append("Bader")
                elif self.mbs_dirdyn_ptr.contents.options.contents.integrator == 7:
888
                    options.append("WMethods")
889
                elif self.mbs_dirdyn_ptr.contents.options.contents.integrator == 8:
890
                    options.append("Custom")
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
            elif key == "verbose":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.verbose)
            elif key == "flag_stop_stiff":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.flag_stop_stiff)
            elif key == "flag_precise_dynamics":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.flag_precise_dynamics)
            elif key == "flag_waypoint":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.flag_waypoint)
            elif key == "flag_solout_wp":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.flag_solout_wp)
            elif key == "delta_t_wp":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.delta_t_wp)
            elif key == "nmax":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.nmax)
            elif key == "toler":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.toler)
            elif key == "rtoler":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.rtoler)
            elif key == "atoler":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.atoler)
            elif key == "dt_max":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.dt_max)
            elif key == "n_freeze":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.n_freeze)
Louis Beauloye's avatar
Louis Beauloye committed
915
916
            elif key == "show_failed_closure":
                options.append(self.mbs_dirdyn_ptr.contents.options.contents.show_failed_closure)
Louis Beauloye's avatar
Louis Beauloye committed
917
918
            elif key == "store_results":
                options.append(self.store_results)
919
            else:
920
921
                print(">>DIRDYN>>  The option " + key + " is not defined in this module")