mbs_invdyn.py 26.7 KB
Newer Older
1
2
3
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
4
Module to handle inverse dynamic analysis on Multibody systems.
5

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

import os
import ctypes

import numpy as np

21
# importing MbsysPy functions
22
from ..mbs_utilities import str_from_c_pointer
23
24
from ..mbs_utilities import bytes_to_str
from ..mbs_utilities import str_to_bytes
Louis Beauloye's avatar
Louis Beauloye committed
25
from ..mbs_utilities import mbs_msg
26

27
28
29
30
# importing MbsysPy classes
from .mbs_dirdyn import MbsResult

# importing libraries
31
from .._mbsysc_loader.loadlibs import libmodules
32

33
# =============================================================================
34
# Global parameter of the current module
35
# =============================================================================
36
__DEBUG__ = False
37
38
39
__MODULE_DIR__ = os.path.dirname(os.path.abspath(__file__))


40
# =============================================================================
41
# Defining Python MbsInvdyn class
42
# =============================================================================
43
44

class MbsInvdyn(object):
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
    """
    Class of the invdyn computation module.

    Attributes
    ----------
    mbs: MbsData
        Instance of MbsData related to the analysis.
    results: MbsResult
        Instance of MbsResult containing the results of the direct dynamics analysis.
    symbolic_path: str
        Path to the folder containing the symbolic functions(python modules)
        to be loaded.
    user_path: str
        Path to the folder containing the user functions(python modules) to be loaded.
    """

61
    def __init__(self, mbs, user_path=None, symbolic_path=None):
62
        """
63
        Create an instance of the MbsInvdyn class for the provided MbsData instance.
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

        Parameters
        ----------
        mbs: MbsData
            Instance of MbsData related to the analysis.
        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'.
            default is None
        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'.
            default is None

        Returns
        -------
80
81
        MbsInvdyn: self
            A MbsInvdyn instance.
82
        """
83
        self.module_name = type(self).__name__
84
85

        if __DEBUG__:
Louis Beauloye's avatar
Louis Beauloye committed
86
            mbs_msg("DEBUG>>  Creating " + self.module_name + " struct for " + mbs.mbs_name + "' MBS.")
87

88
        self.mbs_invdyn_ptr = libmodules.mbs_new_invdyn(mbs.mbs_data_ptr)
89
        if __DEBUG__:
Louis Beauloye's avatar
Louis Beauloye committed
90
            mbs_msg("DEBUG>>  " + self.module_name + " structure loaded")
91

92
        self.mbs = mbs
93

94
        self.user_path = self.mbs.user_path
95
96
        if user_path is not None:
            project_path = bytes_to_str(self.mbs.project_path)
97
98
99
            user_path = os.path.join(project_path, user_path)
            # Error handeling
            if not os.path.isdir(user_path):
Louis Beauloye's avatar
Louis Beauloye committed
100
101
102
                mbs_msg('The user function directory for direct dynamic module does not exist: "' + user_path + '"')
                mbs_msg('The current root folder is: "' + os.getcwd() + '"')
                mbs_msg('The following directory is used instead: "' + self.user_path + '".')
103
104
105
106
            else:
                self.user_path = user_path
        # Path to user function used by partitionning modue
        self.symbolic_path = self.mbs.symbolic_path
107
108
        if symbolic_path is not None:
            project_path = bytes_to_str(self.mbs.project_path)
109
110
111
            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
112
113
114
                mbs_msg('Thesymbolic function directory for direct dynamic module does not exist: "' + symbolic_path + '"')
                mbs_msg('The current root folder is: "' + os.getcwd() + '"')
                mbs_msg('The following directory is used instead: "' + self.symbolic_path + '".')
115
116
            else:
                self.symbolic_path = symbolic_path
117

Louis Beauloye's avatar
Louis Beauloye committed
118
        self.user_fun_list = ['cons_hJ', 'cons_jdqd', 'derivative', 'DrivenJoints',
119
120
                              'ExtForces', 'JointForces', 'LinkForces', 'Link3DForces',
                              'invdyn_init', 'invdyn_loop', 'invdyn_finish'
Louis Beauloye's avatar
Louis Beauloye committed
121
122
123
124
125
                              ]
        self.symb_fun_list = ['accelred', 'cons_hJ', 'cons_jdqd', 'invdyna',
                              'dirdyna', 'extforces', 'gensensor',
                              'link', 'link3D', 'sensor'
                              ]
