Esempio n. 1
0
class DynamicAnalysis(object):
    """
    classdocs
    """
    __simulation_id = itertools.count(0)

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

        #   parent
        self._parent = parent

        #   states of simulation
        self.running = False
        self.stopped = False
        self.finished = False
        self.failed = False
        self._error = False
        self.errorControl = True

        #   signals
        self.step_signal = StepSignal()
        self.finished_signal = FinishedSignal()
        self.refresh_signal = RefreshSignal()
        self.energy_signal = EnergySignal()
        self.error_time_integration_signal = ErrorTimeIntegrationSignal()
        self.filename_signal = SolutionFilenameSignal()
        self.save_screenshot_signal = SaveScreenshot()
        self.solution_signal = SolutionSignal()
        self.signal_simulation_status = SignalSimulationStatus()

        #   display active
        self._active_scene = True

        #   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)

        #   define simulation attributes
        self.simulation_id = None
        self.h_contact = None
        self.t_0 = 0.
        self.t_n = None
        self.stepsNumber = None
        self.absTol = None
        self.relTol = None
        self.absError = None
        self.relError = None
        self.progress = 0
        self._energy_t = 0.
        self._energy_delta = 0.
        self.h_min_level = None
        self.h_max_level = None
        self.h_contact_level = None

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

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

        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
        self.FLAG_contact_finish = 0

        #   level of integration step size - time
        self.h_level = 0
        self.dh = 0
        self._steps_after_contact = 0
        self._dh_constant_steps = 0

        #   solution data settings
        #   write to file during simulation
        self._append_to_file_every_Nth_step = 20
        self._append_to_file_step = 0
        self._append_to_file_during_simulation = True
        self._append_to_file_keep_last_Nth_steps_in_memory = 10

    def _solution_containers(self):
        """
        Function initializes solution containers object attributes to save solution data during numerical integration process
        :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_vector = np.array([0]).astype(int)
        self.step_size_vector = np.array([self._MBD_system.Hmax])
        self.h_level_vector = np.array([0]).astype(int)
        self.energy_data_vector = np.array([self._mechanical_energy(self.q0)])
        self.contact_status_vector = np.array([0]).astype(int)

    def start_solve(self):
        """
        Start solver (time integration process)
        """
        #   set step size
        self.Hmin = self._MBD_system.Hmin
        self.Hmax = self._MBD_system.Hmax
        self.Hcontact = self._MBD_system.Hcontact
        self.Houtput = self._MBD_system.Houtput

        #   set step level
        self.h_min_level = 0
        self.h_max_level = int(np.trunc(np.log2(self.Hmax /
                                                self.Hmin)))  #np.trunc
        self.h_contact_level = np.trunc(np.log2(self.Hmax / self.Hcontact))
        print "self.h_contact_level =", self.h_contact_level
        self.h_output_level = np.trunc(np.log2(self.Hmax / self.Houtput))

        #   solution id
        self.simulation_id = self.__simulation_id.next()

        #   create solution data object to store data at each simulation start
        self._solution_data = SolutionData(MBD_item=self.MBD_system)
        #   clear temp solution file
        self._solution_data._clear_file()

        self.MBD_system.solutions.append(self._solution_data)

        self.signal_simulation_status.signal_simulation_status.emit("Running")
        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) - interput by user
        """
        #   get solution data to one variable
        solution_data = self.collect_solution_data()
        #   append solution data to file
        self._solution_data._append_data_to_temp_file(solution_data[0:-1, :])

        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")

        self.signal_simulation_status.signal_simulation_status.emit("Stopped")
        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:
        """
        self._refresh(t=self.t, step=self.step)
        if self.finished:
            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()
            self.signal_simulation_status.signal_simulation_status.emit(
                "Finished")

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

    def simulation_failed(self):
        """

        :return:
        """
        print "simulation_failed()"
        self.error_time_integration_signal.signal_time_integration_error.emit()
        self.signal_simulation_status.signal_simulation_status.emit("Failed")
        if self._error or self.failed:
            logging.getLogger("DyS_logger").info("Simulation failed!")
        if self.DAE_fun.error:
            logging.getLogger("DyS_logger").info(
                "Violation of kinematic constraint!")

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

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

        #    update display
        self.refresh(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)

        #   simulation progress
        if self.t_n is not None:
            self.progress = t / self.t_n
        else:
            self.progress = self.step / self.stepsNumber

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

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

            self.step_size_vector = np.append(self.step_size_vector, h)
            self.step += 1
            step_num = self.step

            #   append current step number to step counter history array
            self.step_counter_vector = np.append(self.step_counter_vector,
                                                 self.step)
            #    add to vector
            self.t_vector = np.append(self.t_vector, t)
            self.R_vector = np.append(self.R_vector, self.absError)
            #   append current mechanical energy to array
            self.energy_data_vector = np.append(self.energy_data_vector,
                                                self._energy_t)

            #   contact status
            self.contact_status_vector = np.append(self.contact_status_vector,
                                                   self.FLAG_contact)

            #   step size level
            self.h_level_vector = np.append(self.h_level_vector, self.h_level)

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

            for force in self.MBD_system.forces:
                force._track_data(self.step, h, t)

            for spring in self.MBD_system.springs:
                spring._track_data(self.step, h, t)

            for joint in self.MBD_system.joints:
                joint._track_data(self.step, h, t)

            for measure in self.MBD_system.measures:
                measure._track_data(self.step, h, t, q)

            #   check is step number is reached to append data to file
            if self._append_to_file_step == self._append_to_file_every_Nth_step - 1 and self._append_to_file_during_simulation:
                #   collect solution data to one variable
                solution_data = self.collect_solution_data()
                #   append solution data to file
                self._solution_data._append_data_to_temp_file(solution_data[
                    0:self._append_to_file_keep_last_Nth_steps_in_memory, :])
                # print "solution data appended!"
                #   remove all but last value in array/matrix
                self._reset_solution_data_after_append_to_temp_file()

                #   counter
                self._append_to_file_step = 0
            else:
                self._append_to_file_step += 1

        #    reduce step size and continue integration from previous step
        elif self.absError > self.absTol:
            #    go to one before last solution
            q = self.q_sol_matrix[-1, :]
            #   remove last stored value in matrix
            # self.q_sol_matrix = np.delete(self.q_sol_matrix, -1, axis=0)
            #    store time that is too large
            self._t_FLAG1 = t
            t = self.t_vector[-1]  # , 0

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

            self.energy_data_vector[-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
        """
        #   predefine array of zeros
        self.contact_status_list = np.zeros(len(self.MBD_system.contacts),
                                            dtype="int")
        #    check for contact of every contact pair
        for i, contact in enumerate(self.MBD_system.contacts):
            # 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._contact_type in ["general", "roughness profile"]:
                    #   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 != []:
                        self.contact_status_list[
                            i] = contact.check_for_contact(self.step, t, q)
                    else:
                        contact.no_overlap(self.step, t, q)

                #   clearance joints of contact
                elif contact._contact_type.lower() in contact._contact_types:
                    self.contact_status_list[i] = contact.check_for_contact(
                        self.step, t, q)

                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:
                pass
                #    adds simulation data to contact object as this is not possible in the next line because of the recursion
                self.contact_status_list[i] = contact.contact_update(
                    self.step, t, q)

        #    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)

            if self.contact_status_vector[
                    -1] == 1 and self.FLAG_contact_finish == 1:
                FLAG_contact = -1
                self.FLAG_contact_finish -= 1

            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

        #    contact
        if (self.contact_status_list == 1).any():
            FLAG_contact = 1
            self.FLAG_contact_finish = 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 - evaluate contact forces
            # self.DAE_fun.solve_contacts(t, q)

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

        else:
            FLAG_contact = 0

        return FLAG_contact

    def _mechanical_energy(self, q):
        """

        """
        energy = self.MBD_system.evaluate_mechanical_energy(q=q)
        return energy

    def check_time_step_TODO(self, t, h, w):
        """

        :param t:
        :param h:
        :param w:
        :return:
        """
        error = False
        #   continue with current time step - no error
        if (self.absError <= self.absTol) and not (self.DAE_fun.check_C(w, t)):
            # print "NO ERROR"
            self.dh = 0
            if self.FLAG_contact == 0:
                # print "FLAG = 0"
                if self.contact_status_vector[-1] == 1:
                    self.h_level = int(max(self.h_level_vector))

                if self.h_level > 0:
                    self.dh = -1

            if self.FLAG_contact == +1:
                # print "FLAG = 1"
                self.h_level = self.h_contact_level

            if self.FLAG_contact == -1:
                # print "FLAG = -1"
                self.dh = +1

        else:
            # print "ERROR"
            # if self.FLAG_contact == 0:
            #     self.dh = 0
            #
            # if self.FLAG_contact == +1:
            #     print "FLAG = 1"
            #     self.h_level = self.h_contact_level
            if self.FLAG_contact in [-1, +1]:
                # print "self.FLAG_contact =", self.FLAG_contact
                self.dh = +1

        # print "self.h_level =", self.h_level
        # print "self.dh =", self.dh
        self.h_level += self.dh
        # print "self.h_level =", self.h_level
        h = self._evaluate_time_step(self.h_level)

        #   time step size is limited by max value
        if h > self.Hmax:
            h = self.Hmax
            self.h_level = 0

        #   value of time step is smaller than the limit - break computation and raise error
        if h < self.Hmin:
            error = True
            print "Hmin =", self.Hmin
            print "Suggested value is h =", h
            print "absError =", self.absError
            print "absTol =", self.absTol
            print "C(q, t) =", self.DAE_fun.evaluate_C(w, t)
            raise ValueError, "Hmin exceeded!"

        return h, error

    def check_time_step(self, t, h, w):
        """
        Function checks time step size
        """
        # print "self.contact_status_vector[-1]@check_time_step()=", self.contact_status_vector[-1]
        error = False
        self.dh = 0

        #    if at least one contact is present in the MBD system
        if self.FLAG_contact == 1:
            self.dh = 0
            # print 'h_level=', self.h_level
            #   condition to increase speed for calculationg contact conditions
            if self._dh_constant_steps == 0:
                if self.h_level - 1 >= self.h_contact_level:
                    for h_lev in np.arange(self.h_level):
                        if np.around((self.t / self.Hmax * 2**(h_lev)),
                                     decimals=5) % 1 == 0:
                            # dh = -self.h_level + h_lev
                            dh = -1
                            self.h_level += dh
                            if self.h_level < self.h_contact_level:
                                self.h_level = self.h_contact_level
                            break
                else:
                    self.h_level = self.h_contact_level
            else:
                self._dh_constant_steps -= 1

        #    at least one contact has current initial penetration depth larger than initial minimum specified depth by user
        elif self.FLAG_contact == -1 or self.absError > self.absTol:
            if self.h_level + 1 <= self.h_max_level:
                self.dh = 1
                self._dh_constant_steps = 8

            else:
                self.dh = 0
                error = True

                print "Hmin =", self.Hmin
                print "Suggested value is h =", h
                print "absError =", self.absError
                print "absTol =", self.absTol
                print "C(q, t) =", self.DAE_fun.evaluate_C(w, t)

                print Warning, "Hmin exceeded!"

        #   contact is finished and the integration is started from previous time step with smalled step size
        elif self.contact_status_vector[-1] == 1:
            self.h_level = int(max(self.h_level_vector))
            # print 'ELIF h_level', self.h_level

        #    no contact is present at current time step, integration step size can be increased
        else:
            if self._dh_constant_steps == 0:
                if self.h_level - 1 >= self.h_min_level:
                    # print "np.arange(self.h_level) =", np.arange(self.h_level)
                    for h_lev in np.arange(self.h_level):
                        if np.around((self.t / self.Hmax * 2**(h_lev)),
                                     decimals=5) % 1 == 0:
                            # dh = self.h_level - h_lev
                            dh = 1

                            if self.step < self._steps_after_contact:
                                _n = self.step

                            else:
                                _n = self._steps_after_contact

                            _status = self.contact_status_vector[-_n - 1:-1]

                            if (_status == np.zeros(_n)).all():
                                self.dh = -dh
                            else:
                                self.dh = 0

                            break
            else:
                self._dh_constant_steps -= 1

        self.h_level += self.dh

        h = self._evaluate_time_step(self.h_level)

        #   time step size is limited by max value
        if h > self.Hmax:
            h = self.Hmax
            self.h_level = 0

        if h < self.Hmin and self.FLAG_contact != 1:
            h = self.Hmin
            error = True
            print "-----------------------------------------"
            for contact in self.MBD_system.contacts:
                print "contact id =", contact.contact_id
                print "delta =", contact._delta

            print "Hmin =", self.Hmin
            print "Suggested value is h =", h
            print "absError =", self.absError
            print "absTol =", self.absTol
            print "C(q, t) =", self.DAE_fun.evaluate_C(w, t)

            print Warning, "Hmin exceeded!"
            #   multiple of time step
