Home | Trees | Indices | Help |
---|
|
This package is based on the top of MBDyn, a MultiBody Dynamics software written at the university Politecnico di Milano. In MBDyn, a simulation is started by providing an input file describing reference frames, nodes and elements. This package motivation is to turn MBDyn into a multibody dynamics library for Python, so then the user communicates with objects during the whole simulation. He does not describe its problem by a MBDyn input file any more. But moreover he can interact with objects at run time.
Such project requires some vector and matrix manipulation, that will be provided by the Numpy package. To plot the results, the Matplotlib package is suggested (and used during some examples) but not needed for running a simulation. The communication with MBDyn is achieved and documented in the mbdyn.bindings package. The next section is an overview about the MBDyn way of work and why the development was started around it. The second section explains how Python was used for getting new functionalities. What are the current achievements?By using a general description with nodes and elements, almost all the quantities computed were output in text files. Just some of the objects could write optional results, like for example dynamic structural nodes, but it could not be specified for every integrated quantity. It sounds really optional. Why does the user need such feature? Because he knows its model and useless operations at run time are critical as many iterations are involved. Some of the items are used only for the model building but will not output any interesting results. A variant would be to perform different simulations for the same model, a particular behavior being investigated each time. For example, a node under constraints does not need to output all its degrees of freedom, some of them will inherently be out of interest. If the user just want to know about the position of a node, there is no need to output the rotation matrix, velocity and angular velocity. C++ is fast but why does it do many useless operations? The reason comes from the input file. The user has already to supply a value for every field. If moreover he has to specify each quantity to save, or may want a particular degree of freedom, the parameters to write are too numerous.
Forcing the user to supply every field is furthermore relevant for a beginner, but not so convenient for an end user. For example for every node, the user has to write the position, rotation matrix, velocity and angular velocity relative to a reference frame. But a node is supposed to inherit from the reference frame attributes. If those last ones already described the node, the values entered will be a null position, velocity and angular velocity, the rotation matrix will be the identity one. Most of the nodes will be like that because the user needs to set up reference frames for defining the initial conditions of a complex problem. Generally just one or two parameters are specified differently between a node and its reference frame. As a result, it could be convenient to have default value for every item (reference frame, node or element). It could also be useful to describe a custom item having default values suited for the simulation.
The user may also need his own custom class based on an available one. The advantage is that he will then instantiate the same class in his script, that will avoid him to repeat the same description on the chosen library item. This is clearly a problem that developers can not guess, the goal is only to write a library for solving multibody problems. A suited template for a specific problem will be the user job that could as an alternative develop a corresponding library. Two requirements seem to be needed for the user: he would like to specify optional behaviors for some objects and by using the existing ones, he may need to describe its own class. Could it be easy for the developers?The first point to highlight, is that the situation is simpler than in the mbdyn.bindings module for the reason that the MBDyn service is not run. In the pre processing part, the task is finally to write a text file from Python in an object oriented way. This input file will start WraptMBDyn and once the interaction finished, the post processing is also done without a running MBDyn. This point makes the development simpler because it can always been done in Python. Thus there is not all the work of compiling a C++ shared library and SWIG extension with SCons , debugging memory allocation problems with GDB and so on. From here, how was Python used?
Python was used to describe an interface to every MBDyn object. The first advantage was the syntax (for example a class or function is defined by one keyword) and language features (list, dictionaries, everything object, third part packages). The crucial point is that Python allows references to objects. It would have been difficult, and also surely obscure, to write an interface to a C++ code in a language that does not support this feature because the MBDyn design uses it heavily. The disadvantage is for the user coming from a language that never deals with references, that is to say Matlab. In that case the language will of course be simpler (so commercial advertisements are more attractive) but also very limited. On that point Python does well because it only simplifies the pointer mechanism. For the user this is however very important to understand that once he has created an instance , he will always manipulate references to it. This is where the interface really starts to make sense. By using this package, the user first describes an object suited for his problem. Then only the MBDyn ones are going to be simulated but at each time step, in his script, he will have references to the objects current status and can use them to solve its specific problem. All the Python libraries and services are moreover available.
A level of abstraction becomes possible, in the sense that the user writes a suited object, handling the MBDyn results that he wants. Then he can dialog with this new object, solving only a small part of the problem, and forgets about the MBDyn abstract objects (reference frames, nodes and elements). By connecting different small pieces together, the whole problem is getting solved. Moreover useful parts can be shared by different simulations by writing a specific module. Examples of this approach are used in the wind-sim-suite project. The next section explains in details the pre-processing work with Python objects.Each object is responsible of writing its part of the input file. Those informations finally represent how MBDyn will instantiate the C++ objects. This process could certainly be done by Python but it will require further development. Moreover the input file is maybe an intermediate step to keep. First it allows to check how the Python package is working. The user could ignore the input file syntax but in case of a simulation crash, he can test it independently on the MBDyn executable. Moreover the C++ parser checks also for model consistency by requiring a 'control data' section. As a resume, the input file is probably a good idea for the systematic process of a solver.
For making the simulation flexible, the Python interface does not require the control data any more, this work is done in the mbdyn.control_data module. An user mistake will thus be issued by the MBDyn parser. Moreover every reference frames is supposed to have a distinct label, an integer, in order to describe the connectivity in the input file. The same remark applied for every item inside a group of nodes or elements. The groups are defined in the mbdyn.bindings.groups module. As explained in the previous section, the user will now use references to describe the topology of its model. As a result, the mbdyn.groups module will handle an automatic labelling of every item. That's why theBasicObject
of the mbdyn.common
module has a label as attribute. It will be the top class of every
MBDyn item. The same label will also be used to retrieved the MBDyn
instance generated by WraptMBDyn when parsing the input file (this step
is performed by the get_mbdyn_instance
method for each
item). Finally, every information required by MBDyn needs also to
be provided by the interface. The difference is that this last one
will keep the information entered as Python object while it will
need to be transformed as string for the text input file. This job
is done by the ManagerObject
in mbdyn.common that
assures to have a Python value and a corresponding MBDyn one for
every attribute concerned by the input file. The last step is to
add every item to a Simulation instance. What about the other
interface problems?
node1 = StructuralNode() node1.set_type("static") node2 = StructulalNode() # Description to continueis not not more painful than writing:
begin: nodes; structural: 1, static, # description of node 1 goes here structural: 1, dynamic, # description of node 2 goes here end: nodes;
For the developers the situation becomes however really easier, because this is the user that choose the class from the library and create the instance. Thus he expresses more ideas than in a plain text file and he will directly dialog with the instance. In that case no tests are needed, if he fails in that part he will get a Python error. For scientists dealing with multibody dynamics problem, the Python bases are accessible very quickly. Similar simulations as the usual input files could be reproduced without many efforts.
But more can be done from that approach. When the user creates
an instance, default settings are applied on it. They are described
in the set_default
method of every object, as a start
the reader can see mbdyn.nodes and mbdyn.elements_base. If the user sets the node or
element relative to a reference frame, the default properties will
be updated in that base. There are however still some problems,
warned in that place. But the design idea is to apply method
on the object for handling options. For example the attributes that
need to be saved on the item will be specified by the
will_save
, will_save_only
and
will_save_nothing
methods applied on the Record class
(base of the BasicObject and thus every item). Then the
internal saving process is addressed in details in the
post-processing section.
Record
class in mbdyn.record. Then the results need to be saved at
each time step, for this each concerned object has as a
save
method. The main save
method, that
will save all the object tree is performed by the Simulation. However the Simulation
object is not aware about when a time step has been finished,
because this part deals with the MBDyn service. That's why the
save
method of the Simulation
is called
by WraptMBDyn in the mbdyn.bindings
module. At the end of the simulation, the complete object tree has
been filled with results. The PyMBDynFile class is for that reason a container
that will save simulations into a file. Then the user can load his
simulation with results in another script. He has the same objects
tree but that time filled with results. The usual MBDyn behavior,
saving all the results in a file, can nevertheless be find back by
the method write_mbdyn_files
on WraptMBDyn. Thanks to the Python syntax, it is
already easier to achieve post-processing in an interactive section
than having to process text files. Is is possible to do more from
that object-oriented approach?
At that step it may be difficult to follow what represents each section and what has been concretely achieved. The following example try to illustrate it. It could be bombarded with criticisms for being actually too simple and idealistic. It is true that the package has not yet reached a mature status and some solutions are probably more complicated than what they should be. But this section aims at giving a picture of the functionalities researched.
If the user wants to design a rotor, he will certainly set a hub node. The subject is dealing with mechanical engineering, so this node will be a structural node. First, let's create it:class HubNode(StructuralNode): passThe inheritance is done but the new class has nothing new to offer. The node will be dynamic because it will deal with acceleration quantities and be attached to a body element for setting an inertia:
class HubNode(StructuralNode): def __init__(self, name="hub node"): StructuralNode.__init__(self, name) self.set_type("dynamic")Notice the inheritance from the StructuralNode achieved in two lines. The present application programming interface will give you the definition of every object. As the node is at the hub, it is supposed that only the rotational speed needs to be saved during the simulation. The too big simplicity of this example is here. In case the user wants to save the default quantities (position, rotation matrix..) and its own, he has also to customize the
init_results
method of the Record class
for executing all the needed actions before saving the results. But
the present example stays only with one quantity:
class HubNode(StructuralNode): def __init__(self, name="hub node"): StructuralNode.__init__(self, name) self.set_type("dynamic") self.rotational_speed = 0. self.will_save_only("rotational_speed")Now the save method of the Simulation will be called at each time step by WraptMBDyn. The one of the
HubNode
will
be overriden:
class HubNode(StructuralNode): def __init__(self, name="hub node"): StructuralNode.__init__(self, name) self.set_type("dynamic") self.rotational_speed = 0. self.will_save_only("rotational_speed") def save(self): rot_array = self.mbdyn_inst.get_rotational_speed() self.rotational_speed = rot_array[2][0] self.save_results()The
mbdyn_inst
is a reference to the MBDyn instance
computed by the C++ code. This work is provided by the
Simulation
. As a result, its rotational speed vector
will be got at each time step but the user knows from its problem
description that only the value along the z axis
is relevant. For the HubNode
, this is the only result
saved. The hub node will now be used for a simulation
description:
hub_node = HubNode("hub node") # initial conditions go here (reference frame, # position, rotation_matrix...) # Problem description with others nodes and elements simu = Simulation() simu.add_node(hub_node) # others items are added simu.run() pyf = pyMBDynFile("rotor_simu.pymb", "w") pyf.add(simu) pyf.close()All this code will be written in a Python script, for example 'simulate_rotor.py' and the run will be achieved by
python
simulate_rotot.py
. It will create a file 'rotor_simu.pymb'
with the run simulation contained inside. An important remark: the
simulation does not know a HubNode
but the user has
inherited from the StructuralNode
class so it works.
Moreover, his code described in the save
method is
executed at each time step. At the end, everything is saved in the
pyMBDynFile
container, it can now be used in a loading
script, 'load.py' :
pyf = pyMBDynFile("rotor_simu.pymb") simu = pyf.simulations[0] strnodes = simu.nodes.structuralsNow IPython can be used for interaction. The command
ipython load.py
will open a session after executing the script:
>>> hub = strnodes.get("hub node") >>> hub.results [rotational_speed] >>> import pylab as P >>> P.plot(simu.results.time, hub.results.rotational_speed) >>> P.show()
The rotational speed is available through the results
attribute, instance of Results
defined in mbdyn.quantity.
With the three last lines, a figure showing the rotational speed
according to the time should be plotted.
Simulation
class, then he could handle a special object.
Moreover any object could be saved with the simulation, assuming that
it inherits from the Record one. The next step would be to provide a neat
interface to such requirements. This approach was however already
used in the wind-sim-suite project, where a wind turbine object
can be added to the simulation.
To conclude Python does not execute any integration but is just a language replacing the input file to describe a simulation. Its batteries included are however not a joke. Imitating the current way to write input files is possible but a complete programming language is now placed in the user hands. As a result he can describe its own objects that manipulate MBDyn ones, keep references of computed items, define its own and with some efforts extend the library for post-processing. This great flexibility has a price: the requirement to learn Python. But the reward is worth the hassle because the script is interactive and especially suited to his problem. Last but not least, third part packages could potentially improve the scientific usability of MBDyn: SciPy, PyDSTool, IPython, Matplotlib... to name a few. Is there still a reason to not dive into Python?
On the developer side, the significant advances are to turn MBDyn into a Python service and give more responsibility to the user. He is now supposed to know about an object when describing a simulation. In clear the parts where MBDyn was assisting a text file writer is now replaced by a Python interpreter assisting a script programmer. Is it a developer laziness? No, because people simulating multibody problems will surely know about numerical analysis. On that point Python is an user friendly language that has always powerful concepts hidden for later use. Concerning the MBDyn service, most of the actions done at run time should of course be performed in C++ for speed reasons. New Python functionalities should be translated step by step. Nevertheless when a limitation is encountered, a Python framework seems more productive for development than dealing with C++ sources.Version: 0.2-r1
|
|||
|
|
|||
__author_utf8__ =
|
|||
__author_email__ =
|
|||
__mbdyn_developers__ =
|
|
__mbdyn_developers__
|
Home | Trees | Indices | Help |
---|
Generated by Epydoc 3.0beta1 on Thu Aug 30 11:45:41 2007 | http://epydoc.sourceforge.net |