126

127
128
129
        # Storing Results
        self.results = MbsResult(self.mbs)
        self.store_results = True
130

131
        # Exposing some memory
132
        if __DEBUG__:
Louis Beauloye's avatar
Louis Beauloye committed
133
            mbs_msg("DEBUG>>  Exposing " + self.module_name + " fields")
134

135
136
        # Constraints
        self._h = self._Jac = self._jdqd = None
137
138
139
140
        if self.mbs.Ncons > 0:
            self._h = np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.mbs_aux.contents.h, (self.mbs.Ncons + 1, ))
            self._Jac = np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.mbs_aux.contents.Jac[0], (self.mbs.Ncons + 1, self.mbs.njoint + 1))
            self._jdqd = np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.mbs_aux.contents.jdqd, (self.mbs.Ncons + 1, ))
141
        self._huserc = self._Juserc = self._jdqduserc = None
142
143
144
145
        if self.mbs.Nuserc > 0:
            self._huserc = np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.mbs_aux.contents.huserc, (self.mbs.Nuserc + 1, ))
            self._Juserc = np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.mbs_aux.contents.Juserc[0], (self.mbs.Nuserc + 1, self.mbs.njoint + 1))
            self._jdqduserc = np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.mbs_aux.contents.jdqduserc, (self.mbs.Nuserc + 1, ))
146
        # Fields from equation of motion
147
148
149
150
151
        self._M = np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.mbs_aux.contents.M[0], (self.mbs.njoint + 1, self.mbs.njoint + 1))
        self._c = np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.mbs_aux.contents.c, (self.mbs.njoint + 1, ))
        self._F = np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.mbs_aux.contents.F, (self.mbs.njoint + 1, ))
        self._phi = np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.mbs_aux.contents.phi, (self.mbs.njoint + 1, ))

152
    def __str__(self):
153
154
        """Return str(self)."""
        if __DEBUG__:
Louis Beauloye's avatar
Louis Beauloye committed
155
            mbs_msg("DEBUG>>  start of __str")
156
157
158
159
160

        msg = 'MbsInvdyn instance of the project "' + str(self.mbs_name) +\
              '", loaded from the file "' + str(self.mbs_filename) + '".'
        return msg

161
    def __del__(self):
162
        """Delete the object by freeing the C-related memory."""
163
        libmodules.mbs_delete_invdyn(self.mbs_invdyn_ptr, self.mbs.mbs_data_ptr)
164
165
        if __DEBUG__:
            mbs_msg("DEBUG>>  " + self.module_name + " pointer deleted")
166

167
    def run(self, **kwargs):
168
        """
169
170
171
172
        Run an inverse dynamics analysis.

        Options can be setted with set_options.
        Options can be retrieved with get_options
173

174
        Results are stored in the field results(if store_results == True)
175

176
177
178
179
        Returns
        -------
        self.results: MbsResult
            The MbsResults containing the results of the analysis.
180
        """
181
        # Assign required user functions
182
        if self.mbs.opt_load_c < 2:
183
            if __DEBUG__:
Louis Beauloye's avatar
Louis Beauloye committed
184
                mbs_msg("DEBUG>>  Loading user functions")
185

186
            self.mbs.__load_user_fct__(__MODULE_DIR__, self.user_fun_list, self.user_path)
187
            self.mbs.__assign_user_fct__(self.user_fun_list, self)
188

189
        # Assign required symbolic functions
190
        if self.mbs.opt_load_c < 1:
191
192
            # Loading symbolic function
            if __DEBUG__:
Louis Beauloye's avatar
Louis Beauloye committed
193
                mbs_msg("DEBUG>>  Loading symbolic functions")
194
195

            self.mbs.__load_symbolic_fct__(__MODULE_DIR__, self.symb_fun_list, self.symbolic_path)
196
            self.mbs.__assign_symb_fct__(self.symb_fun_list, self)
197

198
199
        self.set_options(**kwargs)

200
        if not self.store_results:
201
202
            error = libmodules.mbs_run_invdyn(self.mbs_invdyn_ptr, self.mbs.mbs_data_ptr)
            error2 = 0  # Unused for this module
203
        else:
204
205
            # save2file forced to 1 because if buffers don't have the complete
            # results, results are loaded from files.