#             m = t * (2.**self.t_level) / self.Hmax

#             next_level = fractions.gcd((2**self.t_level), m)
# print "next_level =", next_level
# time.sleep(100)

        return h, error

    def _evaluate_time_step(self, level):
        """

        """
        h = self.Hmax / (2**level)
        return h

    def write_simulation_solution_to_file(self):
        """
        Function writes solution data to solution data object
        """
        print "write_simulation_solution_to_file()"
        #   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

        #    add to temp file
        data = self.collect_solution_data()
        self._solution_data._append_data_to_temp_file(data)

        #    read from temp file
        if os.path.isfile(self._solution_data._temp_filename):
            self._solution_data._solution_data_from_temp_file()

        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.finished = True

        # print "self.MBD_system._solution_save_options =", self.MBD_system._solution_save_options
        if self.MBD_system._solution_save_options != "discard":
            #   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()

        for joint in self.MBD_system.joints:
            if joint._solution_save_options != "discard":
                joint.write_to_file()

    def collect_solution_data(self):
        """

        :return:
        """
        #   join in one ndarray (matrix)
        solution_data = np.hstack(
            (np.array([self.step_counter_vector]).T,
             np.array([self.energy_data_vector]).T,
             np.array([self.R_vector]).T, np.array([self.step_size_vector]).T,
             np.array([self.t_vector]).T, np.array([self.h_level_vector]).T,
             np.array([self.contact_status_vector]).T, self.q_sol_matrix))

        return solution_data

    def _reset_solution_data_after_append_to_temp_file(self):
        """
        Function removes all elements in array except last item (row)
        :return:
        """
        for data_name in [
                "step_counter_vector", "energy_data_vector", "R_vector",
                "step_size_vector", "t_vector", "h_level_vector",
                "contact_status_vector"
        ]:
            data = getattr(self, data_name)

            new_data = np.array(
                data[self._append_to_file_keep_last_Nth_steps_in_memory:])

            setattr(self, data_name, new_data)

        #   solution matrix
        new_data = self.q_sol_matrix[
            self._append_to_file_keep_last_Nth_steps_in_memory:, :]
        self.q_sol_matrix = new_data

    def save_solution_data(self):
        """

        :return:
        """
        if os.path.isfile(self._solution_data._temp_filename):
            self._solution_data._solution_data_from_temp_file()
        # self._solution_data.add_data(data)

    def load_simulation_solution_from_file(self, filename):
        """
        Function load solution_data from file.
        """
        # self.finished_signal.signal_finished.emit("Animation")
        self.signal_simulation_status.signal_simulation_status.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, t, q):
        """
        Function updates MBD_system data before display
        """
        # self.MBD_system.update_coordinates_and_angles_of_all_bodies(q)
        self.MBD_system.update_vtk_data(t, q)

    def refresh(self, t, q):
        """
        Update visualization widget at preset time steps
        """
        if self._active_scene:
            #   update display on every i-th step
            if self._parent._update_display_type == "step":
                self.update_opengl_widget_step_count += 1
                if self.update_opengl_widget_step_count == self.update_opengl_widget_every_Nth_step or self.finished or self.stopped:
                    self._refresh(t, self.step)

                    self.time = t

                    self.save_updated_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":
                _dt = t - self._dt
                if _dt >= self._parent._dt:
                    self._refresh(t, self.step)

                    #   set new value
                    self._dt = t

        return None

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

        :return:
        """
        #    update visualization widget
        self.MBD_system.update_simulation_properties(time=t, step_num=step)

        #   emit signal
        if self._active_scene:
            self.refresh_signal.signal_refresh.emit()

    def save_updated_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.
        """
        self.step = 0
        self.MBD_system._restore_initial_conditions()
        self.step_signal.signal_step.emit(self.step)
        self.energy_signal.signal_energy.emit(0., 0.)

        self.MBD_system.time = 0.
        self.MBD_system.step_num = 0

        self.refresh_signal.signal_refresh.emit()
        self.refresh(t=0, q=self.MBD_system.q0)
