Plotting Simulation MetricsΒΆ

stuff:

import mechanica as m
import numpy as np
import math

import matplotlib
import matplotlib.pyplot as plt

from time import time
from random import random

print ( matplotlib.__version__ )

# potential cutoff distance
cutoff = 10

# number of particles
count = 6000

# number of time points we avg things
avg_pts = 3

# dimensions of universe
dim=np.array([30., 30., 30.])
center = dim / 2

# new simulator, don't load any example
m.Simulator(dim=dim, cutoff=cutoff, integrator=m.FORWARD_EULER,
            dt=0.002)

clump_radius = 2

# number of bins we use for averaging
avg_bins = 3

prev_pos = np.zeros((count, 3))
avg_vel  = np.zeros((count, 3))
avg_pos  = np.zeros((count, 3))
avg_index = 0;

# the output display array.
# matplotlib uses (Y:X) axis arrays instead of normal (X:Y)
# seriously, WTF matplotlib???
display_velocity = np.zeros((100, 200))
display_velocity_count = np.zeros((100, 200))

# keep a handle on all the cells we've made.
cells = count * [None]

def cartesian_to_spherical(pt, origin):
    """
    Convert a given point in cartesian to a point in spherical (r, theta, phi)
    relative to the origin.
    """

    pt = pt - origin
    r = np.linalg.norm(pt)
    theta = math.atan2(pt[1], pt[0])
    if theta < 0:
        theta = theta + 2 * math.pi
    phi = math.acos(pt[2] / r)
    return np.array((r, theta, phi))


def spherical_index_from_cartesian(pos, origin, theta_bins, phi_bins):
    """
    calculates the i,j indexex in a 2D array of size irange,jrange
    from a given cartesian coordinate and origin.

    theta_bins is number of bins in the theta direction
    phi_bins is number of bins in the phi direction
    """

    # get spherical coordinates in (r, theta, phi)
    sph = cartesian_to_spherical(pos, origin)

    # i is the horizontal axis, theta axis, and j is vertica, the phi
    i = math.floor(sph[1] / (2. * np.pi) * theta_bins)
    j = math.floor(sph[2] / (np.pi + np.finfo(np.float32).eps) * phi_bins)

    return (i, j)


class Yolk(m.Particle):
    mass = 500000
    radius = 6


class Cell(m.Particle):
    mass = 5
    radius = 0.25
    target_temperature=0
    dynamics = m.Overdamped

total_height = 2 * Yolk.radius + 2 * clump_radius
yshift = total_height/2 - Yolk.radius
cshift = total_height/2 - 1.3 * clump_radius


pot_yc = m.Potential.soft_sphere(kappa=300, epsilon=50, r0=1, \
                                 eta=2, tol = 0.03, min=0.1, max=8, shift=True)

pot_cc = m.Potential.soft_sphere(kappa=600, epsilon=0.5, r0=1, \
                                 eta=3, tol = 0.05, min=0, max=2.5, shift=True)

# bind the potential with the *TYPES* of the particles
m.Universe.bind(pot_yc, Yolk, Cell)
m.Universe.bind(pot_cc, Cell, Cell)

# create a random force. In overdamped dynamcis, we neeed a random force to
# enable the objects to move around, otherwise they tend to get trapped
# in a potential
rforce = m.forces.random(0, 1)

# bind it just like any other force
m.bind(rforce, Cell)

yolk = Yolk(position=center-[0., 0., yshift])

for i, p in enumerate(m.random_point(m.SolidSphere, count)):
    pos = p * clump_radius + center+[0., 0., cshift]
    cells[i] = Cell(position=pos)


def calc_avg_pos(e):
    global avg_index
    print("calc_avg_pos, index: ", avg_index)

    for i, p in enumerate(cells):
        avg_vel[i] += p.position - prev_pos[i]
        prev_pos[i] = p.position
        avg_pos[i] += p.position

    if avg_index == (avg_bins - 1):

        avg_pos[:] = avg_pos / avg_bins

        for i in range(count):
            # get the theta / phi index from the cartesian coordinate
            # remeber, matplotlib is backwards and wants matricies in
            # transposed order.
            ii, jj = spherical_index_from_cartesian(avg_pos[i], \
                                                    yolk.position, \
                                                    display_velocity.shape[1], \
                                                    display_velocity.shape[0])

            # counts of samples we have for this spherical coordinate
            display_velocity_count[jj, ii] += 1

            # velocity of the vertical (y) direction
            display_velocity[jj, ii] += avg_vel[i][1] / avg_bins

        display_velocity[:] = display_velocity / avg_bins

        Z = display_velocity


        plt.pause(0.01)
        plt.clf()
        #plt.contour(Z)

        yy = np.linspace(0, np.pi, num=100)
        xx = np.linspace(0, 2 * np.pi, num=200)
        c=plt.pcolormesh(xx, yy, Z, cmap ='jet')
        plt.colorbar(c)
        plt.show(block=False)

        avg_pos[:] = 0
        avg_vel[:] = 0
        display_velocity_count[:] = 0
        display_velocity[:] = 0


    # bump counter where we store velocity info to be averaged
    avg_index = (avg_index + 1) % avg_bins

m.on_time(calc_avg_pos, period=0.01)

# run the simulator interactive
m.Simulator.run()

The complete simulation script is here, and can be downloaded here:

Download: this example script: