Commit 7ba0f6c4 authored by Breno Rilho Lemos's avatar Breno Rilho Lemos 💬

Merge branch 'animation_config' into 'master'

Animation config

See merge request !4
parents 598c9220 dadf3f9d
......@@ -2,9 +2,9 @@
## Project Description
This project has the purpose of generating a 3D animation of an ALICE particle collision event, inside the LHC, using data obtained from CERN's Open Data Portal, which makes ESDs - Event Summary Data files, that contain information about such events - open and available for analysis.
This project has the purpose of generating 3D animations of ALICE particle collision events, inside the LHC, using data obtained from CERN's Open Data Portal, which makes ESDs - Event Summary Data files, that contain information about such events - open and available for analysis.
ESD files regarding the ALICE experiment can be found on http://opendata.cern.ch/search?page=1&size=20&experiment=ALICE, and they should be processed using the Aliroot software, as indicated in the 'Aliroot' section below.
ESD files regarding the ALICE experiment can be found on http://opendata.cern.ch/search?page=1&size=20&experiment=ALICE, and they should be somehow referenced along the process, as explained further.
The software that makes the animation is Blender, which is free and open source. Blender's 2.79b version should be downloaded for this project, and can be found on https://www.blender.org/download/releases/2-79/
......@@ -17,19 +17,13 @@ git clone https://git.cta.if.ufrgs.br/ALICE-open-data/alice-blender-animation.gi
The animation making can be summarized in three basic steps:
1) Downloading an ESD file;
2) Installing aliRoot and running macros;
3) Run bash to generate Blender animation using the ESD processing results.
1) Installing aliRoot;
2) Getting an ESD file;
3) Run script to process ESD data and generate Blender animations using its results.
In case you are not conCERNed about the data being used for the animation and only wish to generate a standard one, skip to the Default Animation section below. For detailed steps on how to make the animation from ESDs, as described above, read the following sections.
## Step 1 - Downloading ESD files
ESD files regarding the ALICE experiment can be found on http://opendata.cern.ch/search?page=1&size=20&experiment=ALICE. If you have doubts on which file to pick for a test, you can select any file on this list: http://opendata.cern.ch/record/1102.
You must save your ESD file inside the 'aliRoot' directory, which is obtained by cloning this repository as mentioned above.
## Step 2 - Installing aliRoot
## Step 1 - Installing aliRoot
Here is the sequence of steps for installing aliRoot, so you are able to process the relevant information for the project.
......@@ -50,82 +44,42 @@ $ aliDoctor AliPhysics
```bash
aliBuild build AliPhysics --defaults user -z aliroot5
```
5) Enter AliPhysics environment
```bash
alienv enter AliPhysics/latest-aliroot5-user
```
6) Run the macro with number of ESD event as an input
```bash
cd ~/alice/alice-blender-animation/aliRoot
aliroot -q -b "runAnalysis.C(7)"
```
Number seven is just an example. An empty input will do the analysis on event number 0.
## Step 2 - Getting an ESD file
With the last step, ESD analysis results will be saved on a text file called `esd-detail.dat`. You must then move this file into the 'animate' folder, where the Blender scripts are.
ESD files regarding the ALICE experiment can be found on http://opendata.cern.ch/search?page=1&size=20&experiment=ALICE. If you have doubts on which file to pick for a test, you can select any file on this list: http://opendata.cern.ch/record/1102.
Here, there are two options from which you can choose:
## Step 3 - Generating animation
- the first one is to download your ESD file and save it in the `alice-blender-animation` directory, which was cloned from the git repository. Make sure you save it on the same path as this `README.md` file and the `workflow_sketch.sh` script, not inside the "aliRoot" or "animate" directories. Also make sure the file is named `AliESDs.root`.
Go inside the 'animate' directory:
- the second one is to copy the URL for the ESD file (the address you would click to download it) and paste it on the command line when you run the script that generates the animation, according to the next section.
```bash
cd ~/alice/alice-blender-animation/animate
```
## Step 3 - Generating animation
Run the python script `animate_particles.py` as in the example below:
Once you are all set, run the `workflow_sketch.sh` script through your terminal in the following way:
```bash
blender -noaudio --background -P animate_particles.py -- -radius=0.05 -duration=10 -camera="OverviewCamera" -datafile="esd-detail.dat" -simulated_t=0.02 -fps=24 -resolution=100
./workflow_sketch.sh <DOWNLOAD> <URL>
```
where everything that follows the double dashes are input arguments for generating the animation. Here is what each argument means:
-radius:
particle radius; must be a number; type float
where <DOWNLOAD> is either "true" of "false", depending on whether you wish to download the ESD file or just go with the one you have already downloaded.
-duration:
If you type in "true", fill in the <URL> field with your ESD's URL, copied in the previous section. The code will then automatically download and run the analysis on the file.
animation duration, in seconds; must be a number; type int
If you type in "false" - in which case you should have downloaded the ESD file yourself - just leave the <URL> field blank.
Have in mind that it will take a long time to generate all the animations.
-camera:
defines animation point of view; must be a string; available options: "OverviewCamera", "BarrelCamera", "ForwardCamera"
-datafile:
filename for event data file; must be a string; must the name your text file: "esd-detail.dat"
-simulated_t:
simulated time of event, in microsseconds; must be a number; type float
-fps:
frames per second; must be a number; type int
-resolution:
animation resolution percent; must be a number; type int
After running the script, your Blender animation should be ready! It will be saved in format .mp4 on the address `/tmp/blender`. Enjoy!
After running the script, your Blender animations should be ready! For each event inside the ESD file, there will be three animations saved in .mp4 format, each one corresponding to a different view of the event. They will be available inside the `output` directory. Enjoy!
# Default Animation
For generating a default animation, simply run the animation python code inside the 'animate' folder, using the `d-esd-detail.dat` file (where 'd' is for 'default') as the input file, as showed below:
For generating a default animation, simply run the script `workflow_sketch.sh` in your terminal as below:
```bash
cd ~/alice/alice-blender-animation/animate
blender -noaudio --background -P animate_particles.py -- -radius=0.05 -duration=10 -camera="BarrelCamera" -datafile="d-esd-detail.dat" -simulated_t=0.02 -fps=24 -resolution=100
./workflow_sketch.sh 0 0 true
```
After running the script, your Blender animation should be ready! It will be saved in format .mp4 on the address `/tmp/blender`. Enjoy!
After this, a single default animation should be ready. It will be available inside the `output` directory, in mp4 format. Enjoy!
......@@ -34,9 +34,6 @@
Int_t esd_event_id = 0; // global variable to store unique event id
Int_t smallEventID = 0; // is equal to esd-event-id until the selected event (one with an appropriate number of tracks) is reached
Int_t mediumEventID = 0; // for events with ~200 tracks
Int_t largeEventID = 0; // for events with many many tracks
class AliAnalysisTaskMyTask; // your analysis class
......@@ -127,69 +124,82 @@ void AliAnalysisTaskMyTask::UserExec(Option_t *)
s_event >> selectedEventID;
s_event.close();
ofstream esd_detail;
esd_detail.open ("esd-detail.dat",std::ofstream::app);
if(selectedEventID == -1) {
ofstream events_number;
events_number.open ("events_number.dat",std::ofstream::out);
fESD = dynamic_cast<AliESDEvent*>(InputEvent()); // get an event (called fESD) from the input file
events_number << esd_event_id+1;
// there's another event format (ESD) which works in a similar way
events_number.close();
} else {
if(!fESD) return; // if the pointer to the event is empty (getting it failed) skip this event
// example part: i'll show how to loop over the tracks in an event
// and extract some information from them which we'll store in a histogram
ofstream esd_detail;
esd_detail.open ("esd-detail.dat",std::ofstream::app);
Int_t iTracks(fESD->GetNumberOfTracks()); // see how many tracks there are in the event
Double_t Vx = 0.01 * fESD->GetPrimaryVertex()->GetX(); // gets vertexes from individual events, in METERS
Double_t Vy = 0.01 * fESD->GetPrimaryVertex()->GetY();
Double_t Vz = 0.01 * fESD->GetPrimaryVertex()->GetZ();
Double_t MagneticField = 0.1 * fESD->GetMagneticField(); // gets magnetic field, in TESLA
fESD = dynamic_cast<AliESDEvent*>(InputEvent()); // get an event (called fESD) from the input file
// there's another event format (ESD) which works in a similar way
/*
Assumed Units: Mass (GeV/c^2)[CONFIRMED] || Energy (GeV) || Momentum (GeV/c) || Charge (* 1.6*10^-19 C)
if(!fESD) return; // if the pointer to the event is empty (getting it failed) skip this event
// example part: i'll show how to loop over the tracks in an event
// and extract some information from them which we'll store in a histogram
*/
Int_t iTracks(fESD->GetNumberOfTracks()); // see how many tracks there are in the event
if(selectedEventID == esd_event_id) { // when we get to the selected event, fill histograms and write data
Double_t Vx = 0.01 * fESD->GetPrimaryVertex()->GetX(); // gets vertexes from individual events, in METERS
Double_t Vy = 0.01 * fESD->GetPrimaryVertex()->GetY();
Double_t Vz = 0.01 * fESD->GetPrimaryVertex()->GetZ();
Double_t MagneticField = 0.1 * fESD->GetMagneticField(); // gets magnetic field, in TESLA
for(Int_t i(0); i < iTracks; i++) { // loop over all these tracks
AliESDtrack* track = static_cast<AliESDtrack*>(fESD->GetTrack(i)); // get a track (type AliESDtrack) from the event
/*
if(!track) continue; // if we failed, skip this track
Assumed Units: Mass (GeV/c^2)[CONFIRMED] || Energy (GeV) || Momentum (GeV/c) || Charge (* 1.6*10^-19 C)
Double_t Mass = track->M(); // returns the pion mass, if the particle can't be identified properly
Double_t Energy = track->E(); // Returns the energy of the particle given its assumed mass, but assumes the pion mass if the particle can't be identified properly.
*/
Double_t Px = track->Px();
Double_t Py = track->Py();
Double_t Pt = track->Pt(); // transversal momentum, in case we need it
Double_t Pz = track->Pz();
if(selectedEventID == esd_event_id) { // when we get to the selected event, fill histograms and write data
Double_t Charge = track->Charge();
for(Int_t i(0); i < iTracks; i++) { // loop over all these tracks
// Add VERTEX (x, y, z), MASS, CHARGE and MOMENTUM (x, y, z) to esd-detail.dat file
esd_detail << Vx << " " << Vy << " " << Vz << " ";
esd_detail << Mass << " " << Charge << " ";
esd_detail << Px << " " << Py << " " << Pz << endl;
AliESDtrack* track = static_cast<AliESDtrack*>(fESD->GetTrack(i)); // get a track (type AliESDtrack) from the event
fHistPt->Fill(Pt); // plot the pt value of the track in a histogram
if(!track) continue; // if we failed, skip this track
fHistMass->Fill(Mass);
Double_t Mass = track->M(); // returns the pion mass, if the particle can't be identified properly
Double_t Energy = track->E(); // Returns the energy of the particle given its assumed mass, but assumes the pion mass if the particle can't be identified properly.
}
Double_t Px = track->Px();
Double_t Py = track->Py();
Double_t Pt = track->Pt(); // transversal momentum, in case we need it
Double_t Pz = track->Pz();
}
Double_t Charge = track->Charge();
// Add VERTEX (x, y, z), MASS, CHARGE and MOMENTUM (x, y, z) to esd-detail.dat file
esd_detail << Vx << " " << Vy << " " << Vz << " ";
esd_detail << Mass << " " << Charge << " ";
esd_detail << Px << " " << Py << " " << Pz << endl;
fHistPt->Fill(Pt); // plot the pt value of the track in a histogram
fHistMass->Fill(Mass);
}
}
esd_detail.close();
}
Event++;
esd_event_id++; // Increment global esd_event_id
fHistEvents->Fill(Event);
esd_detail.close();
// continue until all the tracks are processed
PostData(1, fOutputList); // stream the results the analysis of this event to
......
......@@ -9,7 +9,10 @@
int runAnalysis(int selected_event=0)
{
// Erase output txt files
ofstream esd_detail, s_event;
ofstream esd_detail, s_event, events_number;
events_number.open ("events_number.dat");
events_number.close();
s_event.open ("s-event.dat");
s_event << selected_event;
......@@ -43,7 +46,7 @@ int runAnalysis(int selected_event=0)
TChain* chain = new TChain("esdTree");
// add a few files to the chain (change this so that your local files are added)
chain->Add("AliESDs.root"); // Breno put it on the same directory that was cloned from Pezzi's // repository: AliESD_Example
chain->Add("AliESDs2.root");
//chain->Add("AliESDs2.root");
//chain->Add("../root_files/AliAOD.Muons2.root");
//chain->Add("../root_files/AliAOD.Muons3.root");
......
......@@ -2,7 +2,7 @@
# animate_particles.py - Animate HEP events
#
# For console only rendering (example):
# $ blender -noaudio --background -P animate_particles.py -- -radius=0.05 -duration=1 -camera="BarrelCamera" -datafile="esd-detail.dat" -simulated_t=0.02 -fps=24 -resolution=100 -stamp_note="Texto no canto"
# $ blender -noaudio --background -P animate_particles.py -- -radius=0.05 -duration=1 -camera="BarrelCamera" -datafile="esd-detail.dat" -n_event=0 -simulated_t=0.02 -fps=24 -resolution=100 -stamp_note="Texto no canto"
#
import os
......@@ -34,6 +34,7 @@ parser.add_argument('-simulated_t','--simulated_t')
parser.add_argument('-fps','--fps')
parser.add_argument('-resolution','--resolution_percent')
parser.add_argument('-stamp_note','--stamp_note')
parser.add_argument('-n_event','--n_event')
args = parser.parse_args()
bpy.context.user_preferences.view.show_splash = False
......@@ -43,6 +44,7 @@ exec(compile(open(filename).read(), filename, 'exec'))
# Set animation parameters
r_part = float(args.r_part) # Particle radius
n_event = str(args.n_event) # Event number for video name
simulated_t = float(args.simulated_t) # in microsseconds
duration = int(args.duration) # in seconds
fps = int(args.fps)
......@@ -65,7 +67,7 @@ driver.configure(renderCamera, duration, fps, simulated_t, outputPath, fileIdent
"""
# Create and configure animation driver
driver = dataDriver("AlirootFileGenerator",args.datafile) # Simple dataDriver takes one parameters: filename
driver = dataDriver("AlirootFileGenerator",n_event,args.datafile) # Simple dataDriver takes one parameters: filename
driver.configure(renderCamera, duration, fps, simulated_t, outputPath, fileIdentifier, resolution_percent)
### Build scene
......
......@@ -46,7 +46,7 @@ class animationDriver:
bcsr.ffmpeg.packetsize = 2048
bcsr.ffmpeg.muxrate = 10080000
xpixels = int(bcsr.resolution_percentage * bcsr.resolution_x / 100)
output_prefix=fileIdentifier+str(xpixels)+"px_"+self.name
output_prefix=fileIdentifier+str(xpixels)+"px_"+self.name+self.renderCamera
bcsr.filepath = "/tmp/blender/"+output_prefix
class genDriver(animationDriver): # A driver for particle generators
......@@ -68,8 +68,8 @@ class genDriver(animationDriver): # A driver for particle generators
return particles;
class dataDriver(animationDriver): # A driver for data from files.
def __init__(self,name,datafile):
self.name = name+"_"+datafile+"_"
def __init__(self,name,nEvent,datafile):
self.name = name+"_"+datafile+"_Event_"+nEvent+"_"
self.datafile = datafile
def getParticles(self): # Create particles acording to parameters from file
# Count number of lines in file = number of particles
......
......@@ -12,7 +12,7 @@ export BLENDER_SCRIPT_DIR=$(pwd)/animate/
# Directory where output animations should be placed
export BLENDER_OUTPUT=$(pwd)/output/
# alienv working directory
export ALIENV_WORK_DIR=/mnt/SSD/schnorr/ALICE/sw/
export ALIENV_WORK_DIR=/home/tropos/alice/sw
export ALIENV_ID=AliPhysics/latest-aliroot5-user
# Put blender 2.79b in the PATH env var
export PATH="/home/schnorr/install/blender-2.79-linux-glibc219-x86_64/:$PATH"
......@@ -22,60 +22,119 @@ export PATH="/home/schnorr/install/blender-2.79-linux-glibc219-x86_64/:$PATH"
##############################
function usage()
{
echo "$0 <URL> <DOWNLOAD>";
echo "$0 <DOWNLOAD> <URL> [DEFAULT_ANIMATION]";
echo " where <URL> is a URL to uniquely identify a dataset";
echo " where <DOWNLOAD> is true or false, indicate whether the dataset should be downloaded";
echo " where <DEFAULT_ANIMATION> is optional, either true or false, to indicate if the default animation should be generated";
echo " leaving <DEFAULT_ANIMATION> blank will generate custom animation from data file";
}
##############################
# Parse Parameters #
##############################
URL=$1
if [ -z $URL ]; then
echo "Error. Must pass the dataset URL."
usage
exit
fi
DOWNLOAD=$2
DOWNLOAD=$1
if [ -z $DOWNLOAD ]; then
echo "Error. Must explicitely inform whether to download the dataset or not."
usage
exit
fi
URL=$2
DEFAULT_ANIMATION=$3
if [ -z $DEFAULT_ANIMATION ]; then
DEFAULT_ANIMATION="false"
fi
##############################
# Download Dataset #
##############################
if [ "$DOWNLOAD" = "true" ]; then
if [ -z $URL ]; then
echo "Error. Must pass the dataset URL."
usage
exit
fi
echo "Downloading data."
wget $URL
fi
# Verify if AliESDs.root is here
ALIESD_ROOT_FILE=$(pwd)/AliESDs.root
##############################
# Phase 1: aliroot extract #
# Default animation #
##############################
eval $(alienv -w ${ALIENV_WORK_DIR} -a ubuntu1604_x86-64 load ${ALIENV_ID})
pushd ${ALIROOT_SCRIPT_DIR}
rm --verbose AliESDs.root
ln --verbose -s $ALIESD_ROOT_FILE AliESDs.root
aliroot runAnalysis.C
for type in s m l; do
ls -lh ${type}-esd-detail.dat
done
popd
if [ "$DEFAULT_ANIMATION" = "true" ]; then
echo "Preparing default animation."
##############################
# Phase 1: blender animate #
##############################
pushd ${BLENDER_SCRIPT_DIR}
blender -noaudio --background -P animate_particles.py -- -radius=0.05 -duration=2 -camera="OverviewCamera" -datafile="d-esd-detail.dat" -simulated_t=0.02 -fps=5 -resolution=100 -stamp_note="Texto no canto"
popd
mkdir --verbose -p ${BLENDER_OUTPUT}
mv --verbose /tmp/blender ${BLENDER_OUTPUT}
echo "Done."
fi
##############################
# Phase 2: blender animate #
# Animation from file #
##############################
for type in s m l; do
mv --verbose ${ALIROOT_SCRIPT_DIR}/${type}-esd-detail.dat ${BLENDER_SCRIPT_DIR}
done
pushd ${BLENDER_SCRIPT_DIR}
blender -noaudio --background -P animate_particles.py -- -radius=0.05 -duration=10 -camera="BarrelCamera" -datafile="d-esd-detail.dat" -simulated_t=0.02 -fps=24 -resolution=100
popd
mkdir --verbose -p ${BLENDER_OUTPUT}
mv --verbose /tmp/blender ${BLENDER_OUTPUT}
echo "Done."
if [ "$DEFAULT_ANIMATION" = "false" ]; then
# Verify if AliESDs.root is here
ALIESD_ROOT_FILE=$(pwd)/AliESDs.root
if ! [[ -f "$ALIESD_ROOT_FILE" ]]
then
echo "AliESDs.root not found."
exit
fi
# Create directory where animations will be saved
mkdir --verbose -p ${BLENDER_OUTPUT}
# Move ESD file to aliRoot directory
mv --verbose $(pwd)/AliESDs.root ${ALIROOT_SCRIPT_DIR}
##############################
# Phase 1: aliroot extract #
##############################
eval $(alienv -w /home/tropos/alice/sw -a ubuntu1804_x86-64 load ${ALIENV_ID}) #-w ${ALIENV_WORK_DIR} -a ubuntu1604_x86-64 load ${ALIENV_ID})
pushd ${ALIROOT_SCRIPT_DIR}
aliroot -q -b "runAnalysis.C(-1)"
ls -lh events_number.dat
n_events=`more events_number.dat` # stores number of events in ESD file
if ! [[ "$n_events" =~ ^[0-9]+$ ]] # verifies whether n_events is an integer
then
echo "Failed to extract number of events from file."
exit
fi
for ((i=0; i<n_events; i++))
do
aliroot -q -b "runAnalysis.C($i)"
ESD_DETAIL=${ALIROOT_SCRIPT_DIR}/esd-detail.dat
if ! [[ -f "$ESD_DETAIL" ]]
then
echo "ERROR: aliRoot analysis on event $i went wrong."
fi
##############################
# Phase 2: blender animate #
##############################
mv --verbose ${ALIROOT_SCRIPT_DIR}/esd-detail.dat ${BLENDER_SCRIPT_DIR}
pushd ${BLENDER_SCRIPT_DIR}
for type in "BarrelCamera" "OverviewCamera" "ForwardCamera"; do
blender -noaudio --background -P animate_particles.py -- -radius=0.05 -duration=1 -camera=${type} -datafile="esd-detail.dat" -n_event=$i -simulated_t=0.02 -fps=5 -resolution=50 -stamp_note="Texto no canto"
echo "${type} for event $i done."
done
popd
echo "EVENT $i DONE."
done
popd
# Move animation directory to local folder
mv --verbose /tmp/blender ${BLENDER_OUTPUT}
fi
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment