コード例 #1
0
 def __init__(self):
     self.config_manipulator = ConfigManipulator()
     self.max_speed = float(
         self.config_manipulator.read(ConfigFields.maxSpeed))
     self.size = (float(self.config_manipulator.read(ConfigFields.size)),
                  float(self.config_manipulator.read(ConfigFields.size)))
     self.box_size = float(
         self.config_manipulator.read(ConfigFields.boxSize))
     self.max_particles_count = float(
         self.config_manipulator.read(ConfigFields.particleAmount))
コード例 #2
0
 def __init__(self):
     self.configparser = ConfigManipulator()
     self.size = int(self.configparser.read(ConfigFields.size))
     self.box_size = int(self.configparser.read(ConfigFields.boxSize))
     self.max_speed = int(self.configparser.read(ConfigFields.maxSpeed))
     self.particle_amount = int(
         self.configparser.read(ConfigFields.particleAmount))
     self.time = int(self.configparser.read(ConfigFields.time))
     self.frames = self.unpickle()
     self.max_box_speed = math.floor(self.max_speed / self.box_size)
     self.max_box_size = math.floor(self.size / self.box_size)
コード例 #3
0
    def __init__(self):
        self.config = ConfigManipulator()
        self.particles_amount = int(
            self.config.read(ConfigFields.particleAmount))
        self.particle_size = int(self.config.read(
            ConfigFields.particleSize)) * 265 / int(
                self.config.read(ConfigFields.size))
        self.box_size = int(self.config.read(ConfigFields.boxSize))

        self.figure, self.axes = mpl.subplots()
        self.anim = None
        self.dpi = 500
        self.path = "VXAnimation.mp4"

        self.frame_number = 1
        self.frames = self.unpickle()

        print("Drawing VX chart")
コード例 #4
0
 def __init__(self):
     self.time_delta = float(ConfigManipulator().read(
         ConfigFields.timeDelta))
     self.size_x = float(ConfigManipulator().read(ConfigFields.size))
     self.size_y = float(ConfigManipulator().read(ConfigFields.size))
     self.maximal_distance_as_collision = float(ConfigManipulator().read(
         ConfigFields.maximalDistanceAsCollision))
     self.maximal_timedelta_as_colliding = float(ConfigManipulator().read(
         ConfigFields.maximalTimeDeltaAsColliding))
     self.particle_size = float(ConfigManipulator().read(
         ConfigFields.particleSize))
     self.time = int(ConfigManipulator().read(ConfigFields.time))
コード例 #5
0
    def get_box_velocities(self) -> (int, int):
        """
        Same as above but for speed
        :return: box speed tuple
        """
        box_size = int(ConfigManipulator().read(ConfigFields.boxSize))
        if self.vX > 0:
            box_x = math.floor(self.vX / box_size)
        else:
            box_x = math.ceil(self.vX / box_size)

        if self.vY > 0:
            box_y = math.floor(self.vY / box_size)
        else:
            box_y = math.ceil(self.vY / box_size)

        return box_x, box_y
コード例 #6
0
    def get_box_position(self) -> (int, int):
        """
        Position getter, but in coordinates described as more generalized.
        Under assumptions one box has side length of k
        we calculate x component of box position as quotient of x position and k
        ceiled if x was < 0 and floored id x > 0.
        Same for y
        :return: box pos tuple
        """
        box_size = int(ConfigManipulator().read(ConfigFields.boxSize))
        if self.x > 0:
            box_x = math.floor(self.x / box_size)
        else:
            box_x = math.ceil(self.x / box_size)

        if self.y > 0:
            box_y = math.floor(self.y / box_size)
        else:
            box_y = math.ceil(self.y / box_size)

        return box_x, box_y
コード例 #7
0
    def create_from_file(self, file: str) -> SimFrame:
        """
        Private subfunction, bla bla bla
        :param file: csv file containing data for particles
        :return: SimFrame
        """
        print("First frame will be read from file")
        file_suffix = file.split(".")[-1]
        if file_suffix != "csv":
            raise ResourceWarning("Wrong file format")
        else:
            with open(file, "r") as file_with_particles:
                particles = []
                particle_count = 0
                line = file_with_particles.readline()
                while line != "":
                    line = line.replace(" ", "")
                    particle_properties = line.split(",")
                    try:
                        if len(particle_properties) < 4:
                            raise MissingParticleParams(
                                "Found only " + len(particle_properties) +
                                " on particle " + particle_count)
                        else:
                            new_particle = Particle(
                                int(particle_properties[0]),
                                int(particle_properties[1]),
                                int(particle_properties[2]),
                                int(particle_properties[3]))
                            particles.append(new_particle)

                    except MissingParticleParams as E:
                        print(E)

                    particle_count += 1
                    line = file_with_particles.readline()
                ConfigManipulator().set(ConfigFields.particleAmount,
                                        particle_count)
                return SimFrame(particles)
