Package mbdyn :: Module main
[hide private]

Source Code for Module mbdyn.main

  1  #!/usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3  # 
  4  # This file is part of MBDyn sim suite. 
  5  # Copyright (C) 2007 André ESPAZE, as part of a Master thesis supervised by 
  6  # Martin O.L.Hansen (DTU) and Nicolas Chauvat (Logilab) 
  7   
  8  # MBDyn sim suite is free software; you can redistribute it and/or modify 
  9  # it under the terms of the GNU General Public License as published by 
 10  # the Free Software Foundation; either version 2 of the License, or 
 11  # (at your option) any later version. 
 12  # 
 13  # This program is distributed in the hope that it will be useful, 
 14  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 16  # GNU General Public License for more details. 
 17  # 
 18  # You should have received a copy of the GNU General Public License 
 19  # along with this program; if not, write to the Free Software 
 20  # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
 21  # 
 22  """The main interface to MBDyn. This module contains  
 23  the C{Simulation} class that generates the input file. 
 24  """ 
 25  import os 
 26  import copy  
 27   
 28  from mbdyn.preprocessing import SimulationBase 
 29  try: 
 30      from mbdyn.bindings.main import WraptMBDyn  
 31  except ImportError: 
 32      pass 
 33   
34 -class List:
35 """A list containing object with a name attribute. 36 A kind of dictionary that remenbers the order in which 37 the items have been added. 38 """ 39
40 - def __init__(self):
41 self.list = [] 42 self.list_names = []
43
44 - def add(self, obj, name=None):
45 """Add an object to the list""" 46 self.list.append(obj) 47 if name != None: 48 self.list_names.append(name) 49 else: 50 self.list_names.append(obj.name)
51
52 - def __getitem__(self, obj_name):
53 return self.list[self.list_names.index(obj_name)]
54 55
56 -class Simulation(SimulationBase):
57 """The main MBDyn simulation. 58 C{Simulation} will gather all the objects and run L{WraptMBDyn}, 59 a MBDyn simulation controlled from Python. 60 """ 61
62 - def __init__(self, name="mbdyn simu", title="Mbdyn used from Python", 63 keep=False, overwrite=False):
64 """'name' is only used for writing the files.""" 65 SimulationBase.__init__(self, name, title, keep, overwrite) 66 67 self.time = 0. 68 self.nb_frames = 0 69 70 # For easier work for the user (writing of the update 71 # method and ipython interaction), wm is pointing to wrapt_mbdyn 72 self.wrapt_mbdyn = None 73 self.wm = self.wrapt_mbdyn 74 self.has_wrapt_mbdyn = False 75 self.has_init = False 76 self._has_written = False 77 self.solve = self.solve_by_wrapt_mbdyn 78 79 self.call_update = True 80 self.call_save = True 81 82 self.repr_list = [] 83 self.own_para_names += ["name", "title", "time", "nb_frames", 84 "repr_list"] 85 self.children_names = ["nodes", "refs"] 86 self.will_save("time")
87
88 - def set_integrator(self, integrator):
89 """Set the simulation integrator""" 90 self.integrator = integrator
91
92 - def _add_item_to_list(self, list_name, item):
93 """Add a node, element or a reference frame to 94 the corresponding object list. 95 Store also a reference of the simulation to the item 96 object and the representation name is added for the magic 97 function __repr__. 98 """ 99 item.set_simulation_ref(self) 100 getattr(self, list_name).add(item) 101 if list_name not in self.repr_list: 102 self.repr_list.append(list_name)
103
104 - def add_reference(self, reference):
105 """Add a reference frame to the simulation""" 106 self._add_item_to_list("refs", reference)
107
108 - def add_node(self, node):
109 """Add a node to the simulation""" 110 self._add_item_to_list("nodes", node) 111 self.control_data.add(node)
112
113 - def add_element(self, elt):
114 """Add an element to the simulation""" 115 self._add_item_to_list("elts", elt) 116 self.control_data.add(elt)
117
118 - def add_object(self, obj):
119 """The user can add its own object to the simulation. 120 The idea: if the user adds its own object, then he must not add 121 the element and the node to the simulation. His object already contains 122 a list of elements and a list of nodes. By this manner, the controlData 123 can not have duplicated information, that is to say, duplicated node or 124 element. Currently in development and not in use because 125 it may be simpler to invite the user at inheriting 126 from the C{Simulation} (approach run successfully in wind-sim-suite). 127 """ 128 self.control_data.add(obj) 129 for elt in obj.elements: 130 elt.set_simulation_ref(self) 131 self.elts.add(elt) 132 for node in obj.nodes: 133 node.set_simulation_ref(self) 134 self.nodes.add(node) 135 for ref in obj.references: 136 self.refs.add(ref)
137
138 - def append_output(self, node_lines):
139 """Append a MBDyn time step results to the Python objects. 140 Use when the text files are scanned""" 141 for node_line in node_lines: 142 node_data = node_line.split() 143 node_indice = int(node_data[0]) 144 node_values = [float(val) for val in node_data[1:]] 145 node = self.nodes.get_node_id(node_indice) 146 if node: 147 node.append(node_values)
148
149 - def _set_info_for_loading(self):
150 """Load the time step and the .mov file before 151 loading the results, used only when scanning 152 the output files""" 153 self.mov_file_name = self.file_name + ".mov" 154 self.time_step = self.integrator["time step"][0]
155
156 - def load_results(self):
157 """Load the result from the '.mov. file of MBDyn containing 158 the kinematic degrees of freedom of the nodes""" 159 output_file = open(self.mov_file_name) 160 lines = output_file.readlines() 161 output_file.close() 162 self.nodes.init_results() 163 self.time = [] 164 nodes_nb = self.nodes.get_nodes_nb() 165 outputs_nb = len(lines) / nodes_nb 166 for step_indice in range(outputs_nb): 167 self.time.append(step_indice*self.time_step) 168 output_indice = step_indice*nodes_nb 169 self.append_output(lines[output_indice : output_indice + nodes_nb])
170
171 - def set_wrapt_mbdyn(self, wrapt_mbdyn):
172 """Set an instance of the wraptMBDyn, used 173 when the input file is not written by the Python 174 interface""" 175 self.wrapt_mbdyn = wrapt_mbdyn 176 self.wm = self.wrapt_mbdyn 177 self.has_wrapt_mbdyn = True
178
179 - def _get_mbdyn_instances(self):
180 """The instances provided from the interface get the ones 181 created by MBDyn""" 182 for item in self.nodes.all + self.elts.all + self.refs: 183 item.get_mbdyn_instance()
184
185 - def save_mbdyn(self):
186 """Save the mbdyn status. First the simulation is saved 187 and then all the objects. This method will be called 188 by L{WraptMBDyn} as every time step.""" 189 self.time = self.wm.solver.current_time 190 self.save_results() 191 for item in self.nodes.all + self.elts.all: 192 item.save()
193
194 - def save(self):
195 """The same method as L{save_mbdyn}. The default is 196 just to save mbdyn but it changes when inheritance occurs""" 197 self.save_mbdyn()
198
199 - def update_elts(self):
200 """Update all the element by calling the C{update} method 201 of each element.""" 202 solver = self.wrapt_mbdyn.solver 203 self.time = solver.current_time + solver.time_step 204 for elt in self.elts.all: 205 elt.update(self)
206
207 - def update(self):
208 """The same as L{update_elts}. The default update 209 for a simulation. Called by L{WraptMBDyn} as every 210 time step.""" 211 self.update_elts()
212
213 - def init_simulation(self):
214 """Initialization before running MBDyn. 215 The MBDyn instances are tracked from the Python objects. 216 217 If an update needs to be done on the elements, they are 218 initialized by 'do_as_init'. The WraptMBDyn update method 219 will call the simulation one. 220 221 If the values are saved from Python, the results are 222 initialized. The WraptMBDyn save method will call 223 the simulation one. 224 """ 225 self.time = 0. 226 self.init_results() 227 self._get_mbdyn_instances() 228 if self.call_update: 229 for elt in self.elts.all: 230 elt.do_as_init() 231 self.wrapt_mbdyn.update = self.update 232 if self.call_save: 233 for item in self.nodes.all + self.elts.all: 234 item.init_results() 235 for ref in self.refs: 236 ref.store_mbdyn_data() 237 self.wrapt_mbdyn.save = self.save 238 self.wrapt_mbdyn.final_action = self.final_action
239
240 - def _init_wrapt_mbdyn(self):
241 """Initialize the WraptMBDyn instance. This method 242 will also create a WraptMBDyn in case an input file 243 have been written.""" 244 if not self.has_wrapt_mbdyn: 245 self.write() 246 self._has_written = True 247 self.set_wrapt_mbdyn(WraptMBDyn(self.os_name, self.dir)) 248 self.wrapt_mbdyn.init()
249
250 - def init(self):
251 """Initialize the simulation according to L{WraptMBDyn}. 252 The Python object get references to the object from 253 the bindings module, interfacing the C++ 254 ones.""" 255 if not self.has_init: 256 self._init_wrapt_mbdyn() 257 self.init_simulation() 258 self.has_init = True 259 else: 260 print "'init()' already called on the Simulation"
261
262 - def run_with_executable(self, boolean):
263 """Decide if the simulation with the input file 264 written is run with the MBDyn executable 265 of the bindings. 266 Note: does not make sense in case WraptMBDyn comes 267 from outside, no input file has been written in 268 that case.""" 269 if self.has_wrapt_mbdyn: 270 print "'run_with_excutable' is inactive as " +\ 271 "'set_wrapt_mbdyn' has been called." 272 else: 273 if boolean: 274 self.solve = self.solve_by_mbdyn_exec 275 else: 276 self.solve = self.solve_by_wrapt_mbdyn
277
278 - def solve_by_wrapt_mbdyn(self):
279 """Solve the problem by WraptMBDyn. The most common 280 way to solve a simulation.""" 281 if not self.has_init: 282 self.init() 283 self.wrapt_mbdyn.run_full()
284
285 - def final_action(self):
286 """Called by WraptMBDyn when it finished the simulation. 287 This method allows to interact with WraptMBDyn (by 288 'run_until'...) without loosing the actions that should 289 be done on the simulation object at the final time""" 290 self.nb_frames = len(self.results.time) 291 if self._has_written: 292 self.clean(self.os_name + "_result")
293
294 - def solve_by_mbdyn_exec(self):
295 """Run the MBDyn executable on the input file written.""" 296 command = "mbdyn %s" % self.file_name 297 #print COMMAND 298 os.system(command) 299 self._set_info_for_loading() 300 self.load_results() 301 self.clean()
302
303 - def run_full(self):
304 """Run the complete simulation""" 305 self.solve()
306
307 - def run(self):
308 """Identic function has 'run_full()'""" 309 self.run_full()
310
311 - def __repr__(self):
312 """Return the representation of the simulation""" 313 string = "[" 314 if len(self.repr_list) > 0: 315 for repr in self.repr_list[:-1]: 316 string += repr + ",\n" 317 string += self.repr_list[-1] 318 string += "]" 319 return string
320
321 - def collect_parameters(self):
322 """Collect all the parameters of the Simulation and store them 323 in the para dictionary""" 324 self.collect_own_parameters() 325 for children_name in self.children_names: 326 children = getattr(self, children_name) 327 children.collect_parameters() 328 self.para[children_name] = children.para
329
330 - def set_parameters(self, para):
331 """Set the parameters of the simulation from the pickled 332 dictionary para""" 333 self.set_own_parameters(para) 334 for children_name in self.children_names: 335 children = getattr(self, children_name) 336 children.set_parameters(para[children_name]) 337 for item in self.nodes.all + self.elts.all + self.refs: 338 item.set_simulation_ref(self)
339 340
341 -class PyMBDynFile:
342 """A file containing the MBDyn results as well as the Python information 343 for loading a pickled Simulation. This file acts as a container, 344 many simulations could be contained in one file. 345 """ 346
347 - def __init__(self, name, mode="r", path=".", autoload=True):
348 self.name = name 349 self.mode = mode 350 self.path = path 351 self.file_name = os.path.join(path, name) 352 353 self.simulations = [] 354 self.simulation_paras = [] 355 self.simulation_names = [] 356 357 self.file = None 358 self.CLASS = Simulation 359 self.__open() 360 if (mode=="r") and autoload: 361 self.load()
362
363 - def __open(self):
364 """Open the file""" 365 self.file = open(self.file_name, self.mode)
366
367 - def load(self):
368 """Load the data from the file""" 369 import cPickle as pickle 370 self.simulation_paras = pickle.load(self.file) 371 self.file.close() 372 for simulation_para in self.simulation_paras: 373 simu = self.CLASS() 374 simu.set_parameters(simulation_para) 375 self.simulations.append(simu) 376 self.simulation_names.append(simu.name)
377
378 - def add(self, simu):
379 """Add a simulation to the file to save 380 (save automatically the simulation).""" 381 simu.collect_parameters() 382 para = copy.deepcopy(simu.para) 383 self.simulation_paras.append(para) 384 self.simulations.append(simu) 385 self.simulation_names.append(simu.name) 386 if not self.file.closed: 387 self.file.close() 388 self.__open() 389 self.write()
390
391 - def get_simu(self, name):
392 """Return a simulation from its name""" 393 return self.simulations[self.simulation_names.index(name)]
394
395 - def get_simu_id(self, indice):
396 """Return the indice of a simulation. The numerotation is starting 397 at 1 and not a 0. Python users can directly access the simulation by 398 the list attribute C{simulations}.""" 399 return self.simulations[indice - 1]
400
401 - def write(self):
402 """Write the simulation in the file""" 403 import cPickle as pickle 404 pickle.dump(self.simulation_paras, self.file)
405
406 - def close(self):
407 """Close the file""" 408 self.file.close()
409