<jupyter_start><jupyter_text>An Exploration of Fluctuating Channel Flow This is a sandbox for exploring the fluctuating channel flow data. Data is loaded using the YT package. You might need to install (using `pip`):1. Jupyter (and Jupyter Lab)2. YT3. numpy4. matplotlib... Have fun!  Import Basics<jupyter_code>import sys, os, os.path
import glob

import scipy as sp
import numpy as np

import matplotlib
import matplotlib.pyplot as pp

import yt
from yt.frontends.boxlib.data_structures import AMReXDataset<jupyter_output><empty_output><jupyter_text>Inline plots and namespace:<jupyter_code>%pylab inline
%precision %e<jupyter_output>Populating the interactive namespace from numpy and matplotlib<jupyter_text>Utilities Replace `phi` with `concentration` in plot file's header file (yt doesn't like `phi`...)<jupyter_code>### Replace "phi" with "concentration" in plt header file (yt doesn't like phi...)
def substitute_header(plt_file, source="phi", target="con"):
    
    # load header file
    header_file = os.path.join(plt_file, "Header")
    with open(header_file, "r") as f:
        header_orig = f.readlines()
    
    # select variable lables
    n_lables   = int(header_orig[1])
    l_offset   = 2
    
    # make a backup copy(iff the source was found in original)
    if source+"\n" in header_orig:
        header_cpy  = os.path.join(plt_file, "Header.backup")
        with open(header_cpy, "w") as f:
            for line in header_orig:
                f.write(line)
    
    # replace source with target
    for i in range(l_offset, n_lables+l_offset):
        if header_orig[i] == source+"\n":
            header_orig[i] = target+"\n"
    
    # save substituted file in place of original
    with open(header_file, "w") as f:
        for line in header_orig:
            f.write(line)<jupyter_output><empty_output><jupyter_text>Find Data Currently we're working in the same directory as a the data $=>$ look in `.` for plot files<jupyter_code>data_root = "."
data_dir  = "."
data_path = os.path.join(data_root, data_dir)
n_fill   = 5
prefix   = "plt"
file_fmt = prefix + "{:0" + str(n_fill) + "d}"
file_fmt
data_glob  = os.path.join(data_path, prefix + "*")
data_files = glob.glob(data_glob)
data_files.sort()
print(data_files)
len(data_files)<jupyter_output><empty_output><jupyter_text>Plot Final State of the Simulation<jupyter_code>def plot_index(data_file, str_field, str_coord):
    substitute_header(data_file)
    
    # Loads the data file
    ds = yt.load(data_file)
    
    # Takes a slice perpendicular to the coordinate represented by `str_coord`
    # -> the slice is at the center of the box.
    # -> the data field being sliced has to have the same name as `str_field`
    slc = yt.SlicePlot(ds, str_coord, str_field)
    
    # Set the plotted variable to log scale
    #slc.set_log(str_field, True)
    
    # Show data
    slc.show()
    #slc.save("step_0.png")<jupyter_output><empty_output><jupyter_text>Let's find out what fields are contained in the plot file<jupyter_code>ds = yt.load(data_files[-1])
ds.field_list
ds.domain_dimensions<jupyter_output>yt : [INFO     ] 2019-07-23 14:24:49,942 Parameters: current_time              = 0.005
yt : [INFO     ] 2019-07-23 14:24:49,943 Parameters: domain_dimensions         = [32 32 32]
yt : [INFO     ] 2019-07-23 14:24:49,945 Parameters: domain_left_edge          = [0. 0. 0.]
yt : [INFO     ] 2019-07-23 14:24:49,947 Parameters: domain_right_edge         = [1. 1. 1.]<jupyter_text>Plot the last plot file's $y$-velocity (slicing normal the $y$-axis).<jupyter_code>plot_index(data_files[-1], "shifted_vely", "y")<jupyter_output>yt : [INFO     ] 2019-07-23 14:24:50,224 Parameters: current_time              = 0.005
yt : [INFO     ] 2019-07-23 14:24:50,225 Parameters: domain_dimensions         = [32 32 32]
yt : [INFO     ] 2019-07-23 14:24:50,229 Parameters: domain_left_edge          = [0. 0. 0.]
yt : [INFO     ] 2019-07-23 14:24:50,234 Parameters: domain_right_edge         = [1. 1. 1.]
yt : [INFO     ] 2019-07-23 14:24:50,393 xlim = 0.000000 1.000000
yt : [INFO     ] 2019-07-23 14:24:50,394 ylim = 0.000000 1.000000
yt : [INFO     ] 2019-07-23 14:24:50,396 xlim = 0.000000 1.000000
yt : [INFO     ] 2019-07-23 14:24:50,397 ylim = 0.000000 1.000000
yt : [INFO     ] 2019-07-23 14:24:50,399 Making a fixed resolution buffer of (('boxlib', 'shifted_vely')) 800 by 800
yt : [WARNING  ] 2019-07-23 14:24:50,420 Plot image for field ('boxlib', 'shifted_vely') has both positive and negative values. Min = -15.492875, Max = 37.661723.
yt : [WARNING  ] 2019-07-23 14:24:50,421 Switching to symlog colorbar scaling unless linear s[...]<jupyter_text>Let's do the same for the presure<jupyter_code>plot_index(data_files[-1], "pres", "x")<jupyter_output>yt : [INFO     ] 2019-07-23 14:24:51,014 Parameters: current_time              = 0.005
yt : [INFO     ] 2019-07-23 14:24:51,015 Parameters: domain_dimensions         = [32 32 32]
yt : [INFO     ] 2019-07-23 14:24:51,017 Parameters: domain_left_edge          = [0. 0. 0.]
yt : [INFO     ] 2019-07-23 14:24:51,018 Parameters: domain_right_edge         = [1. 1. 1.]
yt : [INFO     ] 2019-07-23 14:24:51,167 xlim = 0.000000 1.000000
yt : [INFO     ] 2019-07-23 14:24:51,169 ylim = 0.000000 1.000000
yt : [INFO     ] 2019-07-23 14:24:51,174 xlim = 0.000000 1.000000
yt : [INFO     ] 2019-07-23 14:24:51,175 ylim = 0.000000 1.000000
yt : [INFO     ] 2019-07-23 14:24:51,177 Making a fixed resolution buffer of (('boxlib', 'pres')) 800 by 800
yt : [WARNING  ] 2019-07-23 14:24:51,201 Plot image for field ('boxlib', 'pres') has both positive and negative values. Min = -111.473926, Max = 27.577269.
yt : [WARNING  ] 2019-07-23 14:24:51,202 Switching to symlog colorbar scaling unless linear scaling is speci[...]<jupyter_text>Analyse Data ... with `numpy`  Velocity fluctuations<jupyter_code>ds = yt.load(data_files[-1])<jupyter_output>yt : [INFO     ] 2019-07-23 14:24:51,903 Parameters: current_time              = 0.005
yt : [INFO     ] 2019-07-23 14:24:51,904 Parameters: domain_dimensions         = [32 32 32]
yt : [INFO     ] 2019-07-23 14:24:51,911 Parameters: domain_left_edge          = [0. 0. 0.]
yt : [INFO     ] 2019-07-23 14:24:51,913 Parameters: domain_right_edge         = [1. 1. 1.]<jupyter_text>Get information about geometry: $\mathrm{d}x$ and index of centre<jupyter_code>dx = np.array(
    [
        ( ds.domain_right_edge[i] - ds.domain_left_edge[i] ) / ds.domain_dimensions[i] 
        for i in range(ds.dimensionality) 
    ]
)


centre_slice = np.array([ei for ei in ds.domain_right_edge ])/2
ind_cen      = centre_slice / dx
print(ind_cen)<jupyter_output>[16. 16. 16.]<jupyter_text>Extract a "cube of data" from the plot file. This might seem a bit convoluted, but remember that YT is built to handle multi-level data. This function covers a given level (in our case, level 0) with a 3D grid (cube) and exports the data into a dict of `numpy` arrays. This way `cube["filed name"]` is a 3D numpy array.<jupyter_code>cube = ds.covering_grid(level=0, fields=["shifted_velx", "shifted_vely", "shifted_velz"], 
                        left_edge=ds.domain_left_edge, dims=ds.domain_dimensions)
velx = cube["shifted_velx"]
vely = cube["shifted_vely"]
velz = cube["shifted_velz"]<jupyter_output><empty_output><jupyter_text>Double-check the data.<jupyter_code>matshow(velx[:, 16, :])
colorbar()
matshow(vely[:, 16, :])
colorbar()
matshow(velz[:, 16, :])
colorbar()
class SoA:
    _pref = "particle_"
    _pos  = "position_"
    _vel  = "vel"
# New here
    _id   = "id"
    _cpu  = "cpu"
    _id_0 = "id_0"
    _cpu_0 = "cpu_0"
    
    def __init__(self, data):
        str_pos = self._pref+self._pos
        self.px = np.array(data[str_pos + "x"])
        self.py = np.array(data[str_pos + "y"])
        self.pz = np.array(data[str_pos + "z"])

        str_vel = self._pref+self._vel
        self.vx = np.array(data[str_vel + "x"])
        self.vy = np.array(data[str_vel + "y"])
        self.vz = np.array(data[str_vel + "z"])

        str_id = self._pref+self._id
        self.id = np.array(data[str_id])
        str_cpu = self._pref+self._cpu
        self.cpu = np.array(data[str_cpu])
        
        str_id_0 = self._pref+self._id_0
        self.id_0 = np.array(data[str_id_0])
        str_cpu_0 = self._pref+self._cpu_0
        self.cpu_0 = np.array(data[str_cpu_0])
 
# new here
    def __str__(self):
        return "{pos:"  + str(self.px) + "," + str(self.py) + "," + str(self.pz) + \
              "; vel:"  + str(self.vx) + "," + str(self.vy) + "," + str(self.vz) + \
              "; id:"   + str(self.id) + ", cpu:" + str(self.cpu) + ", id_0:" + str(self.id_0) + ", cpu_0:" + str(self.cpu_0) + "," + "}"


    def __repr__(self):
        return str(self)


# new here
class Particle:
    def __init__(self, px, py, pz, vx, vy, vz, id, cpu, id_0, cpu_0):
        self.pos = np.array([px, py, pz])
        self.vel = np.array([vx, vy, vz])
        self.id  = np.array(id)
        self.cpu  = np.array(cpu)
        self.id_0  = np.array(id_0)
        self.cpu_0  = np.array(cpu_0)

    def __str__(self):
        return "P(" + str(self.pos) + "," + str(self.vel) + "," + str(self.id) + "," + str(self.cpu) + "," + str(self.id_0) + "," + str(self.cpu_0) + "," + ")"
    

    def __repr__(self):
        return str(self)


class AoS:
    def __init__(self, amrex_data):
        self.particles = list()
        soa = SoA(amrex_data)
# new here        
        data = zip(soa.px, soa.py, soa.pz, soa.vx, soa.vy, soa.vz, soa.id, soa.cpu, soa.id_0, soa.cpu_0)
        for elt in data:
            self.particles.append(Particle(* elt))



ds = AMReXDataset(data_files[-1])
ds.particle_fields_by_type
ad = ds.all_data()
soa = SoA(ad)
aos = AoS(ad)
aos.particles
nop = 10#number of particles
aos.particles[0].pos[0:nop]
positions_ = dict()
id_        = dict()
cpu_       = dict()
id0_       = dict()
cpu0_      = dict()

for x in range(1,nop+1):
    positions_[x] = list()
    id_[x]        = list()
    cpu_[x]       = list()
    id0_[x]       = list()
    cpu0_[x]      = list()
    

for k in range(0, nop+1):
    data_file = data_files[k]
    #ds = yt.load(data_files[-1])
    ds = AMReXDataset(data_file)
    t = ds.current_time
    ad = ds.all_data()
    aos = AoS(ad)
    for y in range(1,nop+1):
        positions_[y].append(aos.particles[y-1].pos)
        id_[y].append(aos.particles[y-1].id)
        cpu_[y].append(aos.particles[y-1].cpu)
        id0_[y].append(aos.particles[y-1].id_0)
        cpu0_[y].append(aos.particles[y-1].cpu_0)
        
   
x_ = dict()
y_ = dict()
z_ = dict()
for v in range(1,nop+1):
    x_[v] = np.array([pos[0] for pos in positions_[v]])
    y_[v] = np.array([pos[1] for pos in positions_[v]])
    z_[v] = np.array([pos[2] for pos in positions_[v]])


    
for p in range(1, nop+1):
    plot(x_[p], y_[p])
    
for p in range(1,nop+1):
    plot(x_[p])
   
for p in range(1,nop+1):
    plot(y_[p])
for p in range(1,nop+1):
    plot(z_[p])
for p in range(1,nop+1):
    plot(id_[p], '^')
for p in range(1,nop+1):
    plot(cpu_[p], '^')
for p in range(1,nop+1):
    plot(id0_[p], '^')
id_sorted_       = dict()
cpu_sorted_      = dict()
position_sorted_ = dict()
marker_id_       = dict()
marker_cpu_      = dict()

x_               = dict()
y_               = dict()
z_               = dict()

marker_posy_ = dict()

m_index = dict()


for x in range(1,nop+1):
    id_sorted_[x]       = list()
    cpu_sorted_[x]      = list()
    position_sorted_[x] = list()
    
    
prevmarker_id  = -1
prevmarker_cpu = -1    

#for data_file in data_files:
#    ds = AMReXDataset(data_file)
#    ad = ds.all_data()

for n in range(1, 10):
    marker_posy_[n] = list()

for n in range(1, 10):
    m = (n-1)*1
    
    data_file = data_files[m]
    #ds = yt.load(data_files[-1])
    ds = AMReXDataset(data_file)
    t = ds.current_time
    ad = ds.all_data()
    aos = AoS(ad)
    prevmarker_id = -1
    prevmarker_cpu = -1
    for k in range(0, nop):
        if aos.particles[k].id_0 == prevmarker_id and aos.particles[k].cpu_0 == prevmarker_cpu:
                id_sorted_[1].append(aos.particles[k].id)
                cpu_sorted_[1].append(aos.particles[k].cpu)
                position_sorted_[1].append(aos.particles[k].pos)
                marker_id_[1] = aos.particles[k].id
                marker_cpu_[1] = aos.particles[k].cpu
                
    for i in range(1,nop):    
        for k in range(0, nop):
            if aos.particles[k].id_0 == marker_id_[i] and aos.particles[k].cpu_0 == marker_cpu_[i]:
                id_sorted_[i+1].append(aos.particles[k].id)
                cpu_sorted_[i+1].append(aos.particles[k].cpu)
                position_sorted_[i+1].append(aos.particles[k].pos)
                marker_id_[i+1] = aos.particles[k].id
                marker_cpu_[i+1] = aos.particles[k].cpu
                
    for v in range(1,nop+1):
        m_index[v] = v
        x_[v] = np.array([pos[0] for pos in position_sorted_[v]])
        y_[v] = np.array([pos[1] for pos in position_sorted_[v]])
        z_[v] = np.array([pos[2] for pos in position_sorted_[v]])
               
        marker_posy_[n].append([pos[1] for pos in position_sorted_[v]])
        
    plot(marker_posy_[n],'-o')  # this is to plot the marker y positions at a given time step to show the flagellum shape
    #import time
    #time.sleep(1.3) 
marker_posy_[1]
%matplotlib inline

#print(matplotlib.animation.writers.list())
matplotlib.rcParams['animation.writer'] = 'ffmpeg'
#matplotlib.rcParams['animation.writer'] = 'avconv'
x_                = dict()
y_                = dict()
z_                = dict()


for v in range(1,nop+1):
    x_[v] = np.array([pos[0] for pos in position_sorted_[v]])
    y_[v] = np.array([pos[1] for pos in position_sorted_[v]])
    z_[v] = np.array([pos[2] for pos in position_sorted_[v]])


    
for p in range(1,nop+1):
    plot(x_[p], y_[p], "-o")
    
for p in range(1,nop+1):
    plot(x_[p])
   
for p in range(1,nop+1):
    plot(y_[p], ".")
   
for p in range(1,nop+1):
    plot(z_[p])
   
for p in range(1,nop+1):
    plot(id_sorted_[p], '^')
for p in range(1,nop+1):
    plot(cpu_sorted_[p], '^')<jupyter_output><empty_output><jupyter_text>Remove Average `vely` The $y$-data might seem smooth. But there will be tiny fluctuations. In order to see those, let's compute the average in dimensions 2 and 3.<jupyter_code>m_vely = mean(mean(vely[:, :, :], axis=1), axis=1)
