Commit ad9a3d56 authored by Joseph Raphael Roll Bunao's avatar Joseph Raphael Roll Bunao
Browse files

Initial commit

parents
File added
This diff is collapsed.
# coding: utf-8
# In[1]:
from keras.models import model_from_json
# load json and create model
json_file = open('model_v2.json', 'r')
loaded_model_json = json_file.read()
json_file.close()
loaded_model = model_from_json(loaded_model_json)
# load weights into new model
loaded_model.load_weights("model_v2.h5")
loaded_model._make_predict_function()
print("Loaded model from disk")
# In[2]:
import numpy as np
import pandas as pd
import pickle
with open('particle_data.pkl', 'rb') as f:
all_data = pickle.load(f)
# truth = pd.read_csv('event000001000-truth.csv')
# particle = pd.read_csv('event000001000-particles.csv')
# In[3]:
from IPython.display import display, IFrame, HTML
import os
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
from dash.dependencies import Input, Output, State, Event
import os
os.environ['FLASK_ENV'] = 'development'
import logging
logger = logging.getLogger('werkzeug') ## WSGI - web server gateway interface
logger.setLevel(logging.ERROR)
def show_app(app, port=9999, width=900, height=700):
host = 'localhost'
url = f'http://{host}:{port}'
display(HTML(f"<a href='{url}' target='_blank'>Open in a new tab</a>"))
display(IFrame(url, width=width, height=height))
app.css.config.serve_locally = True
app.scripts.config.serve_locally = True
return app.run_server(debug=False, host=host, port=port)
app = dash.Dash(static_folder='assets')
# In[4]:
def particle_locations(nhit, rand_p_num):
p_hits = pd.concat([all_data[(nhit, p_num)][['tx', 'ty', 'tz']]
for p_num in rand_p_num],
axis=1)
xs = p_hits['tx']
ys = p_hits['ty']
zs = p_hits['tz']
return xs, ys, zs
def reconstruct(part_data):
preds = pd.DataFrame(part_data.iloc[0].values.reshape(1,-1))
preds.columns=['tx','ty','tz','tpx','tpy','tpz']
for i in range(len(part_data)-1):
df = pd.DataFrame(loaded_model.predict(preds.iloc[i].values.reshape(1,-1))[0]).T
df.columns=['tx','ty','tz','tpx','tpy','tpz']
preds = preds.append(df, ignore_index=True)
return preds
# In[5]:
nhit_default = 11
npart_default = 9
num_sec = 2.5
# p_num_per_hit_init = pd.DataFrame(list(all_data.keys()))
# p_num_per_hit_init = p_num_per_hit_init[p_num_per_hit_init[0]==nhit_default][1].tolist()
# rand_p_num_init = np.random.choice(p_num_per_hit_init, size=npart_default, replace=False)
# rand_p_num_init = [6003, 5486, 5358, 5360, 4752, 5201, 4864]
rand_p_num_init = [5939, 5866, 5595, 5934, 5438, 4748, 5789, 5246, 5833]
p_num_init = 5939
data_pt_init = all_data[(nhit_default, p_num_init)]
preds_init = reconstruct(data_pt_init)
# 'https://mediaarchive.cern.ch/MediaArchive/Photo/Public/2008/0803012/0803012_01/0803012_01-A4-at-144-dpi.jpg',
# 'https://home.cern/sites/home.web.cern.ch/files/image/update-for_the_public/2018/05/trackml.png',
app.callback_map = {}
app.layout = html.Div([
html.Div([
html.Div(['''
Particle Track Reconstruction
'''], className='Title'),
html.Div(['''
A Neural Network Implementation
'''], className='Subtitle'),
], className='Title-container'),
# html.Div([
html.Div([
html.Div([
'''
Particle accelerators such as the LHC (Large Hadron Collider) at
CERN (Conseil Européen pour la Recherche Nucléaire)
collide beams of particles at near the speed of light and observe the
processes that govern the aftermath of each collision event. Studying
the energies and momenta of the resulting particles gives us a better
understanding of their fundamental properties and interactions which
can lead to new and undiscovered physics.
Several detector systems, such as ATLAS (A Toroidal LHC ApparatuS) or CMS
(Compact Muon Solenoid),
form a concentric cylindrical array of detector
surfaces around the collision point. The resulting particles from the collision events
hit and pass through the array of detectors so that properties such as
their hit locations and corresponding momenta are recorded.
'''
], className='Image-description'),
html.Div([
html.Img(
src='./assets/ATLAS.jpg',
className='Image'),
html.Div([
html.Div([
'The ATLAS detector in LHC'
], className='Bold'),
], className='Image-caption'),
], className='Image-container')
], className='Description'),
html.Div(className='Line-fill'),
html.Div([
html.Div([
html.Img(
src='./assets/Tracks.png',
className='Image'),
html.Div([
html.Div([
'A Collision Event:'
], className='Bold'),
'''
White points represent the resulting particles after the
collision and red lines represent their corresponding tracks
'''
], className='Image-caption'),
], className='Image-container'),
html.Div([
'''
One essential part of the data processing is the partitioning of the
measured hit locations to form the tracks left by the particles. The
particle trajectories can then be used to extract properties such as
their mass. Traditional tracking algorithms do exist but they become
inefficient as one increases the amount of data to process. Already,
the LHC produces several petabytes of data to analyze per year
and is projected to increase further. Scientists then
turn to machine learning techniques such as deep neural
networks to efficiently reconstruct particle tracks.
To help address this, a particle tracking challenge (called TrackML) was posted
in Kaggle by a team of CERN scientists and machine learning experts.
A simulated dataset from a typical LHC detector was made available.
Specifically, the dataset contains the result of 8850 collision
events for training.
'''
], className='Image-description'),
], className='Description'),
html.Div(className='Line-fill'),
html.Div([
html.Div([
'''
We will only consider one such collision event which has around 12000
resulting particles. On the left graph below, we visualize the rescaled particle tracks
as the corresponding particles hit the detector surfaces along their
trajectories. The visualization can be paused or continued by clicking
the button on top of the graph. The aforementioned particles can be grouped
together by the number of detector surfaces they hit. On the sliders below,
we can choose this number along with the corresponding number of particles
we visualize on the graph. In order to showcase the different particles and their
corresponding trajectories, we randomize what particles we show each
time the slider values are changed. By clicking on a particle track data point on the
left graph, the right graph shows the corresponding track reconstruction result
of a fully connected, deep neural network. The true track is also displayed
for comparison. The network takes as input the initial
hit location and momentum of the particle and predicts the particle's next hit
location and momentum. This is done iteratively until the path is reconstructed.
A better implementation would be to use LSTM (Long Short-Term Memory)
neural networks because they are more adapted to sequences.
'''
], className='Image-description'),
html.Div([
html.Img(
src='./assets/NN.png',
className='Image'),
html.Div([
html.Div([
'Neural Network Architecture: '
], className='Bold'),
'''
The network takes in the particle's rescaled hit location
(x, y, z) and momentum (px, py, pz) in order to predict the next
hit location and corresponding momentum
'''
], className='Image-caption'),
], className='Image-container'),
], className='Description'),
html.Div(className='Line-fill'),
# ], className='Description-container'),
dcc.Interval(id='timer', interval=num_sec*1000),
html.Label('Particle Detector Hits', className='Slider-label'),
html.Div([
dcc.Slider(id='nhit-slider',
min= 2,
max= 15,
value=nhit_default,
marks={x : x for x in range(2, 16)},
vertical = False),
], className='Sliders'),
html.Label('Number of Particles', className='Slider-label'),
html.Div([
dcc.Slider(id='npart-slider',
min= 2,
max= 10,
value=npart_default,
marks={x : x for x in range(1, 11)},
vertical = False)
], className='Sliders'),
html.Div(id='hist', hidden=[[nhit_default,nhit_default],
[npart_default,npart_default],
rand_p_num_init]),
html.Div([
html.Button('Pause', id='button'),
], className='Line-fill'),
dcc.Graph(id='3d-graph', className='Graphs'),
html.Div(id='graph-layouts'),
dcc.Graph(id='recon-graph', className='Graphs')
], className='Container')
@app.callback(Output('timer', 'interval'),
[],
[State('timer', 'interval')],
[Event('button', 'click')])
def change_interval(inp):
if inp == num_sec*1000:
return 24*60*60*1000
else:
return num_sec*1000
@app.callback(Output('button', 'children'),
[],
[State('timer', 'interval')],
[Event('button', 'click')])
def change_btn_name(inp):
if inp == num_sec*1000:
return 'Continue'
else:
return 'Pause'
@app.callback(Output('graph-layouts', 'hidden'),
[Input('3d-graph', 'relayoutData')],
[],
[])
def put_layout(inp):
return inp
@app.callback(Output('hist', 'hidden'),
[Input('nhit-slider', 'value'),
Input('npart-slider', 'value')],
[State('hist', 'hidden')],
[Event('timer', 'interval')])
def nhit_hist(nhit, npart, hist):
nhit_prev = hist[0]
npart_prev = hist[1]
nhit_prev.append(nhit)
nhit_prev = nhit_prev[1:]
npart_prev.append(npart)
npart_prev = npart_prev[1:]
if (nhit_prev[0] != nhit) or (npart_prev[0] != npart):
p_num_per_hit = pd.DataFrame(list(all_data.keys()))
p_num_per_hit = p_num_per_hit[p_num_per_hit[0]==nhit][1].tolist()
rand_p_num = np.random.choice(p_num_per_hit, size=npart, replace=False)
else:
rand_p_num = hist[2]
return [nhit_prev, npart_prev, rand_p_num]
@app.callback(Output('3d-graph', 'figure'),
[Input('hist', 'hidden')],
[State('3d-graph', 'figure'),
State('graph-layouts', 'hidden')],
[])
def update_graph(hist, graph_data, layouts):
nhit = hist[0]
npart = hist[1]
rand_p_num = hist[2]
xs, ys, zs = particle_locations(nhit[1], rand_p_num)
if (nhit[0] != nhit[1]) or (npart[0] != npart[1]) or not graph_data:
data_out = [
go.Scatter3d(x=[xs.iloc[0, j]],
y=[ys.iloc[0, j]],
z=[zs.iloc[0, j]],
marker={'size' : 7},
line={'width' : 1},
name='Particle #' + str(rand_p_num[j]))
for j in range(npart[1])
]
else:
data = graph_data['data']
x = pd.DataFrame([p['x'] for p in data]).T
y = pd.DataFrame([p['y'] for p in data]).T
z = pd.DataFrame([p['z'] for p in data]).T
x.columns = ['tx']*npart[1]
y.columns = ['ty']*npart[1]
z.columns = ['tz']*npart[1]
i = x.shape[0] % (nhit[1] + 1)
if i == 0:
x = xs.iloc[0].to_frame().T
y = ys.iloc[0].to_frame().T
z = zs.iloc[0].to_frame().T
else:
x = x.append(xs.iloc[i])
y = y.append(ys.iloc[i])
z = z.append(zs.iloc[i])
data_out = [
go.Scatter3d(x=x.iloc[:, j],
y=y.iloc[:, j],
z=z.iloc[:, j],
marker={'size' : 7},
line={'width' : 1},
name='Particle #' + str(rand_p_num[j]))
for j in range(npart[1])
]
if layouts and ('scene.camera' in layouts.keys()):
camera = layouts['scene.camera']
else:
camera = {
'up': {'x': 0, 'y': 0, 'z': 1},
'center': {'x': 0, 'y': 0, 'z': 0},
'eye': {'x': 1.25, 'y': 1.25, 'z': 1.25}
}
scene = {
'camera' : camera,
'aspectratio' : {'x' : 1, 'y' : 1, 'z' : 1},
'aspectmode' : 'manual',
'xaxis' : {
'title' : 'X',
'range' : [-1.1, 1.1],
'dtick' : 0.5
},
'yaxis' : {
'title' : 'Y',
'range' : [-1.1, 1.1],
'dtick' : 0.5
},
'zaxis' : {
'title' : 'Z (Beam direction)',
'range' : [-1.1, 1.1],
'dtick' : 0.5
}
}
return {
'data' : data_out,
'layout' : go.Layout(
title='(Rescaled) Particle Tracks',
scene=scene,
legend={
'orientation' : 'h'
}
)
}
@app.callback(Output('recon-graph', 'figure'),
[Input('3d-graph', 'clickData')],
[State('hist', 'hidden')])
def graph_input_select(graph_input, hist):
if not graph_input:
return {
'data' : [go.Scatter3d(x=data_pt_init['tx'],
y=data_pt_init['ty'],
z=data_pt_init['tz'],
name='True Particle Trajectory'),
go.Scatter3d(x=preds_init['tx'],
y=preds_init['ty'],
z=preds_init['tz'],
name='Reconstructed Particle Trajectory')],
'layout' : go.Layout(
title='Particle #'+ str(p_num_init) +' Track Reconstruction',
scene={
'aspectratio' : {'x' : 1, 'y' : 1, 'z' : 1},
'aspectmode' : 'manual',
'xaxis' : {
'title' : 'X',
'range' : [-1.1, 1.1],
'dtick' : 0.5
},
'yaxis' : {
'title' : 'Y',
'range' : [-1.1, 1.1],
'dtick' : 0.5
},
'zaxis' : {
'title' : 'Z (Beam direction)',
'range' : [-1.1, 1.1],
'dtick' : 0.5
}
},
legend={
'orientation' : 'h'
}
)
}
else:
curveNumber = graph_input['points'][0]['curveNumber']
nhit = hist[0][1]
rand_p_num = hist[2]
data_pt = all_data[(nhit, rand_p_num[curveNumber])]
preds = reconstruct(data_pt)
return {
'data' : [go.Scatter3d(x=data_pt['tx'],
y=data_pt['ty'],
z=data_pt['tz'],
name='True Particle Trajectory'),
go.Scatter3d(x=preds['tx'],
y=preds['ty'],
z=preds['tz'],
name='Reconstructed Particle Trajectory')],
'layout' : go.Layout(
title='Particle #'+ str(rand_p_num[curveNumber]) +' Track Reconstruction',
scene={
'aspectratio' : {'x' : 1, 'y' : 1, 'z' : 1},
'aspectmode' : 'manual',
'xaxis' : {
'title' : 'X',
'range' : [-1.1, 1.1],
'dtick' : 0.5
},
'yaxis' : {
'title' : 'Y',
'range' : [-1.1, 1.1],
'dtick' : 0.5
},
'zaxis' : {
'title' : 'Z (Beam direction)',
'range' : [-1.1, 1.1],
'dtick' : 0.5
}
},
legend={
'orientation' : 'h'
}
)
}
show_app(app, port=5555)
# In[ ]:
# import pickle
# with open('particle_data.pkl', 'wb') as f:
# pickle.dump(all_data, f, pickle.HIGHEST_PROTOCOL)
# In[ ]:
# with open('particle_data.pkl', 'rb') as f:
# test = pickle.load(f)
/* Table of contents
––––––––––––––––––––––––––––––––––––––––––––––––––
- Plotly.js
- Grid
- Base Styles
- Typography
- Links
- Buttons
- Forms
- Lists
- Code
- Tables
- Spacing
- Utilities
- Clearing
- Media Queries
*/
/* PLotly.js
–––––––––––––––––––––––––––––––––––––––––––––––––– */
/* plotly.js's modebar's z-index is 1001 by default
* https://github.com/plotly/plotly.js/blob/7e4d8ab164258f6bd48be56589dacd9bdd7fded2/src/css/_modebar.scss#L5
* In case a dropdown is above the graph, the dropdown's options
* will be rendered below the modebar
* Increase the select option's z-index
*/
/* This was actually not quite right -
dropdowns were overlapping each other (edited October 26)
.Select {
z-index: 1002;
}*/
/* Grid
–––––––––––––––––––––––––––––––––––––––––––––––––– */
.container {
position: relative;
width: 100%;
max-width: 960px;
margin: 0 auto;
padding: 0 20px;
box-sizing: border-box; }
.column,
.columns {
width: 100%;
float: left;
box-sizing: border-box; }
/* For devices larger than 400px */
@media (min-width: 400px) {
.container {
width: 85%;
padding: 0; }
}
/* For devices larger than 550px */
@media (min-width: 550px) {
.container {
width: 80%; }
.column,
.columns {
margin-left: 4%; }
.column:first-child,
.columns:first-child {
margin-left: 0; }
.one.column,
.one.columns { width: 4.66666666667%; }
.two.columns { width: 13.3333333333%; }
.three.columns { width: 22%; }
.four.columns { width: 30.6666666667%; }
.five.columns { width: 39.3333333333%; }
.six.columns { width: 48%; }
.seven.columns { width: 56.6666666667%; }
.eight.columns { width: 65.3333333333%; }
.nine.columns { width: 74.0%; }
.ten.columns { width: 82.6666666667%; }
.eleven.columns { width: 91.3333333333%; }
.twelve.columns { width: 100%; margin-left: 0; }
.one-third.column { width: 30.6666666667%; }