示例#1
0
class SolveDynamicAnalysis(QObject):    # Thread, QObject
    """
    classdocs
    """
    __simulation_id = itertools.count(0)

    def __init__(self, MBD_system, parent=None):
        """
        Constructor
        """
        super(SolveDynamicAnalysis, self).__init__(parent)

        #   parent
        self._parent = parent

        #   states of simulations
        self.running = False
        self.stopped = False
        self.finished = False
        self.failed = False
        self._no_error = False

        #   signals
        self.step_signal = stepSignal()
        self.finished_signal = FinishedSignal()
        self.repaintGL_signal = RepaintGLSignal()
        self.energy_signal = EnergySignal()
        self.error_time_integration_signal = ErrorTimeIntegrationSignal()
        self.filename_signal = solutionFilenameSignal()
        self.save_screenshot_signal = SaveScreenshot()
        self.solution_signal = SolutionSignal()

        #   MBD system object
        self.MBD_system = MBD_system
        #    copy MBD object
        self._MBD_system = copy.copy(self.MBD_system)
        #    DAE fun object
        self.DAE_fun = DAEfun(self._MBD_system, parent=self)

        #    simulation settings - properties
        # self.integrationMethod = "RKF"  #    self.MBD_system.integrationMethod

        #    update opengl widget every N-th step
        self.step = 0
        self.update_opengl_widget_step_count = 0
        self.update_opengl_widget_every_Nth_step = self.MBD_system.updateEveryIthStep

        self.save_screenshot_step_count = 0
        self.save_screenshot_every_Nth_step = 2 * self.update_opengl_widget_every_Nth_step

        #    info properties
        self.start_time_simulation_info_in_sec_UTC = []
        self.start_time_simulation_info = []
        self.end_time_simulation_info_in_sec_UTC = []
        self.end_time_simulation_info = []
        self.simulation_time_info_in_sec_UTC = []
        self.simulation_time_info = []
        self.stop_time_simulation_info_in_sec_UTC = []
        self.stop_time_simulation_info = []

        self.FLAG = 1
        self.FLAG_contact = 0

    def _solution_containers(self):
        """

        :return:
        """
        #    solution container variable
        self.q0 = self._MBD_system.evaluate_q0()
        self.q_sol_matrix = np.array([self.q0])
        self.t_vector = np.array([[0]])
        self.R_vector = np.array([0])
        self.step_counter = np.array([0])
        self.step_size = np.array([self._MBD_system.Hmax])
        self.energy_data = np.array([self._mechanical_energy(self.q0)])

    def solve(self):
        """
        Solves system of ode with dormand-prince order 5 method with runge-kutta algorithm
        """
        #    copy MBD object
        self._MBD_system = copy.copy(self.MBD_system)
        #    ode fun object
        self.DAE_fun = DAEfun(self._MBD_system, parent=self)

        self.start_solve()

        self.start_time_simulation_info_in_sec_UTC = time.time()
        self.start_time_simulation_info = datetime.datetime.fromtimestamp(self.start_time_simulation_info_in_sec_UTC).strftime("%H:%M:%S %d.%m.%Y")
        print "Simulation started: ", self.start_time_simulation_info

        #    create mass and inverse mass matrix (only once)
        self.DAE_fun.evaluate_M()
        #    create array of initial conditions for differential equations
        if not self.MBD_system.q0_created:
            self.MBD_system.evaluate_q0()

        #   get initial conditions
        q0 = self._MBD_system.evaluate_q0()
        self.FLAG = 1

        #   solution containers
        self._solution_containers()

        self.simulation_id = 0
        #    0 - no contact
        #    1 - contact detected
        #    -1 - contact already happened - reduce integration step
        self.step = 0
        self.h_contact = self._MBD_system.Hmin

        if self.MBD_system.integrationMethod.title() == "ABAM":
            pass

        elif self.MBD_system.integrationMethod.title() == "Runge-Kutta":
            self.solve_ODE_RK(t_0=self._MBD_system.t_0, t_n=self._MBD_system.t_n, q0=q0, absTol=self._MBD_system.absTol, relTol=self._MBD_system.relTol, Hmax=self._MBD_system.Hmax, Hmin=self._MBD_system.Hmin)

        elif self.MBD_system.integrationMethod.title() == "Euler":
            self.solve_ODE_Euler(t_0=self._MBD_system.t_0, t_n=self._MBD_system.t_n, q0=q0, Hmax=self._MBD_system.Hmax)

        else:
            raise ValueError, "Selected integration method not supported! Method: %s"%self.MBD_system.integrationMethod

    def solve_ODE_Euler(self, t_0, t_n, q0, Hmax):
        """
        Euler method for time integration
        :param t_0:
        :param t_n:
        :param q0:
        :param h:
        :return:
        """
        self.t_0 = self._dt = t_0
        self.t_n = t_n
        t = t_0
        w = q0

        self.Hmax = h = Hmax
        self.R = 0

        while self.FLAG == 1:

            if self.stopped:
                self.updateGL(t=t, q=w)
                self.stop_solve()
                self.FLAG = 0

            if t >= self.t_n:
                self.FLAG = 0
                self.finished = True
                self.updateGL(t=t, q=w)

            self.t = t = t + h
            # print "-------------------------------------"
            # print "t =", t, "step =", self.step
            w = w + h * self.DAE_fun.evaluate_dq(h, t, w)
            # print "q =", w
            #    solve contacts here
            # time.sleep(100)
            self.FLAG_contact = self.__evaluate_contacts(t, w)
            # print "self.FLAG_contact =", self.FLAG_contact
            #   evaluate mechanical energy of system
            self._energy_t = self._mechanical_energy(w)
            #   evaluate difference of mechanical energy of a system between this and prevouis time step
            self._energy_delta = self._energy_t - self.energy_data[-1]

            # self.__evaluate_contacts(h, t, w)

            h, t, w = self._track_data(h, t, w)
            # print "track data"

            self._info(t, w)

            #   check time step
            h = self.check_time_step(h, w)

        if self.finished or self.failed:
            self.finished_solve()

        #    save data to file
        if self.MBD_system._save_options.lower() != "discard":
            self.write_simulation_solution_to_file()

    def solve_ODE_RK(self, t_0, t_n, q0, absTol, relTol, Hmax, Hmin):
        """
        RKF - Runge-Kutta-Fehlberg method for time integration
        Based on Numerical Analysis 9th ed Burden & Faires
        Args:
        t_0 -
        t_n -
        q0 -
        absTol -
        Hmax -
        Hmin -
        """
        self.t_0 = self._dt = t_0
        self.t_n = t_n
        t = t_0
        w = q0