206
            self.set_options(save2file=1)
207
208
209
            error = libmodules.mbs_invdyn_init(self.mbs_invdyn_ptr, self.mbs.mbs_data_ptr)
            if (error >= 0):
                error = libmodules.mbs_invdyn_loop(self.mbs_invdyn_ptr, self.mbs.mbs_data_ptr)
210
211

            # Results(buffer) memory is kept BUT FILES WILL BE WRITTEN LATER
212
            if error >= 0 and self.get_options("save2file"):
213
                self._load_results()
214

215
216
            # finish function is required to close the module and write the results to disk.
            error2 = libmodules.mbs_invdyn_finish(self.mbs_invdyn_ptr, self.mbs.mbs_data_ptr)
217

218
        # Unassign user functions
219
        if self.mbs.opt_load_c < 2:
220
            self.mbs.__unassign_user_fct__(self.user_fun_list)
221

222
        # Unassing required symbolic functions
223
        if self.mbs.opt_load_c < 1:
224
            self.mbs.__unassign_symb_fct__(self.symb_fun_list)
225

226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
        if error < 0 or error2 < 0:
            mbs_msg("\n--------------------------------------------------------------------------------\n"
                    "READ CAREFULLY !!!\n"
                    "--------------------------------------------------------------------------------\n\n"
                    "An error occurs during inverse dynamic module.\n"
                    "The messages above give deeper informations on what went wrong.\n"
                    "The messages below gives classic error and error backtrace.\n\n"

                    "Usual errors are:\n"
                    "    - Incompatible module options;\n"
                    "    - Invalid path to trajectory files;\n"
                    "    - Invalid trajectory files contents;\n"
                    "    - The motion reach an singular configuration;\n"
                    "\n"
                    "If the simulation runs a little you should:\n"
                    "    - Open the results files and check the values obtained before failure.\n"
                    "\n--------------------------------------------------\n"
                    "\n--------------------------------------------------\n")
            raise RuntimeError("MbsInvdyn.run() failed, read previous messages.")

246
        return self.results
247

248
249
    def _load_results(self):
        """
250
        Load the results from the buffers.
251

252
253
        If the beginning of the integration is not available in the buffers,
        the complete results are loaded from files
254
        """
255
        # c_mbs_invdyn_write_buffers(self.mbs_invdyn_ptr)
256
257
258
        size1 = self.mbs_invdyn_ptr.contents.buffers[0].contents.index
        if size1 == 0:
            size1 = self.mbs_invdyn_ptr.contents.buffers[0].contents.size
259
260
261
        size2 = self.mbs_invdyn_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 ! ! !)
262
        self.results.q = np.copy(np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.buffers[0].contents.tx, (size1, size2)))
263
        # get time array from the q buffer
264
        self.results.t = self.results.q[:, 0]
265
        if not self.results.t[0] == self.get_options("t0"):
Louis Beauloye's avatar
Louis Beauloye committed
266
            mbs_msg("The beginning of the integration is not available in the buffer.\n The complete results have to be loaded from files.")
267
            filename = bytes_to_str(ctypes.string_at(self.mbs_invdyn_ptr.contents.buffers[0].contents.filename))
268
            self.results.load_results_from_file(filename, module=6)
269
        # get qd and qdd buffer
270
271
        self.results.qd = np.copy(np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.buffers[1].contents.tx, (size1, size2)))
        self.results.qdd = np.copy(np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.buffers[2].contents.tx, (size1, size2)))
272
        size2 = self.mbs_invdyn_ptr.contents.buffers[3].contents.nx + 1
273
        self.results.Qq = np.copy(np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.buffers[3].contents.tx, (size1, size2)))
274
        if self.module_name == "MbsInvdyn":
275
            size2 = self.mbs_invdyn_ptr.contents.buffers[4].contents.nx + 1
276
            self.results.Qa = np.copy(np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.buffers[4].contents.tx, (size1, size2)))
277
278
279
280
            buffer_id = 5
        else:
            buffer_id = 4
        if self.mbs.Nlink:
281
            size2 = self.mbs_invdyn_ptr.contents.buffers[buffer_id].contents.nx + 1