コード例 #8
0
class DrawVelocity:
    """
    Class create animation showing changes of speed in time
    """
    def __init__(self):
        self.config = ConfigManipulator()
        self.particles_amount = int(
            self.config.read(ConfigFields.particleAmount))
        self.particle_size = int(self.config.read(
            ConfigFields.particleSize)) * 265 / int(
                self.config.read(ConfigFields.size))
        self.max_speed = int(self.config.read(ConfigFields.maxSpeed))
        self.box_size = int(self.config.read(ConfigFields.boxSize))

        self.figure, self.axes = mpl.subplots()
        self.anim = None
        self.dpi = 500
        self.path = "SpeedAnimation.mp4"

        self.frame_number = 1
        self.frames = self.unpickle()

        print("Drawing velocity chart")

    def unpickle(self) -> List[SimFrame]:
        """
        Obtain table with simframes from pickled file
        :return:
        """
        with open("simulation.sim", "rb") as file:
            return pickle.load(file)

    def init_drawing(self):
        """
        Initialize chart
        :return:
        """
        # set positions
        sim_frame = self.frames[0]
        x = list()
        y = list()
        for particle in sim_frame.get_particles():
            x.append(particle.get_velocity()[0])
            y.append(particle.get_velocity()[1])

        # give colors
        colors = 0.02 * (np.random.random(self.particles_amount)) - 0.5

        # plot chart
        self.scat = self.axes.scatter(x, y, s=self.particle_size**2, c=colors)
        self.axes.axis(
            [-self.max_speed, self.max_speed, -self.max_speed, self.max_speed])

        # set ticks on chart
        grid_ticks = np.arange(-self.max_speed, self.max_speed, self.box_size)

        self.axes.set_xticks(grid_ticks)
        self.axes.set_yticks(grid_ticks)

        # set grid
        self.axes.grid()

        return self.scat,

    def update(self, step):
        """
        Update animation
        :return:
        """
        print("Rendering frame: ", self.frame_number)
        # check new positions
        sim_frame = self.frames[self.frame_number]
        positions = list()

        # change title showing frame number
        self.axes.set_title(self.frame_number)
        for particle in sim_frame.get_particles():
            x = particle.get_velocity()[0]
            y = particle.get_velocity()[1]
            positions.append((x, y))

        self.frame_number += 1

        # save positions to chart
        self.scat.set_offsets(positions)

        # sizes
        # self.scat.set_sizes([10] * 2)

        # colors
        # self.scat.set_array([0.2] * 2)

        return self.scat,

    def evaluate(self):
        """
        Function used to create animation
        For better understanding read matplotlib.pyplot.animation documentation
        :return:
        """
        self.anim = animation.FuncAnimation(
            self.figure,
            self.update,
            interval=int(self.config.read(ConfigFields.time)),
            frames=int(self.config.read(ConfigFields.time)),
            init_func=self.init_drawing,
            blit=True)
        self.anim.save(self.path,
                       dpi=self.dpi,
                       fps=1 / float(self.config.read(ConfigFields.timeDelta)),
                       extra_args=['-vcodec', 'libx264'])
コード例 #9
0
class Entropy:
    """
        Function used to calculate and draw enthropy

        MACROSTATE
        [ posX ] [ posY] [ speedX ] [ speedY ]
    """
    def __init__(self):
        self.configparser = ConfigManipulator()
        self.size = int(self.configparser.read(ConfigFields.size))
        self.box_size = int(self.configparser.read(ConfigFields.boxSize))
        self.max_speed = int(self.configparser.read(ConfigFields.maxSpeed))
        self.particle_amount = int(
            self.configparser.read(ConfigFields.particleAmount))
        self.time = int(self.configparser.read(ConfigFields.time))
        self.frames = self.unpickle()
        self.max_box_speed = math.floor(self.max_speed / self.box_size)
        self.max_box_size = math.floor(self.size / self.box_size)

    def unpickle(self) -> List[SimFrame]:
        """
        Reads pickled table with simframes, aka simulation.sim
        :return:
        """
        with open("simulation.sim", "rb") as file:
            return pickle.load(file)

    def evaluate(self):
        """
        Function iterates over table with simframes and calculate entropy for each,
        adds it to another table and draw a chart
        :return:
        """
        print("Evaluating entropy")
        x = np.arange(0, self.time + 1, 1)
        y = list()

        actual_frame = 0

        while actual_frame <= self.time:
            print("Evaluating entropy for frame: ", actual_frame)
            entropy = self.get_entropy(self.frames[actual_frame])
            y.append(entropy)
            actual_frame += 1

        fig, ax = plt.subplots()

        fig.suptitle('Zmiana entropii w czasie')

        ax.set_xlabel("czas (kl)")
        ax.set_ylabel("entropia")
        ax.plot(x, y, c='r')
        # ax.set_yscale('log')
        plt.savefig("entropy.png", dpi=500)

    def get_entropy(self, frame: SimFrame) -> float:
        """
        Function eval entropy for given simframe
        Utilize THProb from other class
        :param frame:
        :return: float as entrpy
        """
        thprob = THProb().get_thermal_probability(frame)
        return math.log(thprob)
コード例 #10
0
class Initiator:
    """
        Creates first frame for further simulation, can read data from csv formatted plain text document,
        which name should be supplied under -f option during script startup

    """
    def __init__(self):
        self.config_manipulator = ConfigManipulator()
        self.max_speed = float(
            self.config_manipulator.read(ConfigFields.maxSpeed))
        self.size = (float(self.config_manipulator.read(ConfigFields.size)),
                     float(self.config_manipulator.read(ConfigFields.size)))
        self.box_size = float(
            self.config_manipulator.read(ConfigFields.boxSize))
        self.max_particles_count = float(
            self.config_manipulator.read(ConfigFields.particleAmount))

    def create(self) -> SimFrame:
        """
        function to call to generate first frame,
        generation from file is inferred from existence of init_file value in config.ini
        :return: SimFrame with first state
        """
        print("Creating first frame")

        init_satate_file = self.config_manipulator.read(
            ConfigFields.init_state_file)
        if init_satate_file == "":
            # file not found
            return self.create_random()
        else:
            # file found
            return self.create_from_file(init_satate_file)

    def create_random(self) -> SimFrame:
        """
        private subfunciton for random generation of states
        :return: SimFrame
        """
        print("first frame will be created randomly")

        particles = []
        count_of_created_particles = 0
        while count_of_created_particles < self.max_particles_count:
            position = self.dice_position()
            speed = self.dice_speed()
            new_particle = Particle(position[0], position[1], speed[0],
                                    speed[1])

            particles.append(new_particle)
            count_of_created_particles += 1

        # for particle in particles:
        #     print(particle)

        return SimFrame(particles)

    def create_from_file(self, file: str) -> SimFrame:
        """
        Private subfunction, bla bla bla
        :param file: csv file containing data for particles
        :return: SimFrame
        """
        print("First frame will be read from file")
        file_suffix = file.split(".")[-1]
        if file_suffix != "csv":
            raise ResourceWarning("Wrong file format")
        else:
            with open(file, "r") as file_with_particles:
                particles = []
                particle_count = 0
                line = file_with_particles.readline()
                while line != "":
                    line = line.replace(" ", "")
                    particle_properties = line.split(",")
                    try:
                        if len(particle_properties) < 4:
                            raise MissingParticleParams(
                                "Found only " + len(particle_properties) +
                                " on particle " + particle_count)
                        else:
                            new_particle = Particle(
                                int(particle_properties[0]),
                                int(particle_properties[1]),
                                int(particle_properties[2]),
                                int(particle_properties[3]))
                            particles.append(new_particle)

                    except MissingParticleParams as E:
                        print(E)

                    particle_count += 1
                    line = file_with_particles.readline()
                ConfigManipulator().set(ConfigFields.particleAmount,
                                        particle_count)
                return SimFrame(particles)

    def dice_speed(self) -> (float, float):
        """
        Dice speed for particle,
        x component is randomized, and y component is calculated as cathetus of right angle triangle,
        so hypotenuse holds
        :return: speed tuple
        """
        speed_x = random.random() * self.max_speed
        speed_y = math.sqrt(self.max_speed**2 - speed_x**2)

        # also randomize directions of move
        if random.randint(0, 1) == 0:
            speed_x = -speed_x
        if random.randrange(0, 1) == 1:
            speed_y = -speed_y

        return speed_x, speed_y

    def dice_position(self):
        """
        Dice position
        :return: position tuple
        """
        x = random.random() * self.box_size

        y = random.random() * self.size[1]

        return x, y