#         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" % q0)

        self.Hmax = Hmax
        self.Hmin = Hmin

        h = Hmax
        h_contact = self._MBD_system.Hmin
        self._t_FLAG1 = 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_GL_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:
            # print "-------------------------------------"
            # print "step =", self.step, "contact =", self.FLAG_contact
            # print "t =", t,
            if self.stopped:
                self.updateGL(t=t, q=w)
                self.stop_solve()
                self.FLAG = 0

            if self.FLAG_contact == 1:
                h = h_contact
            elif self.FLAG_contact == 0:
                h = Hmax
            # print "h =", h,
            # print "self.FLAG_contact =", self.FLAG_contact
            # print "--------------------------------"
            # print "h =", h
            # print "t =", t
            # print "w =", w
            # print "self.DAE_fun.evaluate_dq(h, t, w) =", self.DAE_fun.evaluate_dq(h, t, w)
            K1 = h * self.DAE_fun.evaluate_dq(h, t, w)
            K2 = h * self.DAE_fun.evaluate_dq(h, t + (1 / 4.) * h, w + (1 / 4.) * K1)
            K3 = h * self.DAE_fun.evaluate_dq(h, t + (3 / 8.) * h, w + (3 / 32.) * K1 + (9 / 32.) * K2)
            K4 = h * self.DAE_fun.evaluate_dq(h, t + (12 / 13.) * h, w + (1932 / 2197.) * K1 - (7200 / 2197.) * K2 + (7296 / 2197.) * K3)
            K5 = h * self.DAE_fun.evaluate_dq(h, t + h, w + (439 / 216.) * K1 - 8 * K2 + (3680 / 513.) * K3 - (845 / 4104.) * K4)
            K6 = h * self.DAE_fun.evaluate_dq(h, t + (1 / 2.) * h, w - (8 / 27.) * K1 + 2 * K2 - (3544 / 2565.) * K3 + (1859 / 4104.) * K4 - (11 / 40.) * K5)

            self.R = (1. / h) * np.linalg.norm((1 / 360.) * K1 - (128 / 4275.) * K3 - (2197 / 75240.) * K4 + (1 / 50.) * K5 + (2 / 55.) * K6)
            self.R = absTol
            #    if calculated difference is less the absTolerance limit accept the calculated solution
            if self.R <= absTol or self.FLAG_contact == 1:
                self.t = t = t + h
                # print "i =", self.step, "t =", t
                # self._parent.ui.simulation_progressBar.setValue(int(1/self.t))
                # print "t =", t, "h =", h,
                w = w + (25. / 216.) * K1 + (1408. / 2565.) * K3 + (2197. / 4104.) * K4 - (1. / 5.) * K5