282
283
284
            self.results.Z = np.copy(np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.buffers[buffer_id].contents.tx, (size1, size2)))
            self.results.Zd = np.copy(np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.buffers[buffer_id + 1].contents.tx, (size1, size2)))
            self.results.Fl = np.copy(np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.buffers[buffer_id + 2].contents.tx, (size1, size2)))
285
286
            buffer_id = buffer_id + 3
        if self.mbs.nqc:
287
            size2 = self.mbs_invdyn_ptr.contents.buffers[buffer_id].contents.nx + 1
288
            self.results.Qc = np.copy(np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.buffers[buffer_id].contents.tx, (size1, size2)))
289
290
            buffer_id = buffer_id + 1
        if self.mbs.nhu:
291
            size2 = self.mbs_invdyn_ptr.contents.buffers[buffer_id].contents.nx + 1
292
            self.results.Lambda = np.copy(np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.buffers[buffer_id].contents.tx, (size1, size2)))
293

294
295
296
        if self.mbs_invdyn_ptr.contents.user_buffer.contents.nx:
            size = self.mbs_invdyn_ptr.contents.user_buffer.contents.index
            nbOutput = self.mbs_invdyn_ptr.contents.user_buffer.contents.nx
297
            user_out = np.copy(np.ctypeslib.as_array(self.mbs_invdyn_ptr.contents.user_buffer.contents.X[0], (nbOutput, size)))
298
            for i in range(nbOutput):
299
                name = bytes_to_str(self.mbs_invdyn_ptr.contents.user_buffer.contents.names[i])
300
301
                self.results.outputs[name] = user_out[i, :]

302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
    def set_user_fct_from_file(self, function_name, user_path, user_file):
        """
        Load a user function from a file chosen by the user instead of the default one in the userfctR folder.

        The function is then unassigned by the module at the end of the run().

        Parameters
        ----------
        function_name : str
            name of the user function to replace.
        user_path : str
            path to the new user function file.
        user_file : str
            name of the new user function file.


        """
        self.mbs.__set_user_fct_from_file__(function_name, user_path, user_file)

    def set_user_fct_from_ptr(self, function_name, user_fct_ptr):
322
        """
323
324
325
        Load a user function chosen by the user instead of the default one in the userfctR folder.

        The function is then unassigned by the module at the end of the run().
326

327
328
        Parameters
        ----------
329
330
331
332
333
334
335
        function_name : str
            name of the user function to replace.
        user_fct_ptr : ptr
            new user function pointer.

        """
        self.mbs.__set_user_fct_from_ptr__(function_name, user_fct_ptr)
336

337
338
339
340
    def set_options(self, **kwargs):
        """

        Set the specified options for Invdyn module.
341

342
343
        Parameters
        ----------
344
        motion: int
345
            Determines how the evolution of q, qd qdd are provided.
346
347
348
349
350
            oneshot(default): Uses q, qd and qdd at the current time and configuration of the MBS.
            closeloop: Only for inverse kinematics analysis. Same as oneshot but save the iteration of the close loop process(NR).
            trajectory: Compute the evolution of between t0 and tf.
        trajectoryqname: char
            Give the path and filename(with extention) to the file containing the input trajectory in position of the joints.
351
352
353
354
            Only required for motion == 'trajectory' if some joints are independant.
            By default, pointer to NULL.
            Requirement on the file:
            First column is the time, other are the joints coordinates.
355
            Either provide only the independant joint(by increasing index), user_drivenjoint will be called.
356
            Either provide all the joint, user_drivenjoint will be neglected.
357
        trajectoryqdname: char
358
            Give the path and filename(with extention) to the file containing the input trajectory in velocity of the joints.
359
360
361
362
            Only required for motion == 'trajectory' if some joints are independant.
            By default, pointer to NULL.
            Requirement on the file:
            First column is the time, other are the joints velocities.
363
            Either provide only the independant joint(by increasing index), user_drivenjoint will be called.
364
            Either provide all the joint, user_drivenjoint will be neglected.
365
        trajectoryqddname: char
366
            Give the path and filename(with extention) to the file containing the input trajectory in acceleration of the joints.
367
368
369
370
            Only required for motion == 'trajectory' if some joints are independant.
            By default, pointer to NULL.
            Requirement on the file:
            First column is the time, other are the joints accelerations.
371
            Either provide only the independant joint(by increasing index), user_drivenjoint will be called.
372
            Either provide all the joint, user_drivenjoint will be neglected.
373
        t0: float
374
            initial time of the simulation, default = 0.0
375
        tf: float
376
            final time of the simulation, default = 5.0
377
        dt: float
378
            Time step, default = 0.001
379
380
            For motion == 'trajectory'(for inverse kinematic analysis, there must be at least one independent joint):
            Set to 0.0 to use the time vector of the coordinate input file(MbsSolvekinOptions::t0 and MbsSolvekinOptions::tf are ignored).
381
            Specify a value to use specific time vecor.
382
383
        save2file: int
            Determine whether results are written to files on disk(in MbsSolvekinOptions::respath folder):
384
            1: results are saved
385
            0: results are not saved
386
            default = 1
387
        resfilename: str
388
            The keyword used for determining the name of result files
389
        respath: str
390
391
            Path in which result file are saved.
            Default: the resultsR folder of the project
392
        animpath: str
393
394
            Path in which anim file is saved.
            Default: the animationR folder of the project
395
        save_anim: int
396
            1 to save the anim file
397
            0 otherwise(only valid if 'save2file' is set to 1)
398
            default = 1
399
        framerate: int
400
401
            number of frame per second for the .anim file
            default = 1000
402
        saveperiod: int
403
            The number of time steps between two buffer records
404
405
            default: 1(every time step are recorded)
        max_save_user: int
406
407
            The maximal number of user variables saved
            default: 12
408
        buffersize: int
409
410
411
412
            The number of time step that can be recorded in the buffer.
            Results are written to disk when the buffer is full.
            default: -1
            compute the buffer size for saving results only once at the end according to dt0, t0 and tf.
413
        verbose: int
414
415
            Gives informations during the process.
            default: 1, to disable set it to 0.
416
        store_results: boolean
417
418
            1 to save a copy of the results from the buffers
            default = 1
419

420
        """
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
        def motion(value):
            if(type(value) is int):
                if (value >= 0 and value <= 2):
                    return value
                else:
                    raise ValueError
            elif type(value) is str:
                if value == "oneshot":
                    return 0
                elif value == "closeloop":
                    return 1
                elif value == "trajectory":
                    return 2
                else:
                    raise ValueError
            else:
                raise TypeError

        options = {'motion': {'convert': motion, 'c_name': 'motion'},
                   'trajectoryqname': {'convert': str_to_bytes, 'c_name': 'trajectoryqname'},
                   'trajectoryqdname': {'convert': str_to_bytes, 'c_name': 'trajectoryqdname'},
                   'trajectoryqddname': {'convert': str_to_bytes, 'c_name': 'trajectoryqddname'},
                   't0': {'convert': float, 'c_name': 't0'},
                   'tf': {'convert': float, 'c_name': 'tf'},
                   'dt': {'convert': float, 'c_name': 'dt'},
                   'save2file': {'convert': int, 'c_name': 'save2file'},
                   'resfilename': {'convert': str_to_bytes, 'c_name': 'resfilename'},
                   'respath': {'convert': str_to_bytes, 'c_name': 'respath'},
                   'animpath': {'convert': str_to_bytes, 'c_name': 'animpath'},
                   'save_anim': {'convert': int, 'c_name': 'save_anim'},
                   'framerate': {'convert': int, 'c_name': 'framerate'},
                   'saveperiod': {'convert': int, 'c_name': 'saveperiod'},
                   'max_save_user': {'convert': int, 'c_name': 'max_save_user'},
                   'buffersize': {'convert': int, 'c_name': 'buffersize'},
                   'verbose': {'convert': int, 'c_name': 'verbose'},
                   'store_results': {'convert': int, 'c_name': 'store_results'},
                   }
458

459
        for key, value in kwargs.items():
460
461
462
463
464
465
466
467
468
469
            if key not in options:
                raise TypeError("{:} is an invalid option name.".format(key))
            try:
                c_name = options[key]['c_name']
                setattr(self.mbs_invdyn_ptr.contents.options.contents, c_name, options[key]['convert'](value))
            except ValueError as err:
                # if wrong value in motion
                if key == 'motion':
                    raise ValueError('>>INVDYN>>  {:} is not a valid motion'.format(value)).with_traceback(err.__traceback__) from None
                # if error during the cast
470
                else:
