class IntegrateRKF45(DynamicAnalysis): """ classdocs """ def __init__(self, MBD_system, parent=None): """ Constructor """ super(IntegrateRKF45, self).__init__(MBD_system, parent) def evaluate_absError(self, w, w_new): """ :return: """ # e = (1. / self.h) * np.linalg.norm(((1./360.)*K1 - (128./4275.)*K3 - (2197./75240.)*K4 + (1./50.)*K5 + (2./55.)*K6), ord=2) # w_new = self._evaluate_w_new(w, K1, K2, K3, K4, K5, K6) e = self.evaluate_error_HHT_I3(w, w_new) # if e < 1E-11: # e = 1E-11 return e def evaluate_error_HHT_I3(self, w, w_new): """ :return: """ q_new = self.get_q(w_new) self.evaluate_q_max(w_new) x = q_new / self.q_max # error e = (self.h**2 / np.sqrt(self.q_n)) * np.linalg.norm( x, ord=2) #(self.h**2 / np.sqrt(self.q_n)) * np.linalg.norm(x, ord=2) return e def evaluate_error_RKF45(self, K1, K2, K3, K4, K5, K6): """ :return: """ d = (1. / self.h) * np.abs( np.array((1. / 360.) * K1 - (128. / 4275.) * K3 - (2197. / 75240.) * K4 + (1. / 50.) * K5 + (2. / 55.) * K6)) e = np.max(np.abs(self.get_q(d))) return e def _evaluate_w_new(self, w, K1, K2, K3, K4, K5, K6): """ :return: """ w_new = w + (25. / 216.) * K1 + (1408. / 2565.) * K3 + ( 2197. / 4104.) * K4 - (1. / 5.) * K5 return w_new def check_error(self): """ :return: """ if self.absError is np.nan: self.simulation_error.setError("Evaluated error is NaN!") return True if self.absError > self.absTol: return True else: return False def check_time_step(self, t, h, w, R=None): """ :param t: :param h: :param w: :return: """ if self.FLAG_contact == 0: delta = 0.84 * (self.absTol / np.max(R))**(1. / 4.) if delta <= 0.1: h = 0.1 * h elif delta >= 4.: h = 4. * h else: h = delta * h if h > self.Hmax: h = self.Hmax if t >= self.t_n: self.FLAG = 0 elif t + h > self.t_n: h = self.t_n - t elif h < self.Hmin: print "h =", h print "self.Hmin =", self.Hmin print "self.absTol =", self.absTol print "self.absError =", self.absError # h = self.Hmin self.simulation_error.setWarning("Hmin exceeded!") # error = True # h = self.Hmin # print "Hmin exceeded!" # self.FLAG = 0 if self.FLAG_contact == 1: h = self.Hcontact if self.FLAG_contact == -1: h = 0.5 * h if h < self.Hmin and t < self.t_n - self.Hmin: print "h =", h print "self.Hmin =", self.Hmin print "self.absTol =", self.absTol print "self.absError =", self.absError print "self.contact_status_list =", self.contact_status_list self.simulation_error.setError("Hmin exceeded! FLAG contact is: " + str(self.FLAG_contact), q=w) # error = True # h = self.Hmin return h, self.simulation_error.error def solve(self, q0=[], t_n=None, absTol=1E-9): """ Solves system of ode with order 5 method with runge-kutta algorithm """ # redefine solution containers self._solution_containers() # copy MBD object if hasattr(self.MBD_system, "setSolver"): self.MBD_system.setSolver(self) self._MBD_system = self.MBD_system # set solver self._MBD_system.setSolver(self) # dae fun object if self.DAE_fun is None: self.DAE_fun = DAEfun(self._MBD_system, parent=self) if q0: self.q0 = q0 self.start_solve() # create array of initial conditions for differential equations # get initial conditions if hasattr(self._MBD_system, "q0"): self._MBD_system.q0 = self.q0 if t_n is not None: self.t_n = t_n # evaluate stiffness matrix if hasattr(self.DAE_fun, "evaluate_K"): self.DAE_fun.evaluate_K(self.q0) self.simulation_id = 0 # 0 - no contact # +1 - contact detected # -1 - contact already happened - reduce integration step self.step = 0 if hasattr(self._MBD_system, "Hmin"): self.h_contact = self._MBD_system.Hmin self._append_to_file_step = 0 self.t_0 = self._dt = 0 self.FLAG = 1 if hasattr(self._MBD_system, "t_n"): if self._MBD_system.t_n is not None: self.t_n = self._MBD_system.t_n if hasattr(self._MBD_system, "stepsNumber"): self.stepsNumber = self._MBD_system.stepsNumber t = self.t_0 w = self.q0 if self.t_n is None and self.stepsNumber is not None: self.t_n = np.inf # logging.getLogger("DyS_logger").info("Size of MBD system in bytes %s" % sys.getsizeof(self.MBD_system)) logging.getLogger("DyS_logger").info( "Simulation started with initial conditions q0:\n%s" % self.q0) h = self.Hmax self._t_FLAG1 = self.Hmax # print "absTol =", absTol # self.update_opengl_widget_every_Nth_step = 1*((t_n - t_0)/Hmax) # print "self.update_opengl_widget_every_Nth_step =", self.update_opengl_widget_every_Nth_step self.save_updated_screenshot_to_file(self.t_0) # np.set_printoptions(precision=20, threshold=1000, edgeitems=True, linewidth=1000, suppress=False, formatter={'float': '{: 10.9e}'.format}) while self.FLAG == 1 and not self._error and not self.DAE_fun.error: # time.sleep(.001) # if self.step > 1415: # print "----------------------" # print "step =", self.step, "t =", t, "h =", h#"self.FLAG_contact =", self.FLAG_contact # print "step =", self.step, "h =", h, "t =", t # print "step =", self.step self.h = h self.t = t # print "self.h =", self.h K1 = h * self.DAE_fun.evaluate_dq(t, w) K2 = h * self.DAE_fun.evaluate_dq(t + (1. / 4.) * h, w + (1. / 4.) * K1) K3 = h * self.DAE_fun.evaluate_dq( t + (3. / 8.) * h, w + (3. / 32.) * K1 + (9. / 32.) * K2) K4 = h * self.DAE_fun.evaluate_dq( t + (12. / 13.) * h, w + (1932. / 2197.) * K1 - (7200. / 2197.) * K2 + (7296. / 2197.) * K3) K5 = h * self.DAE_fun.evaluate_dq( t + h, w + (439. / 216.) * K1 - 8. * K2 + (3680. / 513.) * K3 - (845. / 4104.) * K4) K6 = h * self.DAE_fun.evaluate_dq( t + (1. / 2.) * h, w - (8. / 27.) * K1 + 2. * K2 - (3544. / 2565.) * K3 + (1859. / 4104.) * K4 - (11. / 40.) * K5) w_new = self._evaluate_w_new(w, K1, K2, K3, K4, K5, K6) # self.absError = (1. / h) * np.linalg.norm((1. / 360.) * K1 - (128. / 4275.) * K3 - (2197. / 75240.) * K4 + (1. / 50.) * K5 + (2. / 55.) * K6) # self.absError = self.evaluate_error_HHT_I3(w, w_new, K1, K2, K3, K4, K5, K6) self.absError = self.evaluate_absError(w, w_new) #self.absError = (1. / h) * np.linalg.norm((1. / 360.) * K1 - (128. / 4275.) * K3 - (2197. / 75240.) * K4 + (1. / 50.) * K5 + (2. / 55.) * K6) #self.absError = 0.1*self.absTol # self.R = absTol # print "E_RKF45 =", self.evaluate_error_RKF45(K1, K2, K3, K4, K5, K6), "E_HHT_I3 =", self.absError # if calculated difference is less the absolute tolerance limit and accept the calculated solution # if not self.errorControl: # self.absError = self.absTol # if (self.absError <= self.absTol) and (self.FLAG_contact in [0, 1]): # print "self.check_error() =", self.check_error() # solve contacts self.FLAG_contact = self._evaluate_contacts(t, w_new) if not self.check_error(): #and (self.FLAG_contact in [0, 1]) # next time point self.t = t = t + h # value of vector of variables at next time step w = w_new if self.FLAG_contact in [0, 1]: # evaluate mechanical energy of system self._mechanical_energy, self._kinetic_energy, self._potential_energy, self._elastic_strain_energy = self._evaluate_mechanical_energy( w) self._energy_delta = self.evaluate_energy_delta( self._mechanical_energy) else: self.t, self.step, self._mechanical_energy, self._energy_delta = self._use_last_accapted_solution( t, self.step) else: self.t, self.step, self._mechanical_energy, self._energy_delta = self._use_last_accapted_solution( t, self.step) t = self.t # w = w # self.step = self.step # self._mechanical_energy = 0. # self._energy_delta = 0. # track - store simulation state data of different MBD system objects # print "h1 =", h h, t, w = self._track_data(h, t, w) # print "h2 =", h # check time step if self.errorControl: h, self._error = self.check_time_step(t, h, w, R=self.absError) else: print UserWarning, "Error control dissabled! Results may be wrong!" self._error = False # print "h3 =", h # process information of integration process if not self.check_error() and (self.FLAG_contact in [ 0, 1 ]) and self.update_visualization_widget: self._info(t, w) # check if finished if (t >= self.t_n) or (self.step == self.stepsNumber): self.FLAG = 0 self.finished = True self.refresh(t=t, q=w) # integration finished - end time reached successfully if self.finished or self.failed: self.refresh(t=t, q=w) self.finished_solve() self.FLAG = 0 if self.stopped: self.refresh(t=t, q=w) self.stop_solve() self.FLAG = 0 if np.isnan(t): self._error = True self.failed = True print "t is NaN! Check Hmax!" if self._error or self.failed or self.simulation_error.error: print "self._error =", self._error print "self.failed =", self.failed print "self.DAE_fun.error =", self.DAE_fun.error self.simulation_failed() print self.simulation_error.info print Warning, "Simulation failed!" # save data to file if self.write_to_file: self.write_simulation_solution_to_file() def _use_last_accapted_solution(self, t, step): """ :return: """ energy_t = 0. energy_delta = 0. return t, step, energy_t, energy_delta