#                 if self.step > 220:
#                     print self.step, w
#                     print "-----------------------------------"
                #    check time step size
#                t = self.check_time_step(t, w)
#                print "t_out =", t
#                 print "t = %1.3e" % t  # , "absTol =%10.3E" % R_, "h =%10.3E" % h, "step =", self.step
#                 __print_options = np.get_printoptions()
#                 np.set_printoptions(precision=10, threshold=1000, edgeitems=True, linewidth=1000, suppress=False, formatter={'float': '{: 10.9e}'.format})
#                 np.set_printoptions(**__print_options)

                #    solve contacts here
                # print "t =", t
                # time.sleep(100)
                self.FLAG_contact = self.__evaluate_contacts(t, w)
                # print "self.FLAG_contact =", self.FLAG_contact
                #   evaluate mechanical energy of system
                self._energy_t = self._mechanical_energy(w)
                self._energy_delta = self._energy_t - self.energy_data[-1]

                h, t, w = self._track_data(h, t, w)

                #   evaluate difference of mechanical energy of a system between this and prevouis time step

                self._info(t, w)

                #   check time step
                h = self.check_time_step(h, w)

            #    evaluate error and change step size if needed
            # delta = 0.84 * (absTol / R) ** (1 / 4.)
            #
            #
            # if self.FLAG_contact == 0 or self.FLAG_contact == 1:
            #     if delta <= 0.1:
            #         h = 0.1 * h
            #     elif delta >= 4:
            #         h = 4 * h
            #     else:
            #         h = delta * h
            #
            #     if h > Hmax:
            #         h = Hmax
            #
            # else:
            #     #   new step size - h has to be smaller than the last calculated over impact time
            #     # print "t =", t
            #     # print "h =", h
            #     # print "t+h =", t+h
            #     # print "self._t_FLAG1 =", self._t_FLAG1
            #     if t + h >= self._t_FLAG1:
            #         h = (self._t_FLAG1 - t)/2
            #     # print "h =", h
            #
            #   if end time is reached stop/break integration process
            if t >= self.t_n:
                self.FLAG = 0
                self.finished = True
                self.updateGL(t=t, q=w)
            #
            # #    reduce step size to get to final time t_n
            # elif t + h > t_n:
            #     h = t_n - t
            #
            # #    break integration as minimum step size is exceeded
            # elif h < Hmin and R > absTol:
            #     self.failed = True
            #     self.FLAG = 0
            #     print "t =", t
            #     print "absTol =", absTol
            #     print "R =", R
            #     print "h =", h
            #     h = Hmin
            #     self.error_time_integration_signal.signal_time_integration_error.emit()
            #
            #     print "Hmin exceeded! Procedure failed!"
            #    time step after contact is constant and very small value
            if self.FLAG_contact == 1:
                h = self.Hmin
                # if h_after_contact < 10 * Hmin:
                #     h = 10 * Hmin
                # else:
                #     h = Hmax

            #    integration finished - end time reached successfully
            if self.finished or self.failed or self.stopped:
                self.finished_solve()

        #    save data to file
        self.write_simulation_solution_to_file()

    def _info(self, t, w):
        """

        :return:
        """
        #    update coordinates and angles of all bodies
        self.__update_coordinates_and_angles_of_all_bodies(w)

        #    update opengl display
        self.updateGL(t, w)

        # self.step += 1
        # step_counter = np.append(step_counter, self.step)

        self.update_opengl_widget_step_count += 1
        self.save_screenshot_step_count += 1

        #    step number signal
        self.step_signal.signal_step.emit(self.step)

        #    energy data signal
        self.energy_signal.signal_energy.emit(self._energy_t, self._energy_delta)

    def _track_data(self, h, t, q):
        """

        :return:
        """
        #    save values at next time step to matrix of solution (q_matrix)
        if self.FLAG_contact == 0 or self.FLAG_contact == 1:
            #   append solution at i-th time to solution matrix
            self.q_sol = self.q_sol_matrix = np.vstack((self.q_sol_matrix, np.array(q)))

            self.step_size = np.vstack((self.step_size, h))
            self.step += 1
            step_num = self.step

            #   append current step number to step counter history array
            self.step_counter = np.append(self.step_counter, self.step)
            #    add to vector
            self.t_vector = np.vstack((self.t_vector, t))
            self.R_vector = np.vstack((self.R_vector, self.R))
            #   append current mechanical energy to array
            self.energy_data = np.append(self.energy_data, self._energy_t)

            for contact in self.MBD_system.contacts:
                contact._track_data(self.step, h, t, q)

        #    reduce step size and continue integration from previous step
        elif self.FLAG_contact == -1:
            #    go to one before last solution
            q = self.q_sol_matrix[-1, :]
            #    store time that is too large
            self._t_FLAG1 = t
            t = self.t_vector[-1, 0]  # , 0

            #    reduce step size
            h = 0.5 * h
            # self.step -= 1
            # step_num  = self.step
            # step_counter[-1] = self.step

            self.energy_data[-1] = self._energy_t

        return h, t, q

    def __evaluate_contacts(self, t, q):
        """
        Function solves contacts. Finds overlap pairs of (sub)AABB and calculates actual distances between node
        and line (edge). If distance is below userdefined limit contact is present and contact equations are solved.
        :type self: object
        Args:
            q    vector of positions and velocities (translational and rotational)
        Returns:
            q_   vector of new calculated velocities (positions are equal before and after contact
            status - 0 - contact is not detected continue with integration to next time step
                     1 - contact is detected (has happened) return to previous time step solution and split time step
                         size
                     2 - contact is detected (will happen) split time step size
        Raises:
            None
        """
        # print "---------------------------------"
        # print "t =", t, "step =", self.step,
        self.__update_coordinates_and_angles_of_all_bodies(q)

        self.contact_status_list = []
        #    check for contact of every contact pair
        for contact in self.MBD_system.contacts:
            contact.data_tracker(t, self.step)
            # print "contact._contact_point_found =", contact._contact_point_found, "t =", t
            if not contact._contact_point_found:
                #    function recursively loops through all potential AABB objects in AABB tree of each body
                #    and if two AABB objects overlap, a new overlap object is created
                #    that has both overlapping AABB objects
                #   general contact
                if contact._type == "General":
                    #   adds simulation data to contact object
                    #   reset to empty list a contact object attribute of list of overlap pairs,
                    #   as this is not possible in the next line (function) due to the recursion
                    contact.AABB_list_of_overlap_pairs = []
                    #   check for overlap and if overlap is present build a overlap pair object
                    contact.check_for_overlap(q, contact.AABB_i, contact.AABB_j)

                    #   if list of overlap object pairs is not empty, check for contact
                    if contact.AABB_list_of_overlap_pairs is not []:
                        status = contact.check_for_contact(q)
                        self.contact_status_list.append(status)
                    else:
                        contact.no_overlap()

                #   revolute clearance joint contact
                elif contact._type.lower() == "revolute clearance joint" or contact._type.lower() == "contact sphere-sphere" or contact._type.lower() == "contact plane-sphere" or contact._type.lower() == "pin-slot clearance joint linear":
                    status = contact.check_for_contact(q)
                    # print "t =", t, "status(check_for_contact) =", status
                    self.contact_status_list.append(status)

                else:
                    self.FLAG = 0
                    QtGui.QMessageBox.critical(self._parent, "Error!", "Contact type not correct: %s"%contact._type+". \nDefine correct contact type!", QtGui.QMessageBox.Ok)
                    raise ValueError, "Contact type not correct: %s"%contact._type, "\n Define correct contact type!"
            else:
                #    adds simulation data to contact object as this is not possible in the next line because of the recursion
                # print "contact.update_status()"
                # print "contact_update() @ solve_ODE"
                status = contact.contact_update(self.step, t, q)
                # print "status (from contact_update) =", status
                self.contact_status_list.append(status)

            self.contact_status_list = np.array(self.contact_status_list)
            # print "self.contact_status_list =", self.contact_status_list

            #    no contacts
            if (self.contact_status_list == 0).all():
                FLAG_contact = 0

                callerframerecord = inspect.stack()[0]      # 0 represents this line
                                                            # 1 represents line at caller
                frame = callerframerecord[0]
                # print "NO CONTACT"
                # print "simulation sleep"

                info = inspect.getframeinfo(frame)
                # print "file:", info.filename
                # print "function:", info.function+"()"
                # time.sleep(100)
                return FLAG_contact

            #    contact
            if (self.contact_status_list == 1).any():
                FLAG_contact = 1
                # logging.getLogger("DyS_logger").info("Contact detected at simulation time:%s \nbody_i=%s \nbody_j=%s", t, self.MBD_system.bodies[contact.body_id_i]._name, self.MBD_system.bodies[contact.body_id_j]._name)
                # logging.getLogger("DyS_logger").info("Contact detected at simulation time:%s "%t)
                #   repaint opengl widget