471
472
473
474
475
476
477
478
                    raise TypeError("{:} is {:}, can not be casted from {:}.".format(key, options[key]['convert'], type(value))).with_traceback(err.__traceback__) from None

            except AttributeError as err:
                # if error during cast of strings (i.e in str_to_bytes)
                raise TypeError("{:} is str, can not be casted from {:}".format(key, type(value))).with_traceback(err.__traceback__) from None

            except TypeError as err:
                # if wrong type in motion
Louis Beauloye's avatar
Louis Beauloye committed
479
480
                if key == 'motion':
                    raise TypeError("{:} is str or int, can not be casted from {:}.".format(key, type(value))).with_traceback(err.__traceback__) from None
481

482
483
    def get_options(self, *args):
        """
484
        Get the specified options for Invdyn module.
485

486
487
        Parameters
        ----------
488
        The different options specifed in the documentation of 'set_options()'
489

490
491
        Returns
        -------
492
        The value of the different options specifed in the documentation of 'set_options()'
493
494
495
496
        """
        options = []
        for key in args:
            if key == "motion":
497
498
499
500
501
502
                if self.mbs_invdyn_ptr.contents.options.contents.motion == 0:
                    options.append("oneshot")
                elif self.mbs_invdyn_ptr.contents.options.contents.motion == 1:
                    options.append("closeloop")
                elif self.mbs_invdyn_ptr.contents.options.contents.motion == 2:
                    options.append("trajectory")
503
            elif key == "trajectoryqname":
504
505
506
                address = self.mbs_invdyn_ptr.contents.options.contents.trajectoryqname
                defaut = None
                options.append(str_from_c_pointer(address, defaut))
507
            elif key == "trajectoryqdname":
508
509
510
                address = self.mbs_invdyn_ptr.contents.options.contents.trajectoryqdname
                defaut = None
                options.append(str_from_c_pointer(address, defaut))
511
            elif key == "trajectoryqddname":
512
513
514
                address = self.mbs_invdyn_ptr.contents.options.contents.trajectoryqddname
                defaut = None
                options.append(str_from_c_pointer(address, defaut))
515
516
517
518
519
520
521
522
523
            elif key == "t0":
                options.append(self.mbs_invdyn_ptr.contents.options.contents.t0)
            elif key == "tf":
                options.append(self.mbs_invdyn_ptr.contents.options.contents.tf)
            elif key == "dt":
                options.append(self.mbs_invdyn_ptr.contents.options.contents.dt)
            elif key == "save2file":
                options.append(self.mbs_invdyn_ptr.contents.options.contents.save2file)
            elif key == "resfilename":
524
525
526
                address = self.mbs_invdyn_ptr.contents.options.contents.resfilename
                defaut = 'invdyn'
                options.append(str_from_c_pointer(address, defaut))
527
            elif key == "respath":
528
529
530
                address = self.mbs_invdyn_ptr.contents.options.contents.respath
                defaut = os.path.abspath(os.path.join(self.mbs.project_path, 'resultsR'))
                options.append(str_from_c_pointer(address, defaut))
531
            elif key == "animpath":
532
533
534
                address = self.mbs_invdyn_ptr.contents.options.contents.animpath
                defaut = os.path.abspath(os.path.join(self.mbs.project_path, 'animationR'))
                options.append(str_from_c_pointer(address, defaut))
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
            elif key == "save_anim":
                options.append(self.mbs_invdyn_ptr.contents.options.contents.save_anim)
            elif key == "framerate":
                options.append(self.mbs_invdyn_ptr.contents.options.contents.framerate)
            elif key == "saveperiod":
                options.append(self.mbs_invdyn_ptr.contents.options.contents.saveperiod)
            elif key == "max_save_user":
                options.append(self.mbs_invdyn_ptr.contents.options.contents.max_save_user)
            elif key == "buffersize":
                options.append(self.mbs_invdyn_ptr.contents.options.contents.buffersize)
            elif key == "verbose":
                options.append(self.mbs_invdyn_ptr.contents.options.contents.verbose)
            elif key == "store_results":
                options.append(self.store_results)
            else:
Louis Beauloye's avatar
Louis Beauloye committed
550
                mbs_msg(">>" + self.module_name + ">> The option " + key + " is not defined in this module")
551

552
553
554
555
        if len(options) == 0:
            return
        if len(options) == 1:
            return options[0]
556

557
        return tuple(options)