コード例 #11
0
class THProb:
    """
    Class used to calculate Thermal Probability
    """
    """
        MACROSTATE
        [ posX ] [ posY] [ speedX ] [ speedY ]
    """
    def __init__(self):
        self.configparser = ConfigManipulator()
        self.size = int(self.configparser.read(ConfigFields.size))
        self.box_size = int(self.configparser.read(ConfigFields.boxSize))
        self.max_speed = int(self.configparser.read(ConfigFields.maxSpeed))
        self.particle_amount = int(
            self.configparser.read(ConfigFields.particleAmount))
        self.time = int(self.configparser.read(ConfigFields.time))
        self.frames = self.unpickle()
        self.max_box_speed = math.floor(self.max_speed / self.box_size)
        self.max_box_size = math.floor(self.size / self.box_size)

    def unpickle(self) -> List[SimFrame]:
        """
        Read pickled list with entire simulation form file
        :return: list with Simframes representing entire simulation
        """
        with open("simulation.sim", "rb") as file:
            return pickle.load(file)

    def evaluate(self):
        """
        Iterates over list with simulations, and calculate thprob for each
        :return:
        """
        print("Evaluating Thermal Probability")
        x = np.arange(0, self.time + 1, 1)
        y = list()

        actual_frame = 0

        while actual_frame <= self.time:
            print("THProb evaluating for frame: ", actual_frame)
            thprob = self.get_thermal_probability(self.frames[actual_frame])
            y.append(thprob)
            actual_frame += 1

        fig, ax = plt.subplots()

        fig.suptitle('Zmiana prawdopodobieństwa w czasie')

        ax.set_xlabel("czas (kl)")
        ax.set_ylabel("prawdopodobieństwo termodynamiczne")
        ax.plot(x, y)
        ax.set_yscale('log')
        plt.savefig("thprob.png", dpi=500)

    def create_macrostates(self, frame: SimFrame) -> np.ndarray:
        """
        Create ndarray representing macrostate.
        Shape of array is defined as:
            X -> maximal position in box coordinates + 1
            Y -> same as above
            vX -> maximal speed in box coordinates multiplied by two plus one,
                    cuz particle can has negative speed and 0 speed
            vY -> same as above
        :param frame:
        :return:
        """
        shape = (self.max_box_size + 1, self.max_box_size + 1,
                 self.max_box_speed * 2 + 1, self.max_box_speed * 2 + 1)
        particles = frame.get_particles()

        macrostate = np.ndarray(shape=shape, dtype=int)
        macrostate.fill(0)

        for particle in particles:
            x = particle.get_box_position()[0]
            y = particle.get_box_position()[1]

            x_speed = particle.get_box_velocities()[0]
            y_speed = particle.get_box_velocities()[1]

            # we need to fix speeds transforming them from system in which
            # they can have negative speeds, to system in which they can have
            # only positive or 0 speed
            # it's linear transformation to the left of value max_box_speed
            # then -max_box_speed becomes 0
            # and max_box_speed becomes two times bigger
            fixed_x_speed = x_speed + self.max_box_speed
            fixed_y_speed = y_speed + self.max_box_speed

            # also we need to check if we deal with particle which speeds are in
            # desired range - rounding errors can make situations in
            # which particles can obtain some extra speed
            # for them, we dont have place in ndarray
            if x_speed <= self.max_box_speed and y_speed <= self.max_box_speed:
                macrostate[x][y][fixed_x_speed][fixed_y_speed] += 1

        return macrostate

    def get_thermal_probability(self, frame: SimFrame) -> float:
        """
        In general thermal probability is permutaion with repeats over set of particles being
        in some macrostate.
        Then we can calculate it by dividing factorial of count of particles by product of
        factorials of particles being in this same state
        :param frame:
        :return:
        """

        macrostates = self.create_macrostates(frame)

        # we need to linearise 4D array
        macrostates_cout = macrostates.size
        macrostates = macrostates.reshape(macrostates_cout)

        # nominator = math.factorial(self.particle_amount)
        nominator = self.stirling_approximation(self.particle_amount)
        denominator = 1

        for i in range(macrostates_cout):
            denominator *= self.stirling_approximation(macrostates[i])

        # try:
        #     print(nominator, denominator)
        #     return nominator / denominator
        # except OverflowError as e:
        #     print("Float division overflow")
        #     return 10 ** 300

        return nominator / denominator

    def factorial(self, n: int):
        product = 1
        n1 = 2
        while n1 <= n:
            product *= n1
            n1 += 1
        return product

    def stirling_approximation(self, n):
        """
        Stirling approximation of factorial, although is faster than normal factorial
        python float math module allows to create numbers not grater than 10 ^ 300
        (200! is much grater), so we need to create some exceptions to catch this situations
        :param n:
        :return:
        """
        if n < 2:
            return 1
        else:
            try:
                return math.e**(n * math.log(n) - n)
            except OverflowError as e:
                print("Float exponentiation overflow")
                return 10**300