#                 self.repaintGL_signal.signal_repaintGL.emit()

                #   solve contacts - construct contact forces
                # self.DAE_fun.solve_contacts(t, q)

                # logging.getLogger("DyS_logger").info("Contact calculation finished")
                return FLAG_contact

            #    contact has already happened - reduce time step
            if (self.contact_status_list == -1).any():
                FLAG_contact = -1  # 0-no contact, 1-contact has already happened - reduce time step
                return FLAG_contact

        else:
            FLAG_contact = 0
            return FLAG_contact

    def _mechanical_energy(self, q):
        """

        """
        #    predefine zero array
        _energy = np.zeros(self.MBD_system.number_of_bodies)

        #   energy of all bodies
        for i, body in enumerate(self.MBD_system.bodies):
            _q = q2R_i(q, body.body_id)
            _dq = np.append(q2dR_i(q, body.body_id), q2dtheta_i(q, body.body_id))

            #   body energy
            # body_energy = 0.5 * (body.mass * (_dq**2) + body.J_zz * (_omega**2)) + (body.mass * self.MBD_system.gravity * _q[1])
            body_energy = body.mechanical_energy(q=_q, dq=_dq, gravity=self.MBD_system.gravity)
            _energy[i] = body_energy

        #   energy of normal contact forces
        _energy_of_contacts = np.zeros(len(self.MBD_system.contacts))
        # for i, contact in enumerate(self.MBD_system.contacts):
        #     _energy_of_contacts[i] = contact.mechanical_energy()

        #   total mechanical energy
        energy = np.sum(_energy) + np.sum(_energy_of_contacts)

        return energy

    def check_time_step(self, h, q):
        """

        """
        # _t_max = []
        # for contact in self.MBD_system.contacts:
        #     if contact.AABB_list_of_overlap_pairs != []:
        #         for body_id in contact.contact_body_id_list:
        #
        #             _t = self.MBD_system.bodies[body_id].skin_thickness / np.linalg.norm(q2dR_i(q, body_id) + q2dtheta_i(q, body_id) * self.MBD_system.bodies[body_id].uP_i_max, ord=2)
        #             _t_max.append(_t)
        #
        #         t_max = min(_t_max)
        #         if t > t_max:
        #             return t_max
        #         else:
        #             return t
        #     else:
        #         return t
        # if h < self.Hmin:
        #     h = self.Hmin
        if self.FLAG_contact == 1:
            h = self.h_contact
        elif self.FLAG_contact == -1:
            h = h
        else:
            h = self.Hmax

        return h

    def write_simulation_solution_to_file(self):
        """
        Function writes solution data to solution data object
        """
        print "write_simulation_solution_to_file()"
        solution_data = self.collect_solution_data()

        #   write solution data and info to solution data object
        self._solution_data.set_filetype(self.MBD_system._solution_filetype)

        self.solution_filename = 'solution_data_%02d'%self.simulation_id#+self.MBD_system._solution_filetype

        if self.MBD_system._save_options == "save to new":
            #   check filename if already exists
            self.solution_filename = check_filename(self.solution_filename)

        #   set solution data filename
        self._solution_data.setName(self.solution_filename)

        #   add data to object attribute
        self._solution_data.add_data(solution_data)
        self._solution_data.finished = True

        # print "exe1"
        # print "self.MBD_system._solution_save_options =", self.MBD_system._solution_save_options
        if self.MBD_system._solution_save_options != "discard":
            print "exe2"
            #   write data to file
            self._solution_data.write_to_file()

            #   emit signal
            # self.solution_signal.solution_data.emit(id(self._solution_data), self._solution_data._filename)

            #   write contact values of every simulation time step to file
            for contact in self.MBD_system.contacts:
                if contact._solution_save_options != "discard":
                    contact.write_to_file()

    def collect_solution_data(self):
        """

        :return:
        """
        #   reshape data to join in one matrix
        #   step
        _step = np.array([self.step_counter]).T
        #   energy
        _energy_data = np.array([self.energy_data]).T
        #   add all solution data to one variable
        solution_data = np.hstack((_step, _energy_data, self.R_vector, self.step_size, self.t_vector, self.q_sol_matrix))

        return solution_data

    def save_solution_data(self):
        """

        :return:
        """
        data = self.collect_solution_data()
        self._solution_data.add_data(data)

    def start_solve(self):
        """
        Start solver (time integration process)
        """
        self.simulation_id = self.__simulation_id.next()

        #   create solution data object to store data at each simulation start
        self._solution_data = SolutionData(MBD_system=self.MBD_system)#parent=self.MBD_system.Solution
        print "self._solution_data._name =", self._solution_data._name
        self.MBD_system.solutions.append(self._solution_data)

        logging.getLogger("DyS_logger").info("Simulation started, simulation id: %s"%self.simulation_id)

        self.running = True
        self.stopped = False
        self.finished = False

    def stop_solve(self):
        """
        Stop solver (time integration process)
        """
        self.stopped = True
        self.running = False

        self.stop_time_simulation_info_in_sec_UTC = time.time()
        self.stop_time_simulation_info = datetime.datetime.fromtimestamp(self.stop_time_simulation_info_in_sec_UTC).strftime("%H:%M:%S %d.%m.%Y")

        logging.getLogger("DyS_logger").info("Simulation stopped by user at simulation time:%s", self.t)

    def finished_solve(self):
        """
        Method sets some parameters when integration process is finished
        :return:
        """
        if self.finished:
            self.save_solution_data()
            self.solution_signal.solution_data.emit(id(self._solution_data), self._solution_data._name)
            logging.getLogger("DyS_logger").info("Simulation finished successfully!")
            self.finished_signal.signal_finished.emit("Finished")
        else:
            logging.getLogger("DyS_logger").info("Simulation failed!")

        #   set booleans
        self.finished = True
        self.running = False

    def load_simulation_solution_from_file(self, filename):
        """
        Function load solution_data from file.
        """
        self.finished_signal.signal_finished.emit("Animation")
        if os.path.exists(filename):
            self.solution_data = np.loadtxt(str(filename), skiprows=2)
            return self.solution_data

    def __update_coordinates_and_angles_of_all_bodies(self, q):
        """
        Function updates MBD_system data before display
        """
        self.MBD_system.update_coordinates_and_angles_of_all_bodies(q)

    def updateGL(self, t, q):
        """
        Update opengl widget at preset time steps
        """
        #   update display on every i-th step
        if self._parent._update_display_type == "step":
            if self.update_opengl_widget_step_count == self.update_opengl_widget_every_Nth_step or self.finished or self.stopped:
                self._updateGL()

                self.time = t

                self.save_updated_GL_screenshot_to_file(self.time)

                #    reset step counter to update opengl widget
                self.update_opengl_widget_step_count = 0

        #   update display on simulation time interval dt
        if self._parent._update_display_type == "dt":
            _t = t - self._dt
            if _t >= self._parent._dt:
                self._updateGL(t, self.step)

                #   set new value
                self._dt = t


        return None

    def _updateGL(self, t, step):
        """

        :return:
        """
        #    update opengl widget
        self.MBD_system.update_simulation_properties(time=t, step_num=step)
        #   emit signal
        self.repaintGL_signal.signal_repaintGL.emit()

    def save_updated_GL_screenshot_to_file(self, t):
        """

        """
        if self.MBD_system.save_screenshots:
            if (self.save_screenshot_step_count == self.save_screenshot_every_Nth_step) or (t == self.t_0) or (self.finished):

                self.screenshot_filename_abs_path = os.path.join(self.MBD_system.saved_screenshots_folder_abs_path, str("step=" + "%010d" % self.step))
                self.save_screenshot_signal.signal_saveScreenshot.emit()
                self.save_screenshot_step_count = 0

    def restore_initial_condition(self):
        """
        Function restores initial conditions and displays it with opengl widget.
        """
        print "restore_initial_condition()"
        self.step = 0
        self.MBD_system._restore_initial_conditions()

        self.repaintGL_signal.signal_repaintGL.emit()
        self.updateGL(t=0, q=self.MBD_system.q0)