Esempio n. 2
0
class KinematicAnalysis(DynamicAnalysis):
    """
    classdocs
    """
    def __init__(self, MBD_system, parent=None):
        """
        Constructor
        """
        super(KinematicAnalysis, self).__init__(MBD_system, parent)
        #   parent
        self._parent = parent

        #    DAE fun object
        self.DAE_fun = DAEfun(self._MBD_system, parent=self)

    def solve(self):
        """
        Solves a kinematic system
        """
        print "solve()"
        # pprint(vars(self))

        #   start solve
        self.start_solve()

        self.simulation_id = 0
        self.FLAG = 1

        # scipy.optimize.newton()

        t = 0.
        h = self._MBD_system.Hmax
        self.t_n = self.MBD_system.t_n

        #   initial approximation
        q = self.q_sol = self.MBD_system.evaluate_q0()
        #   use  positions vector (translational and rotational)
        q = q[0:len(q) / 2]
        #   us
        #   solution containers
        self._solution_containers()

        #   size of C, C_q, C_t vectors, matrix
        self.DAE_fun._C_q_size()

        #   options to track data
        self.q_sol_matrix = np.array([q])
        self._energy_t = 0
        self._energy_delta = np.nan

        #   check before run
        if not self.DAE_fun.check_C(q, t):
            self.FLAG = 1
        else:
            print "Error found before simulation run!"
            self.FLAG = 0
            self.finished_solve()

        #   kinematic analysis
        while self.FLAG == 1:
            # print "----------------------------------------"
            # print "t =", t
            if self.stopped:
                # self.update_GL_(t=t, q=w)
                self.stop_solve()
                self.FLAG = 0

            if t >= self.t_n:
                self.FLAG = 0
                self.finished = True
                print "finished!"
                # self.update_GL_(t=t, q=w)

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

            #   evaluate C vector
            # C = self.DAE_fun.evaluate_C(q, t)
            # print "C =", len(C)
            # print C

            # C_q = self.DAE_fun.evaluate_C_q(q)
            # print "C_q ="
            # print C_q
            # print "q (in) =", q
            q = scipy.optimize.fsolve(self.DAE_fun.evaluate_C,
                                      q,
                                      args=(t),
                                      fprime=self.DAE_fun.evaluate_C_q,
                                      xtol=self.MBD_system.TOL_dq_i,
                                      maxfev=50)
            # q = scipy.optimize.newton(self.DAE_fun.evaluate_C, q, fprime=self.DAE_fun.evaluate_C_q, tol=self.MBD_system.TOL_dq_i, maxiter=50)
            # print "q (out) =", q

            #   evaluate C_q matrix
            C_q = self.DAE_fun.evaluate_C_q(q, t)
            # print "C_q ="
            # print C_q
            #   evaluate C_t vector
            C_t = self.DAE_fun.evaluate_C_t(q, t)
            # print "C_t =", C_t
            #   solve linear system of equations for dq
            dq = np.linalg.solve(C_q, -C_t)

            #   assemble new q vector q=[q, dq]
            _q = np.concatenate([q, dq])
            self.q_sol = _q
            #   evaluate vector Q_d
            Q_d = self.DAE_fun.evaluate_Q_d(_q)

            #   solve linear system of equations for ddq
            ddq = np.linalg.solve(C_q, Q_d)

            #   track data
            self.R = np.nan
            self._track_data(h, t, q)

            self._info(t, q)

            #   increase time step
            t = t + h
            self.t = t

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

        #    save data to file
        self.write_simulation_solution_to_file()