/////////////// TPC Group 2 ///////////

// Programmer: Till Bovermann


///////// Read Data

// Simulated data of proton-proton collisions of the TPC, one set of tracks is given, with single measured events of electron clouds reaching one of the two read-out chambers after a certain time with a certain charge

// KV, 02/2010 (Data from Matevz Tadel), prepared for SBEII



(

q = ();

q.datFiles = [1, 6, 10, 30, 96];


q.allAllTPCData = q.datFiles.collect{|ext|

var allTPCdata;

q.dataFolder = Document.current.dir ++ "/TPC_m_data_%/".format(ext);

q.myfileName = "m_data_%".format(ext);


// get all tracks including [tracknumber, # of data associated with track]:

q.headerArchive = ZArchive.read(q.dataFolder +/+ q.myfileName ++ "_tracks.zar");

q.trackInfos = q.headerArchive.readItem;

// read and post data for ONE track:

q.readTPC = { |q, index = 0|

var trackID = q.trackInfos[index][0];

var trackArchive = ZArchive.read(q.dataFolder +/+ q.myfileName ++ "_" ++ trackID ++ ".zar");

var data = trackArchive.readItem;

trackArchive.close; 

data.do { |track, i| 

track[3] = (track[4].abs)/2.6 * 100 

}; // correct time! 

data

};

// q.readTPC(14);

allTPCdata = q.trackInfos.size.collect { |i| 

var track = q.readTPC(i);

"read track %.\n".postf(i);

track

};

};

)


q.allTPCdata = q.allAllTPCData[0]


// tests

q.allTPCdata.shape;

q.allTPCdata[1].shape;



(

// get physical values at minimum of radius

q.getPhysical = {|q, trackId = 0, eventID = 0|

var minR, minIdxR, minPhi, charge, secParTheta, z, type;


// get smallest value in q.rIdx

minR    = q.allAllTPCData[eventID][trackId].flop[1].minItem;

minIdxR = q.allAllTPCData[eventID][trackId].flop[1].minIndex;

// phi at minimum of radius

minPhi = q.allAllTPCData[eventID][trackId].flop[2][minIdxR];


// deposited track charge (q)

charge = q.allAllTPCData[eventID][trackId].flop[7].sum;


// secondary Particle Theta 

// multiply by 100 to keep scaling (m -> cm)

z = q.allAllTPCData[eventID][trackId].flop[4][minIdxR] * 100; 

secParTheta = atan(z, minR);

type = q.allAllTPCData[eventID][trackId].flop[8][minIdxR];

[minR, minPhi, charge, secParTheta, type]

};

)


/* test

q.getPhysical(0, 0); // */



(

// get all physical data needed for sonification

q.physicalDatas = q.allAllTPCData.collect{|event, eventID| 

event.size.collect{|i|

[i, eventID].postln;

q.getPhysical(i, eventID);

}

};


/* tests

q.physicalDatas[1].flop.plot2;

q.allTPCdata[5].flop[1].minIndex;

q.allTPCdata[5].flop[1][12]  // */

)





// A parametermapping of the five computed attributes, tracks played in a row



(

SynthDef(\physicalMapping, {|out = 0, freq = 100, pan = 0, dur = 1, amp = 1, brilliance = 3000|

var src, env, panner;

src = LPF.ar(LFSaw.ar(freq), brilliance);

env = EnvGen.ar(Env.perc(0.01, dur-0.01), doneAction: 2);

panner = Pan2.ar(src * env, pan, amp);

Out.ar(out, panner);

}).memStore;


Tdef(\player, {

var minR,minPhi, charge, secParTheta, type, time, lastTime = 0, dt;

var freq, amp, dur, pan, brilliance;

1.do{

q.sortedData.do{|row|

# minR, minPhi, charge, secParTheta, type = row;

// mapping...

freq = type.abs + 100;

amp  = charge.linlin(0, 100000, 1, 5).reciprocal;

pan  = type.sign;

dur  = secParTheta.linlin(-0.5pi, 0.5pi, 0.1, 0.5);

time = minPhi.linlin(-pi, pi, 0, 3);

brilliance = secParTheta.linexp(-0.5pi, 0.5pi, 500, 10000);

[freq, amp, dur, pan, brilliance, time-lastTime].postln;

(time - lastTime).wait;

(instrument: \physicalMapping, freq: freq, amp: amp, pan: pan, dur: dur).play;

lastTime = time;

};

1.wait;

}

});


// trigger events

q.triggerIt = {|q, eventID = 0|

q.sortedData = q.physicalDatas[eventID].deepCopy.sort{|a, b|

a[1] < b[1]

};

Tdef(\player).play;

}

)


// do!

q.triggerIt(0);

q.triggerIt(1);

q.triggerIt(2);

q.triggerIt(3);

q.triggerIt(4);