#              ^^-- returns a 2D array of average velocities
#         ^^------- returns a 1D array of average velocities (the average of the previous average)
plot(m_vely)<jupyter_output><empty_output><jupyter_text>Compute fluctuations: `m_vely` is applied to all `dim=1` slices<jupyter_code># slice-wise subtraction of the average velocity... 
# I can't think of a fancy pythonic way of doing this => I'll do it in this cumbersome way:
fluct_vely = np.zeros_like(vely)
for i in range(vely.shape[0]):
    for j in range(vely.shape[1]):
            fluct_vely[:, i, j] = vely[:, i, j] - m_vely[:]
matshow(fluct_vely[:, 8, :])
colorbar()<jupyter_output><empty_output><jupyter_text>Compute $x$, $y$ and $z$ Temperatures (Fluctuations in `velx`, `vely`, `velz`)<jupyter_code>t_x = mean(mean(velx[:, :, :]**2, axis=1), axis=1)
#           ^^-- returns a 2D array of average velocities
#      ^^------- returns a 1D array of average velocities (the average of the previous average)
t_x = sqrt(t_x)
t_y = mean(mean(fluct_vely[:, :, :]**2, axis=1), axis=1)
#           ^^-- returns a 2D array of average velocities
#      ^^------- returns a 1D array of average velocities (the average of the previous average)
t_y = sqrt(t_y)
t_z = mean(mean(velz[:, :, :]**2, axis=1), axis=1)
#           ^^-- returns a 2D array of average velocities
#      ^^------- returns a 1D array of average velocities (the average of the previous average)
t_z = sqrt(t_z)
plot(t_x)
plot(t_y)
plot(t_z)<jupyter_output><empty_output><jupyter_text>We see that the $x$-fluctuations are supressed due to the wall $\Rightarrow{}$ needs fixing!  Old Stuff $\Rightarrow{}$ Clean up at some point<jupyter_code>def grad(phi):
    dphi_x = np.zeros_like(phi)
    dphi_y = np.zeros_like(phi)
    dphi_z = np.zeros_like(phi)
    
    dphi_x[ :-1, :, :] += phi[1:,   :, :]
    dphi_x[1:,   :, :] -= phi[ :-1, :, :]
    
    dphi_y[:,  :-1, :] += phi[:, 1:,   :]
    dphi_y[:, 1:,   :] -= phi[:,  :-1, :]
    
    dphi_z[:, :,  :-1] += phi[:, :, 1:, ]
    dphi_z[:, :, 1:  ] -= phi[:, :,  :-1]
    
    return dphi_x, dphi_y, dphi_z
grad_x, grad_y, grad_z = grad(cube["con"])
matshow(cube['con'][32, :, :])
matshow(grad_z[32, :, 65:])
matshow(cube['con'][43, :, :])
matshow(grad_z[43, :, :])
plot(grad_z[43, 30, :])
matshow(grad_z[32, :, :])
matshow(cube['con'][:, :, 45])
matshow(grad_x[:, :, 45])
def sphere_coord(i_x, i_y, i_z, dr=dx, r_c=centre_colloid):
    x = (i_x + 0.5)*dr[0] - r_c[0]
    y = (i_y + 0.5)*dr[1] - r_c[1]
    z = (i_z + 0.5)*dr[2] - r_c[2]
    
    r     = np.sqrt( x**2 + y**2 + z**2)
    theta = np.arccos(z/r)
    phi   = np.arctan2(y, x)
        
    return r, theta, phi

def r_unit(theta, phi):
    return np.array([
        np.sin(theta)*np.cos(phi),
        np.sin(theta)*np.sin(phi),
        np.cos(theta)
    ])

def theta_unit(theta, phi):
    return np.array([
        np.cos(theta)*np.cos(phi),
        np.cos(theta)*np.sin(phi),
       -np.sin(theta)
    ])

def phi_unit(phi):
    return np.array([
       -np.sin(phi),
        np.cos(phi),
        0
    ])
def grad_sphere(grad_x, grad_y, grad_z):
    grad_r     = np.zeros_like(grad_x)
    grad_phi   = np.zeros_like(grad_y)
    grad_theta = np.zeros_like(grad_z)
    
    r_dat     = np.zeros_like(grad_x)
    phi_dat   = np.zeros_like(grad_x)
    theta_dat = np.zeros_like(grad_x)
    
    for ind, x in ndenumerate(grad_x):
        y = grad_y[ind]
        z = grad_z[ind]
        
        r, theta, phi = sphere_coord(ind[0], ind[1], ind[2])
        r_vec     = r_unit(theta, phi)
        theta_vec = theta_unit(theta, phi)
        phi_vec   = phi_unit(phi)
        
        grad_r[ind]     = np.dot(np.array([x, y, z]), r_vec)
        grad_phi[ind]   = np.dot(np.array([x, y, z]), phi_vec)
        grad_theta[ind] = np.dot(np.array([x, y, z]), theta_vec)
        
        r_dat[ind]     = r
        phi_dat[ind]   = phi
        theta_dat[ind] = theta
        
    return np.array(grad_r), np.array(grad_phi), np.array(grad_theta), r_dat, phi_dat, theta_dat
grad_r, grad_phi, grad_theta, r_dat, phi_dat, theta_dat = grad_sphere(grad_x, grad_y, grad_z)
matshow(r_dat[32, :, :])
matshow(phi_dat[32, :, :])
matshow(theta_dat[32, :, :])
matshow(grad_norm[43, :, :])
matshow(grad_phi[45, :, :])
matshow(grad_theta[45, :, :])
plot(grad_theta[45, 32, :])
plot(grad_phi[45, 40, :])
plot(grad_theta[45, 40, :])
plot(grad_phi[45, 40, :])
matshow(grad_theta[:, :, 60])
matshow(grad_phi[:, :, 60])
matshow(cube['con'][:, :, 60])
matshow(r_dat[:, :, 60])
matshow(theta_dat[:, :, 60])
matshow(phi_dat[:, :, 60])
def scan_theta(r, phi, theta_range, grad_x, grad_y, grad_z, r_c=centre_colloid, dr=dx):
    scan = np.zeros_like(theta_range)
    
    for i, theta in enumerate(theta_range):
        x = r_c[0] + r * np.sin(theta)*np.cos(phi)
        y = r_c[1] + r * np.sin(theta)*np.sin(phi)
        z = r_c[2] + r * np.cos(theta)
                
        i_x = int(x / dx[0])
        i_y = int(y / dx[1])
        i_z = int(z / dx[2])
        
        dphi_x = grad_x[i_x, i_y, i_z]
        dphi_y = grad_y[i_x, i_y, i_z]
        dphi_z = grad_z[i_x, i_y, i_z]
        
        e_theta = theta_unit(theta, phi)
        scan[i] = np.dot(np.array([dphi_x, dphi_y, dphi_z]), -e_theta)
    
    return scan
x = np.linspace(0, np.pi, num=100)
y_1 = scan_theta(1.4e-3, 0.0, x, grad_x, grad_y, grad_z)
y_2 = scan_theta(1.4e-3, 0.5, x, grad_x, grad_y, grad_z)
y_3 = scan_theta(1.4e-3, 1, x, grad_x, grad_y, grad_z)
plot(np.pi-x, y_1)
plot(np.pi-x, y_2)
plot(np.pi-x, y_3)
y
sel = np.abs(r_dat - 1.1e-3) < 1e-3
sum(sel)
theta_sel = theta_dat[sel]
phi_sel   = phi_dat[sel]

grad_norm_sel  = grad_norm[sel]
grad_phi_sel   = grad_phi[sel]
grad_theta_sel = grad_theta[sel]
phi_selector = np.abs(phi_sel - 0.6) < 1e-3
sum(phi_selector)
sorted_pts = np.array(sorted(zip(theta_sel[phi_selector], grad_theta_sel[phi_selector])))
plot(sorted_pts[:,0], sorted_pts[:,1])
plot(theta_sel[:100])<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1579439712471075, 'fraction_numerical': 0.051745359657328543, 'mean_word_length': 2.8971603990790484, 'pattern_counts': {'":': 1, '<': 61, '<?xml version=': 0, '>': 63, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '16', 'dir': 'jupyter-structured-clean-dedup', 'id': '133277', 'license': 'BSD-3-Clause-LBNL', 'n_tokens_mistral': 8791, 'n_tokens_neox': 8035, 'n_words': 1782, 'path': 'exec/immersed_boundary/flagellum/Explore Data MP.ipynb', 'repo_name': 'PeculiarOvertones/FHDeX', 'size': '20311'}