Author: [log in to unmask]
Date: Thu Feb 26 11:12:44 2015
New Revision: 2212
Log:
LedAnalysis driver commit
Modified:
java/trunk/users/src/main/java/org/hps/users/celentan/LedAnalysis.java
Modified: java/trunk/users/src/main/java/org/hps/users/celentan/LedAnalysis.java
=============================================================================
--- java/trunk/users/src/main/java/org/hps/users/celentan/LedAnalysis.java (original)
+++ java/trunk/users/src/main/java/org/hps/users/celentan/LedAnalysis.java Thu Feb 26 11:12:44 2015
@@ -21,6 +21,9 @@
import org.lcsim.util.Driver;
import org.lcsim.util.aida.AIDA;
+/* This is the driver used to determine the response of each calorimeter channel after a LED run
+ * @author Andrea Celentano <[log in to unmask]>
+ */
public class LedAnalysis extends Driver{
private static final int NUM_CHANNELS = 11 * 47;
@@ -31,10 +34,14 @@
DatabaseConditionsManager conditionsManager;
- EcalChannelCollection ChannelCollection;
- EcalLedCollection LedCollection;
+ private EcalChannelCollection ChannelCollection;
+ private EcalLedCollection LedCollection;
+ private EcalConditions ecalConditions;
+
Map < Integer,Integer > LedTopMap;
Map < Integer,Integer > LedBotMap;
+
+ private boolean useRawEnergy=false;
private int id,row,column,chid,ledid,driverid;
private int eventN = 0;
@@ -55,14 +62,31 @@
private int[] iStep = new int[nDrivers];
private int[] nEvents = new int[NUM_CHANNELS];
+
+ private double energy,rawEnergy;
+ private long cellID;
//Histograms
+ private ArrayList<ITuple> iTuple;
+ private ArrayList<IProfile1D> cProfile;
+ private ArrayList<IFunction> fFunction;
+
private ArrayList<IHistogram1D> hRaw;
- private ArrayList<ICloud1D> hStrip;
+ private ArrayList<IHistogram1D> hStrip;
+
+ public void setUseRawEnergy(boolean useRawEnergy) {
+ this.useRawEnergy=useRawEnergy;
+ }
+
+
@Override
protected void detectorChanged(Detector detector) {
System.out.println("LedAnalysis::Detector changed was called");
+ for (int ii=0;ii<nDrivers;ii++){
+ iStep[ii]=-1;
+ }
+
// Setup conditions
conditionsManager = DatabaseConditionsManager.getInstance();
@@ -72,6 +96,8 @@
ChannelCollection = conditionsManager.getCollection(EcalChannelCollection.class);
LedCollection = conditionsManager.getCollection(EcalLedCollection.class);
+ ecalConditions = conditionsManager.getCachedConditions(EcalConditions.class, TableConstants.ECAL_CONDITIONS).getCachedData();
+
for (EcalChannel channel : ChannelCollection){
chid = channel.getChannelId();
@@ -93,19 +119,20 @@
aida.tree().cd("/");
// IPlotterFactory factory= aida.analysisFactory().createPlotterFactory("ECAL DAQ Plots");
+ iTuple = new ArrayList<ITuple>(NUM_CHANNELS);
+ cProfile= new ArrayList<IProfile1D>(NUM_CHANNELS);
+ fFunction= new ArrayList<IFunction>(NUM_CHANNELS);
hRaw = new ArrayList<IHistogram1D>(NUM_CHANNELS);
- hStrip = new ArrayList<ICloud1D>(NUM_CHANNELS);
+ hStrip = new ArrayList<IHistogram1D>(NUM_CHANNELS);
for (int ii=0;ii<NUM_CHANNELS;ii++){
int row = EcalMonitoringUtilities.getRowFromHistoID(ii);
- int column = EcalMonitoringUtilities.getColumnFromHistoID(ii);
-
- // Initialize the histograms for the current crystal channel.
- hRaw.add(aida.histogram1D("h1_"+ii, 1000, -1,30));
- hStrip.add(aida.cloud1D("strip_"+ii,100000));
+ int column = EcalMonitoringUtilities.getColumnFromHistoID(ii);
+ iTuple.add(aida.analysisFactory().createTupleFactory(aida.tree()).create("nTuple"+ii,"nTuple"+ii,"int fEvn=0 , double fCharge=0.",""));
+
}
}
@@ -121,9 +148,19 @@
column = hit.getIdentifierFieldValue("ix");
row = hit.getIdentifierFieldValue("iy");
id = EcalMonitoringUtilities.getHistoIDFromRowColumn(row, column);
-
+ cellID=hit.getCellID();
+ energy = hit.getCorrectedEnergy();
+
+ if (useRawEnergy){
+ rawEnergy = getRawADCSum(energy,cellID);
+ }
+ else {
+ rawEnergy = energy;
+ }
+
+
//find the LED
- chid = ChannelCollection.findGeometric(hit.getCellID()).getChannelId();
+ chid = ChannelCollection.findGeometric(cellID).getChannelId();
if (row>0){
ledid=LedTopMap.get(chid);
}
@@ -137,13 +174,22 @@
if (iStep[driverid]<(nSteps-1)){
if (ledid==LEDStep[driverid][iStep[driverid]+1]){
iStep[driverid]++;
- System.out.println("LedAnalysis:: increment step "+driverid+" "+ledid+" "+column+" "+row+" "+id);
+ System.out.println("LedAnalysis:: increment step for driver "+driverid+" "+ledid+" "+column+" "+row+" "+id);
}
}
+
+ if (iStep[driverid]==-1) continue;
+
/*Case 1: this led is the one in the corresponding step*/;
if (ledid==LEDStep[driverid][iStep[driverid]]){
- hRaw.get(id).fill(hit.getCorrectedEnergy());
- hStrip.get(id).fill(nEvents[id],hit.getCorrectedEnergy());
+ //hRaw.get(id).fill(rawEnergy);
+ //cStrip.get(id).fill(nEvents[id],rawEnergy);
+
+ iTuple.get(id).fill(0,nEvents[id]);
+ iTuple.get(id).fill(1,rawEnergy);
+ iTuple.get(id).addRow();
+
+
nEvents[id]++;
}
else{ /*Case 2: this led is not one in the corresponding step (but maybe is the neighborhood??Ctalk??)*/;
@@ -153,10 +199,104 @@
}
}
}
+
+ /*
+ * The endOfData() method analises each ntuple to find the LED response.
+ * We cannot simply fit a gaussian to the energy distribution, since there is a high-energy tail due to the LED being turned on:
+ * When the LED turns on, it is "cold", and emits more light. Immediately, it starts to heat, and due to temperature effects the
+ * emitted light is less. This is clearly visible if one plots the charge VS the event number: the trend is decreasing, toward a
+ * plateau, that corresponds to the value at thermal equilibrium.
+ *
+ * For (few) channels, the first charge values are close to 0, then charge grows rapidly, then it returns back to the plateau.
+ * To handle these, I always cut the first 10% events
+ * To properly handle this:
+ *
+ * 1) First create a profile histogram, charge VS event number.
+ * 2) Fit it with something like "A*exp(-event_number/N0)+C. The function does not need to be extra-accurate at this stage
+ * 3) Cut the events with event_number < 5*N0.
+ * 4) Fit the remaining events with a gaussian.
+ */
@Override
public void endOfData() {
System.out.println("LedAnalysis::end of data");
- }
+
+
+ double e,eMin,eMax;
+ int n,nBins;
+
+ double skip=0.1;
+
+ IFunctionFactory fFactory=aida.analysisFactory().createFunctionFactory(aida.tree());
+ IPlotter pPlotter= aida.analysisFactory().createPlotterFactory().create();
+ IFitResult fResult;
+ IFitter fFitter;
+
+ for (int id = 0; id < 11 * 47; id++) {
+
+ eMin=9999;
+ eMax=-9999;
+ row = EcalMonitoringUtilities.getRowFromHistoID(id);
+ column = EcalMonitoringUtilities.getColumnFromHistoID(id);
+
+ /*Create the profile. Create it for all the channels, to keep sync.*/
+ nBins=nEvents[id]/100;
+ if (nBins<=0) nBins=1;
+ cProfile.add(aida.profile1D("strip_"+id,nBins,-0.5,nEvents[id]*(1-skip)+0.5));
+
+ /*Create the function for the profile fit*/
+ /* Create it for all the channels, to keep sync.*/
+ fFunction.add(fFactory.createFunctionFromScript("fun0_"+id,1,"A*exp(-x[0]/tau)+B","A,tau,B","",null));
+
+
+ if (EcalMonitoringUtilities.isInHole(row,column)==true) continue;
+ if (nEvents[id]==0) {
+ //System.out.println("LedAnalysis: channel x= "+column+" y= "+row+" not found");
+ continue;
+ }
+
+ /*Fill the profile*/
+ iTuple.get(id).start();
+ iTuple.get(id).skip((int)(nEvents[id]*skip)); /*This is the work-around for those channels with charge starting from 0 and rapidly growing*/
+ n=0;
+ while ( iTuple.get(id).next() ){
+ e=iTuple.get(id).getDouble(1);
+ if (e>eMax) eMax=e;
+ if (e<eMin) eMin=e;
+ cProfile.get(id).fill(1.*n,e);
+ n++;
+ }
+
+
+ /*Init function parameters*/
+ double[] initialPars= {eMax-eMin,1.*(nEvents[id]/10),eMin};
+ fFunction.get(id).setParameters(initialPars);
+
+ /*Do the fit*/
+ fFitter=aida.analysisFactory().createFitFactory().createFitter("chi2","","V");
+ System.out.println("LedAnalysis:: do fit "+id+" "+fFitter.engineName()+" "+fFitter.fitMethodName());
+ fResult=fFitter.fit(cProfile.get(id),fFunction.get(id));
+ double[] fPars = fResult.fittedParameters();
+ double[] fParErrs = fResult.errors();
+ String[] fParNames = fResult.fittedParameterNames();
+ System.out.println("Chi2 = "+fResult.quality());
+ for(int i=0; i< fResult.fittedFunction().numberOfParameters(); i++ ){
+ System.out.println(fParNames[i]+" : "+fPars[i]+" +- "+fParErrs[i]);
+ }
+ System.out.println("LedAnalysis:: fit "+id+" done \n");
+ /*plot*/
+ pPlotter.region(0).clear();
+ pPlotter.region(0).plot(cProfile.get(id));
+ pPlotter.region(0).plot(fFunction.get(id));
+ // plotter.show();
+
+ if (useRawEnergy){
+ eMin=eMin/.2; //@TODO do this better
+ eMax=eMax/.2; //@TODO do this better
+ }
+
+ }
+ }
+
/**
* This function returns the driver number (from 0 to 3) given the LED id.
@@ -171,4 +311,22 @@
else if ((led>=168)&&(led<224)) ret=3;
return ret;
}
+
+/**
+ * Very simple method to retreive the pedestal-subtracted raw Energy.
+ * If the gain changes (because we do a re-calibration), I do not want to include this in the LED analysis
+ * @param energy
+ * @param cellID
+ * @return
+ */
+ public double getRawADCSum(double energy,long cellID){
+ EcalChannelConstants channelData = ecalConditions.getChannelConstants(ecalConditions.getChannelCollection().findGeometric(cellID));
+ double RawSum=energy / ECalUtils.GeV;
+ double gain=channelData.getGain().getGain();
+ double ret=RawSum/gain;
+ // System.out.println("A:C "+RawSum+" "+ret);
+
+ return ret;
+
+ }
}
|