silvermy@ornl.gov - SMcalib - directory with tools for SuperModule calibrations at...
authordsilverm <dsilverm@f7af4fe6-9843-0410-8265-dc069ae4e863>
Thu, 9 Oct 2008 13:24:02 +0000 (13:24 +0000)
committerdsilverm <dsilverm@f7af4fe6-9843-0410-8265-dc069ae4e863>
Thu, 9 Oct 2008 13:24:02 +0000 (13:24 +0000)
EMCAL/SMcalib/AliEMCALCalibAPD.cxx [new file with mode: 0644]
EMCAL/SMcalib/AliEMCALCalibAPD.h [new file with mode: 0644]
EMCAL/SMcalib/AliEMCALMapAPD.cxx [new file with mode: 0644]
EMCAL/SMcalib/AliEMCALMapAPD.h [new file with mode: 0644]
EMCAL/SMcalib/DCSGenerateAPD.C [new file with mode: 0644]
EMCAL/SMcalib/README [new file with mode: 0644]
EMCAL/SMcalib/WriteBias.C [new file with mode: 0644]
EMCAL/SMcalib/WriteBiasFixVoltage.C [new file with mode: 0644]
EMCAL/SMcalib/WriteBiasV30.C [new file with mode: 0644]
EMCAL/SMcalib/WriteNewBias.C [new file with mode: 0644]
EMCAL/SMcalib/biasSetup.sh [new file with mode: 0755]

diff --git a/EMCAL/SMcalib/AliEMCALCalibAPD.cxx b/EMCAL/SMcalib/AliEMCALCalibAPD.cxx
new file mode 100644 (file)
index 0000000..84a08b1
--- /dev/null
@@ -0,0 +1,224 @@
+/**************************************************************************
+ * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ *                                                                        *
+ * Author: The ALICE Off-line Project.                                    *
+ * Contributors are mentioned in the code where appropriate.              *
+ *                                                                        *
+ * Permission to use, copy, modify and distribute this software and its   *
+ * documentation strictly for non-commercial purposes is hereby granted   *
+ * without fee, provided that the above copyright notice appears in all   *
+ * copies and that both the copyright notice and this permission notice   *
+ * appear in the supporting documentation. The authors make no claims     *
+ * about the suitability of this software for any purpose. It is          *
+ * provided "as is" without express or implied warranty.                  *
+ **************************************************************************/
+
+/* $Id: $ */
+
+// Objects of this class read txt file with APD number data
+//
+
+#include <fstream>
+#include <TString.h>
+
+#include "AliEMCALCalibAPD.h"
+
+const int kMaxLen = 1000; // maximum length of single line (# of characters)
+// an OK line with complete info should have a certain number of characters
+const int kMinLenAPDLine = 145;
+const int kMaxLenAPDLine = 170;
+
+ClassImp(AliEMCALCalibAPD)
+
+//____________________________________________________________________________
+AliEMCALCalibAPD::AliEMCALCalibAPD() : 
+  fNCalibAPD(0),
+  fData(0)
+{
+  //Default constructor.
+}
+
+//____________________________________________________________________________
+void AliEMCALCalibAPD::ReadCalibAPDInfo(Int_t nAPD, const TString &txtFileName)
+{
+  //Read data from txt file. ; coordinates given on SuperModule basis
+
+  std::ifstream inputFile(txtFileName.Data());
+  if (!inputFile) {
+    printf("AliEMCALCalibAPD::ReadCalibAPDInfo - Cannot open the APD info file %s\n", txtFileName.Data());
+    return;
+  }
+
+  fNCalibAPD = nAPD;
+  if (fData) delete [] fData;
+  fData = new AliEMCALCalibAPDData[fNCalibAPD];
+
+  char line[kMaxLen];
+
+  // get header lines:
+  inputFile.getline(line, kMaxLen);
+  //  printf(" 1st header line character count %d\n", inputFile.gcount());
+  inputFile.getline(line, kMaxLen);
+  //  printf(" 2nd header line character count %d\n", inputFile.gcount());
+
+  // variables for reading
+  int i1,i2,i3,i4,i5;
+  float f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12;
+  char c1[10], c2[20];
+
+  int j = 0; // index for the ones that were read OK
+  for (Int_t i = 0; i < fNCalibAPD; i++) {
+    AliEMCALCalibAPDData &t = fData[j];
+    if (!inputFile) {
+      printf("AliEMCALCalibAPD::ReadCalibAPDInfo - Error while reading input file.\n");
+      fNCalibAPD = j; // that's how many we actually read succesfully
+      printf("AliEMCALCalibAPD::ReadCalibAPDInfo - read %d OK\n", fNCalibAPD);
+      return;
+    }
+
+    // use some temporary/local values to perhaps help with the order when 
+    // trying to read all the many fields in a line..
+    inputFile.getline(line, kMaxLen);
+    int nchar = inputFile.gcount();
+    //    printf(" line %d ok %d - character count %d\n", i, j, nchar);
+
+    if (nchar>kMinLenAPDLine && nchar<kMaxLenAPDLine) {
+      // looks like the line has about the right number of characters, let's
+      // try to decode it now..
+
+      //      printf("input: %s\n",line);
+      sscanf(line, "%d,%u,%8s,%9s,%d,%d,%f,%f,%f,%f,%f,%f,%f,%f,%f,%d,%f,%f,%f",
+            &i1, &i2, c1, c2, &i3, &i4, // header-type info
+            &f1, &f2, &f3, &f4, &f5, &f6, &f7, &f8, &f9, // measurements
+            &i5, &f10, &f11, &f12); // Hamamatsu
+
+      //      printf("after scanf: %s\n",line);
+      /*
+      printf("%d,%u,%s,%s,%d,%d,%g,%g,%g,%g,%g,%g,%g,%g,%g,%d,%g,%13.11f,%g\n",
+            i1, i2, c1, c2, i3, i4, // header-type info
+            f1, f2, f3, f4, f5, f6, f7, f8, f9, // measurements
+            i5, f10, f11, f12); // Hamamatsu
+      */
+      // assign the variables:
+      t.fAPDNum = i1; 
+      t.fSerialNum = i2; 
+      sprintf(t.fStatus,"%s",c1);
+      sprintf(t.fLocation,"%s",c2);
+      t.fRunNum = i3; 
+      t.fTestPos = i4; 
+
+      t.fV30 = f1; 
+      t.fV50 = f2; 
+      t.fVoltCoeff = f3;
+      t.fPar[0] = f4;
+      t.fPar[1] = f5;
+      t.fPar[2] = f6;
+      t.fParErr[0] = f7;
+      t.fParErr[1] = f8;
+      t.fParErr[2] = f9;
+
+      t.fBreakDown = i5; 
+      t.fHamV50 = f10;
+      t.fDarkCurrent = f11;
+      t.fTestTemp = f12;
+
+      j++; // increment our 'OK' counter..
+    } // line length appears OK      
+  } // i, APD
+
+  inputFile.close();
+
+  return;
+}
+
+//____________________________________________________________________________
+void AliEMCALCalibAPD::WriteCalibAPDInfo(const TString &txtFileName)
+{
+  // write data to txt file. ; coordinates given on SuperModule basis
+
+  std::ofstream outputFile(txtFileName.Data());
+  if (!outputFile) {
+    printf("AliEMCALCalibAPD::WriteCalibAPDInfo - Cannot open the APD output file %s\n", txtFileName.Data());
+    return;
+  }
+
+  char *comma = ",";
+
+  for (Int_t i = 0; i < fNCalibAPD; i++) {
+    AliEMCALCalibAPDData &t = fData[i];
+
+    outputFile << t.fAPDNum << comma
+              << t.fSerialNum << comma // Serial Number; from Hamamatsu
+              << t.fStatus << comma //
+              << t.fLocation << comma //
+              << t.fRunNum << comma
+              << t.fTestPos << comma
+              << t.fV30 << comma // Catania/Houston Voltage V30 (V) at T = 25 deg C
+              << t.fV50 << comma 
+              << t.fVoltCoeff << comma // 1/M x dM/dV
+              << t.fPar[0] << comma // fit parameters, p0,p1,p2 - for ADC vs bias measurement
+              << t.fPar[1] << comma
+              << t.fPar[2] << comma
+              << t.fParErr[0] << comma // error on fit parameters      
+              << t.fParErr[1] << comma 
+              << t.fParErr[2] << comma 
+              << t.fBreakDown << comma // Hamamatsu Breakdown Voltage (V)      
+              << t.fHamV50 << comma; // Hamamatsu Voltage V50 (V)
+    // I wasn't able to quite reproduce the values as they appeared on the 
+    // original file: e.g. dark current is not always 11-field - if last digit is zero..
+    // the other floats have 6 significant digits, but sometimes switch to 
+    // scientific notation - don't know how to handle this for varying length of fields.. -leave it as is for now..
+    outputFile << t.fDarkCurrent << comma; // Hamamatsu Dark Current (A)       
+    /*
+    // some tweaking for the dark-current field to get the output the same
+    // as on the original CSV
+    outputFile.precision(11);  
+    outputFile << fixed << t.fDarkCurrent << comma; // Hamamatsu Dark Current (A)      
+    // back to normal..
+    outputFile.precision(6); outputFile.unsetf(ios_base::floatfield);  
+    */
+
+    outputFile << t.fTestTemp // Hamamatsu Testing Temperature (deg C) 
+              << endl; 
+
+  } // i, APD
+
+  outputFile.close();
+
+  return;
+}
+
+//____________________________________________________________________________
+AliEMCALCalibAPD::~AliEMCALCalibAPD()
+{
+  delete [] fData;
+}
+
+//____________________________________________________________________________
+AliEMCALCalibAPD::AliEMCALCalibAPDData AliEMCALCalibAPD::GetCalibAPDDataId(Int_t apdIndex)const
+{
+  AliEMCALCalibAPDData t;  // just to maybe prevent a crash, but we are returning something not-initialized so maybe not better really..
+  if (!fData)
+    return t;
+
+  return fData[apdIndex];
+}
+
+//____________________________________________________________________________
+AliEMCALCalibAPD::AliEMCALCalibAPDData AliEMCALCalibAPD::GetCalibAPDDataNum(Int_t apdNum)const
+{
+  AliEMCALCalibAPDData t;  // just to maybe prevent a crash, but we are returning something not-initialized so maybe not better really..
+  if (!fData)
+    return t;
+
+  for (int i=0; i<fNCalibAPD; i++) {
+    if (fData[i].fAPDNum == apdNum) {
+      return fData[i];
+    }
+  }
+
+  // if we made it to here, then no match was found - just return then
+  return t;
+}
+
+
diff --git a/EMCAL/SMcalib/AliEMCALCalibAPD.h b/EMCAL/SMcalib/AliEMCALCalibAPD.h
new file mode 100644 (file)
index 0000000..425a905
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef ALIEMCALCALIBAPD_H
+#define ALIEMCALCALIBAPD_H
+
+/* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * See cxx source for full Copyright notice                               */
+
+/* $Id: $ */
+
+#include <TObject.h>
+class TString;
+
+/*
+  Objects of this class read txt file with APD data
+  AliEMCALCalibAPD inherits TObject only to use AliLog "functions".
+*/
+
+class AliEMCALCalibAPD : public TObject {
+public:
+  AliEMCALCalibAPD();
+
+  void ReadCalibAPDInfo(Int_t nAPD, const TString &txtFileName); // info file is for nSm=1 to 12 SuperModules
+  void WriteCalibAPDInfo(const TString &txtFileName); // info file is for nSm=1 to 12 SuperModules
+
+  virtual ~AliEMCALCalibAPD();
+
+  struct AliEMCALCalibAPDData {
+    Int_t fAPDNum;    // assigned APD-PA number; Catania 10000-, Houston: 20000-
+    UInt_t fSerialNum; // Serial Number; from Hamamatsu        
+    Char_t fStatus[10]; // Status info: should be "tested"
+    Char_t fLocation[20]; // where was the test done: "Catania" or "Houston"
+    Int_t fRunNum; // DATE run at test station
+    Int_t fTestPos; // location of APD during test
+
+    Float_t fV30;      // Catania/Houston Voltage V30 (V) at T = 25 deg C
+    Float_t fV50;      // Catania/Houston Voltage V30 (V) at T = 25 deg C
+    Float_t fVoltCoeff; // 1/M x dM/dV
+    Float_t fPar[3];   // fit parameters, p0,p1,p2 - for ADC vs bias measurement
+    Float_t fParErr[3]; // error on fit parameters     
+
+    Int_t fBreakDown; // Hamamatsu Breakdown Voltage (V)       
+    Float_t fHamV50;       // Hamamatsu Voltage V50 (V)        
+    Float_t fDarkCurrent; // Hamamatsu Dark Current (A)        
+    Float_t fTestTemp; // Hamamatsu Testing Temperature (deg C)        
+
+  };
+
+  // pointer to stored info.
+  Int_t GetNCalibAPD() const { return fNCalibAPD; }; 
+  AliEMCALCalibAPDData * GetCalibAPDData() const { return fData; };
+
+  // - via the index in the stored array:
+  virtual AliEMCALCalibAPDData GetCalibAPDDataId(Int_t apdIndex) const;
+  // - or via the actual APD number
+  virtual AliEMCALCalibAPDData GetCalibAPDDataNum(Int_t apdNum) const;
+
+protected:
+
+  Int_t          fNCalibAPD; // Number of APDs
+  AliEMCALCalibAPDData *fData; // array with the data
+
+private:
+
+  AliEMCALCalibAPD(const AliEMCALCalibAPD &);
+  AliEMCALCalibAPD &operator = (const AliEMCALCalibAPD &);
+
+  ClassDef(AliEMCALCalibAPD, 1) //CalibAPD data reader
+};
+
+#endif
diff --git a/EMCAL/SMcalib/AliEMCALMapAPD.cxx b/EMCAL/SMcalib/AliEMCALMapAPD.cxx
new file mode 100644 (file)
index 0000000..8689da2
--- /dev/null
@@ -0,0 +1,318 @@
+/**************************************************************************
+ * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ *                                                                        *
+ * Author: The ALICE Off-line Project.                                    *
+ * Contributors are mentioned in the code where appropriate.              *
+ *                                                                        *
+ * Permission to use, copy, modify and distribute this software and its   *
+ * documentation strictly for non-commercial purposes is hereby granted   *
+ * without fee, provided that the above copyright notice appears in all   *
+ * copies and that both the copyright notice and this permission notice   *
+ * appear in the supporting documentation. The authors make no claims     *
+ * about the suitability of this software for any purpose. It is          *
+ * provided "as is" without express or implied warranty.                  *
+ **************************************************************************/
+
+/* $Id: $ */
+
+// Objects of this class read txt file with APD number data
+//
+
+#include <fstream>
+#include <TString.h>
+
+#include "AliEMCALMapAPD.h"
+
+const int kFirstAPD = 10213; // dummy number, only used for testing
+
+ClassImp(AliEMCALMapAPD)
+
+//____________________________________________________________________________
+AliEMCALMapAPD::AliEMCALMapAPD() : 
+  fNSuperModule(0),
+  fSuperModuleData(0)
+{
+  //Default constructor.
+}
+
+//____________________________________________________________________________
+void AliEMCALMapAPD::ReadMapAPDInfoStripBasis(Int_t nSM, const TString &txtFileName)
+{
+  //Read data from txt file; coordinates given on StripModule basis
+
+  std::ifstream inputFile(txtFileName.Data());
+  if (!inputFile) {
+    printf("AliEMCALMapAPD::ReadMapAPDInfoStripBasis - Cannot open the APD info file %s\n",txtFileName.Data());
+    return;
+  }
+
+  fNSuperModule = nSM;
+  if (fSuperModuleData) delete [] fSuperModuleData;
+  fSuperModuleData = new AliEMCALSuperModuleMapAPD[fNSuperModule];
+
+  Int_t iSM = 0; // SuperModule index
+  Int_t iAPD = 0;
+  // info in map is based on Strip Info
+  Int_t iStrip = 0;
+  Int_t iStripCol = 0;
+  Int_t iStripRow = 0;
+
+  // we'll convert this into SuperModule Info
+  Int_t iCol = 0;
+  Int_t iRow = 0;
+
+  Int_t nAPDPerSM = fgkEmCalCols * fgkEmCalRows;
+
+  for (Int_t i = 0; i < fNSuperModule; i++) {
+    AliEMCALSuperModuleMapAPD &t = fSuperModuleData[i];
+    if (!inputFile) {
+      printf("AliEMCALMapAPD::ReadMapAPDInfoStripBasis - Error while reading input file.\n");
+      return;
+    }
+    inputFile >> iSM;
+    t.fSuperModuleNum = iSM;
+
+    for (Int_t j=0; j<nAPDPerSM; j++) {
+      inputFile >> iStrip >> iStripCol >> iStripRow >> iAPD;
+      // iStrip is a number in the range 0..23 (number of StripModules per SuperModule)
+      // iStripCol is a number in the range 0..1 (number of tower columns per StripModule)
+      // iStripRow is a number in the range 0..23 (number of tower rows per StripModule)
+      iCol = iStrip*2 + iStripCol;
+      iRow = iStripRow;
+
+      if (iSM%2 == 1) { // C side, oriented differently than A side: swap..
+       iCol = fgkEmCalCols-1 - iCol;
+       iRow = fgkEmCalRows-1 - iRow;
+      }
+
+      t.fAPDNum[iCol][iRow] = iAPD;
+    }
+
+  } // i, SuperModule
+
+  inputFile.close();
+
+  return;
+}
+
+
+//____________________________________________________________________________
+void AliEMCALMapAPD::ReadMapAPDInfoSingleStripBasis(Int_t iSM, Int_t iStrip, const TString &txtFileName)
+  // iSM is the SuperModule number
+  // iStrip is a number in the range 0..23 (number of StripModules per SuperModule)
+{
+  //Read data from txt file; coordinates given on StripModule basis
+
+  std::ifstream inputFile(txtFileName.Data());
+  if (!inputFile) {
+    printf("AliEMCALMapAPD::ReadMapAPDInfoSingleStripBasis - Cannot open the APD info file %s\n",txtFileName.Data());
+    return;
+  }
+
+  // see if there is an existing SuperModule with the right index
+  Int_t foundSM = -1;
+  for (Int_t i = 0; i < fNSuperModule; i++) {
+    AliEMCALSuperModuleMapAPD &t = fSuperModuleData[i];
+    if (t.fSuperModuleNum == iSM) foundSM = i;
+  }
+
+  if (foundSM == -1) {
+    printf("AliEMCALMapAPD::ReadMapAPDInfoSingleStripBasis - no SuperModule %d found!\n", iSM);
+    return;
+  }
+
+  AliEMCALSuperModuleMapAPD &t = fSuperModuleData[foundSM];
+
+  Int_t iAPD = 0;
+  // info in map is based on Strip Info
+  Int_t iStripCol = 0;
+  Int_t iStripRow = 0;
+
+  // we'll convert this into SuperModule Info
+  Int_t iCol = 0;
+  Int_t iRow = 0;
+
+  Int_t nAPDPerStrip = 2 * fgkEmCalRows; // 2 columns in a strip
+
+  for (Int_t j=0; j<nAPDPerStrip; j++) {
+    if (!inputFile) {
+      printf("AliEMCALMapAPD::ReadMapAPDInfoSingleStripBasis - Error while reading input file.\n");
+      return;
+    }
+    inputFile >> iStripCol >> iStripRow >> iAPD;
+    // iStripCol is a number in the range 0..1 (number of tower columns per StripModule)
+    // iStripRow is a number in the range 0..23 (number of tower rows per StripModule)
+    iCol = iStrip*2 + iStripCol;
+    iRow = iStripRow;
+
+    /*
+// For the SuperModule calibration we will typically use SuperModule 0
+// for all - so don't worry about any swaps for now.. 
+// I.e. we'll work in a local column and row coord. system, not necessarily ALICE
+// May revisit later..
+    if (iSM%2 == 1) { // C side, oriented differently than A side: swap..
+      iCol = fgkEmCalCols-1 - iCol;
+      iRow = fgkEmCalRows-1 - iRow;
+    }
+    */
+
+    t.fAPDNum[iCol][iRow] = iAPD;
+  }
+
+  inputFile.close();
+
+  return;
+}
+
+
+//____________________________________________________________________________
+void AliEMCALMapAPD::ReadMapAPDInfo(Int_t nSM, const TString &txtFileName)
+{
+  //Read data from txt file. ; coordinates given on SuperModule basis
+
+  std::ifstream inputFile(txtFileName.Data());
+  if (!inputFile) {
+    printf("AliEMCALMapAPD::ReadMapAPDInfo - Cannot open the APD info file %s\n", txtFileName.Data());
+    return;
+  }
+
+  fNSuperModule = nSM;
+  if (fSuperModuleData) delete [] fSuperModuleData;
+  fSuperModuleData = new AliEMCALSuperModuleMapAPD[fNSuperModule];
+
+  Int_t iSM = 0; // SuperModule index
+  Int_t iAPD = 0;
+  Int_t iCol = 0;
+  Int_t iRow = 0;
+
+  Int_t nAPDPerSM = fgkEmCalCols * fgkEmCalRows;
+
+  for (Int_t i = 0; i < fNSuperModule; i++) {
+    AliEMCALSuperModuleMapAPD &t = fSuperModuleData[i];
+    if (!inputFile) {
+      printf("AliEMCALMapAPD::ReadMapAPDInfo - Error while reading input file.");
+      return;
+    }
+    inputFile >> iSM;
+    t.fSuperModuleNum = iSM;
+
+    for (Int_t j=0; j<nAPDPerSM; j++) {
+      inputFile >> iCol >> iRow >> iAPD;
+
+      // assume that this info is already swapped and done for this basis?
+      /*
+      if (iSM%2 == 1) { // C side, oriented differently than A side: swap..
+       iCol = fgkEmCalCols-1 - iCol;
+       iRow = fgkEmCalRows-1 - iRow;
+      }
+      */
+
+      t.fAPDNum[iCol][iRow] = iAPD;
+    }
+
+  } // i, SuperModule
+
+  inputFile.close();
+
+  return;
+}
+
+//____________________________________________________________________________
+void AliEMCALMapAPD::WriteMapAPDInfo(const TString &txtFileName)
+{
+  // write data to txt file. ; coordinates given on SuperModule basis
+
+  std::ofstream outputFile(txtFileName.Data());
+  if (!outputFile) {
+    printf("AliEMCALMapAPD::WriteMapAPDInfo - Cannot open the APD output file %s\n", txtFileName.Data());
+    return;
+  }
+
+  Int_t iCol = 0;
+  Int_t iRow = 0;
+
+  Int_t nAPDPerSM = fgkEmCalCols * fgkEmCalRows;
+
+  for (Int_t i = 0; i < fNSuperModule; i++) {
+    AliEMCALSuperModuleMapAPD &t = fSuperModuleData[i];
+    outputFile << t.fSuperModuleNum << endl;
+
+    for (Int_t j=0; j<nAPDPerSM; j++) {
+      iCol = j / fgkEmCalRows;
+      iRow = j % fgkEmCalRows;
+      outputFile << iCol << " " << iRow << " " 
+                << t.fAPDNum[iCol][iRow] << endl;
+    }
+
+  } // i, SuperModule
+
+  outputFile.close();
+
+  return;
+}
+
+//____________________________________________________________________________
+AliEMCALMapAPD::~AliEMCALMapAPD()
+{
+  delete [] fSuperModuleData;
+}
+
+//____________________________________________________________________________
+AliEMCALMapAPD::AliEMCALSuperModuleMapAPD AliEMCALMapAPD::GetSuperModuleMapAPDId(Int_t supModIndex)const
+{
+  AliEMCALSuperModuleMapAPD t;  // just to maybe prevent a crash, but we are returning something not-initialized so maybe not better really..
+  if (!fSuperModuleData)
+    return t;
+
+  return fSuperModuleData[supModIndex];
+}
+
+//____________________________________________________________________________
+AliEMCALMapAPD::AliEMCALSuperModuleMapAPD AliEMCALMapAPD::GetSuperModuleMapAPDNum(Int_t supModIndex)const
+{
+  AliEMCALSuperModuleMapAPD t;  // just to maybe prevent a crash, but we are returning something not-initialized so maybe not better really..
+  if (!fSuperModuleData)
+    return t;
+
+  for (int i=0; i<fNSuperModule; i++) {
+    if (fSuperModuleData[i].fSuperModuleNum == supModIndex) {
+      return fSuperModuleData[i];
+    }
+  }
+
+  return t;
+}
+
+//____________________________________________________________________________
+void AliEMCALMapAPD::GenerateDummyAPDInfo(Int_t nSM, Int_t * iSM)
+{
+  // just a temporary method to create some info to exercise I/O
+
+  fNSuperModule = nSM;
+  if (fSuperModuleData) delete [] fSuperModuleData;
+  fSuperModuleData = new AliEMCALSuperModuleMapAPD[fNSuperModule];
+
+  Int_t iAPD = 0;
+  Int_t iCol = 0;
+  Int_t iRow = 0;
+
+  Int_t nAPDPerSM = fgkEmCalCols * fgkEmCalRows;
+
+  for (Int_t i = 0; i < fNSuperModule; i++) {
+    AliEMCALSuperModuleMapAPD &t = fSuperModuleData[i];
+    t.fSuperModuleNum = iSM[i]; // set SuperModules in Order
+
+    for (Int_t j=0; j<nAPDPerSM; j++) {
+
+      iCol = j / fgkEmCalRows;
+      iRow = j % fgkEmCalRows;
+      iAPD = j + kFirstAPD + i*nAPDPerSM; // just a dummy number; assuming all APDs are assigned in order from Catania.. 
+
+      t.fAPDNum[iCol][iRow] = iAPD;
+    }
+
+  } // i, SuperModule
+
+  return;
+}
+
diff --git a/EMCAL/SMcalib/AliEMCALMapAPD.h b/EMCAL/SMcalib/AliEMCALMapAPD.h
new file mode 100644 (file)
index 0000000..9e6a62e
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef ALIEMCALMAPAPD_H
+#define ALIEMCALMAPAPD_H
+
+/* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * See cxx source for full Copyright notice                               */
+
+/* $Id: $ */
+
+#include <TObject.h>
+class TString;
+
+static const int fgkEmCalRows = 24; // number of rows per module for EMCAL
+static const int fgkEmCalCols = 48; // number of columns per module for EMCAL
+
+/*
+  Objects of this class read txt file with APD data
+  AliEMCALMapAPD inherits TObject only to use AliLog "functions".
+*/
+
+class AliEMCALMapAPD : public TObject {
+public:
+  AliEMCALMapAPD();
+
+  void ReadMapAPDInfoStripBasis(Int_t nSM, const TString &txtFileName); // info file is for nSm=1 to 12 SuperModules
+  void ReadMapAPDInfoSingleStripBasis(Int_t iSM, Int_t iStrip, const TString &txtFileName); // info file is for one single SuperModule and StripModule
+  void ReadMapAPDInfo(Int_t nSM, const TString &txtFileName); // info file is for nSm=1 to 12 SuperModules
+
+  void WriteMapAPDInfo(const TString &txtFileName); // info file is for nSm=1 to 12 SuperModules
+
+  void GenerateDummyAPDInfo(Int_t nSM, Int_t * iSM); // for debug purposes 
+
+  virtual ~AliEMCALMapAPD();
+
+  struct AliEMCALSuperModuleMapAPD {
+    Int_t fSuperModuleNum;
+    Int_t fAPDNum[fgkEmCalCols][fgkEmCalRows];
+  };
+
+  // pointer to stored info.
+  Int_t GetNSuperModule() const { return fNSuperModule; }; 
+  AliEMCALSuperModuleMapAPD * GetSuperModuleData() const { return fSuperModuleData; };
+
+  // - via the index in the stored array:
+  virtual AliEMCALSuperModuleMapAPD GetSuperModuleMapAPDId(Int_t smIndex) const;
+  // - or via the actual SM number
+  virtual AliEMCALSuperModuleMapAPD GetSuperModuleMapAPDNum(Int_t smNum) const;
+
+protected:
+
+  Int_t          fNSuperModule; // Number of supermodules.
+  AliEMCALSuperModuleMapAPD *fSuperModuleData; // SuperModule data
+
+private:
+
+  AliEMCALMapAPD(const AliEMCALMapAPD &);
+  AliEMCALMapAPD &operator = (const AliEMCALMapAPD &);
+
+  ClassDef(AliEMCALMapAPD, 1) //MapAPD data reader
+};
+
+#endif
diff --git a/EMCAL/SMcalib/DCSGenerateAPD.C b/EMCAL/SMcalib/DCSGenerateAPD.C
new file mode 100644 (file)
index 0000000..d44a2c0
--- /dev/null
@@ -0,0 +1,245 @@
+// constants
+static const int fgkEmCalRows = 24; // number of rows per module for EMCAL
+static const int fgkEmCalCols = 48; // number of columns per module for EMCAL
+
+const int NRCU = 2; // per SM
+const int NBranch = 2; // per RCU
+const int NFEC = 9; // per branch, labelled 1..9
+const int NCSP = 32; // per FEC
+
+// some global variables
+int biasVoltage[NRCU][NBranch][NFEC][NCSP]; 
+int towerCol[NRCU][NBranch][NFEC][NCSP]; 
+int towerRow[NRCU][NBranch][NFEC][NCSP]; 
+
+//__________________________________________________________
+void Tower2FEEBiasInfo(const char *inputFileName)
+{
+  ifstream inputFile(inputFileName);
+  int ic, ir,ival;
+  int ircu, ibranch, card, icsp;
+  for (int icol=0; icol<fgkEmCalCols; icol++) {
+    for (int irow=0; irow<fgkEmCalRows; irow++) {
+      inputFile >> ic >> ir >> ival;
+
+      // could check here that ic && ir match with icol && irow, but should not be needed
+
+      // translate to FEE type indices
+      Tower2FEEMap(ic, ir, 
+                  &ircu, &ibranch, &card, &icsp);
+
+      // debug
+      /*
+      printf("ic %d ir %d ircu %d ibranch %d card %d icsp %d\n",
+            ic, ir, ircu, ibranch, card, icsp);
+      */
+
+      // store value
+      biasVoltage[ircu][ibranch][card][icsp] = ival;
+      towerCol[ircu][ibranch][card][icsp] = ic;
+      towerRow[ircu][ibranch][card][icsp] = ir;
+    }
+  }
+
+  inputFile.close();
+
+  return;
+}
+
+//__________________________________________________________
+void Tower2FEEMap(const int icol, const int irow,
+                 int *ircu, int *ibranch, int *card, int *icsp)
+{ /*
+    If you are interested in where these magic numbers come from -
+    See mapping info on 
+    http://dsilverm.web.cern.ch/dsilverm/mapping/emcal_mapping.html
+    http://dsilverm.web.cern.ch/dsilverm/mapping/ppt/Coordinates_and_Mapping.pdf
+   */
+
+  // each FEC covers a 4x8 tower area
+  int C = irow/8; // Cable bundle
+  int FEC = C*12 + icol/4; // FEC in 0..35 range
+
+  *ircu = FEC / 18; // 18 FEC per RCU
+  *ibranch = (FEC%18) / 9;
+  *card = FEC % 9;  
+
+  // columns and rows within an FEC area
+  int tCol = icol%4;
+  int tRow = irow%8;
+
+  // The mapping to CSP is a bit complicated so I also define two more help variables here..
+  // which T-card?
+  int TCard = tCol/2; // 0=Top (even StripModules), 1=Bottom (odd StripModules)
+  int locCol = tCol%2;  // local column inside T-card 
+
+  *icsp = (7 - tRow) + locCol*16 + TCard*8;
+}
+
+/* Main method.. */
+//__________________________________________________________
+void DCSGenerateAPD(const char *inputFileName,
+                   const char *outputDir,
+                   const int readBack=0) 
+{
+
+  // set up which bias voltage should be applicable for which CSP..
+  Tower2FEEBiasInfo(inputFileName);
+
+  // general setup block: note - for old RCU firmware (DS: hope this doesn't change with new firmware)
+  const char *branch_str[] = { "A", "B"};
+  const int trailer_offset = 0x48;
+  const int read_header = 0x520000; 
+  const int write_header = 0x620000; 
+  
+  // hv = hvmin + prop*DAC; values fitted/measured by ZhongBao; correction with David K at SPS beamtest
+  float hvmin = 207.9;
+  float prop = 0.2022; 
+  // resulting voltage settings should be good within a few volts 
+  cout << " HV-DAC prop. constant = " << prop << endl;
+  char iv_dac_setting[100]; 
+  
+  char cfile[200];
+
+  FILE* fout_setbias_card[NRCU][NBranch][NFEC];
+  FILE* fout_readbias_card[NRCU][NBranch][NFEC];
+  
+  // end of setup, let's go..
+  
+  int rcu_addr_card = 0x7000;
+  int csp_addr = trailer_offset;
+  int word = 0;
+  char comment[400];
+  
+  int rcu_addr_read = 0x7000; // we'll also write the readbias file in the same loop, so
+  // need a separate index also
+
+  for (int rcu=0; rcu<NRCU; rcu++) {
+    for (int branch=0; branch<NBranch; branch++) {
+      for (int ifec=0; ifec<NFEC; ifec++) {
+       int card = ifec;
+       int icard = ifec+1;
+
+       sprintf(cfile,"%s/set_rcu_%d_bias_branch_%s_FEC_%d.scr",
+               outputDir, rcu, 
+               branch_str[branch], icard);
+       fout_setbias_card[rcu][branch][card] = fopen(cfile, "w");
+
+       sprintf(cfile,"%s/read_rcu_%d_bias_branch_%s_FEC_%d.scr", 
+               outputDir, rcu,
+               branch_str[branch], icard);
+       fout_readbias_card[rcu][branch][card] = fopen(cfile, "w");
+
+       rcu_addr_card = 0x7000;
+       rcu_addr_read = 0x7000;
+
+       for (int icsp = 0; icsp<NCSP; icsp++) {
+         
+         /* 
+            some funkiness to address the CSPs correctly follows here. 
+            DS verified this with section 16.1 "Bias voltage programming", table 8
+            of H. Muller's PHOS manual (version from Jan 2007) 
+         */ 
+         if (icsp<16) { csp_addr = trailer_offset + icsp; }
+         else { csp_addr = trailer_offset - 1 - (icsp%16); }
+         if (icsp >= 24) csp_addr += 0x20;
+
+         // what does the desired voltage (in V) correspond to in DAC?
+         int iv_dac = (int)( (biasVoltage[rcu][branch][card][icsp] - hvmin)/prop );
+         if (iv_dac > 0x3FF) iv_dac = 0x3FF;
+         sprintf(iv_dac_setting,"700%03X",iv_dac);
+
+
+         // set up instructions that should be written
+         word = write_header | (branch << 16) | (icard << 12) | (csp_addr);
+
+         // write a long comment with all info for this CSP
+         sprintf(comment, "# RCU %d, Branch %s, FEC %d, CSP %d - Tower Col %d, Row %d ", 
+                 rcu, branch_str[branch], icard, icsp,
+                 towerCol[rcu][branch][card][icsp],
+                 towerRow[rcu][branch][card][icsp]
+                 );  
+       
+         fprintf(fout_setbias_card[rcu][branch][card], "w 0x%4X 0x%6X   %s\n",
+                 rcu_addr_card, word, comment);
+         rcu_addr_card++;
+
+         fprintf(fout_setbias_card[rcu][branch][card], "w 0x%4X 0x%s   # Set Voltage: %d V, DAC %d (hex: %03X)\n", 
+                 rcu_addr_card, iv_dac_setting, 
+                 biasVoltage[rcu][branch][card][icsp], 
+                 iv_dac, iv_dac
+                 );
+         rcu_addr_card++;
+
+         // slighly modified comment for read command - include voltage info
+         sprintf(comment, "# RCU %d, Branch %s, FEC %d, CSP %d - Tower Col %d, Row %d : %d V, DAC %d (hex: %03X)", 
+                 rcu, branch_str[branch], icard, icsp,
+                 towerCol[rcu][branch][card][icsp],
+                 towerRow[rcu][branch][card][icsp],
+                 biasVoltage[rcu][branch][card][icsp], 
+                 iv_dac, iv_dac
+                 );  
+
+         word = read_header | (branch << 16) | (icard << 12) | (csp_addr);
+         fprintf(fout_readbias_card[rcu][branch][card], "w 0x%4X 0x%06X  %s\n", rcu_addr_read, word, comment);
+         rcu_addr_read++;
+       } // csp loop
+       
+       // after CSP per card; send update command
+       word = write_header | (branch << 16) | (icard << 12) | 0x1e;
+       fprintf(fout_setbias_card[rcu][branch][card],"w 0x%4X 0x%06X   # Update Voltages\n", 
+               rcu_addr_card, word); 
+       rcu_addr_card++;
+
+       // also put ending for the individual card files:
+       fprintf(fout_setbias_card[rcu][branch][card],"w 0x%4X 0x%06X \n", 
+               rcu_addr_card, 0x700000);
+       rcu_addr_card++;
+       fprintf(fout_setbias_card[rcu][branch][card],"w 0x%4X 0x%06X \n", 
+               rcu_addr_card, 0x390000);
+       rcu_addr_card++;
+      
+       fprintf(fout_setbias_card[rcu][branch][card],"wait 1 us\n");
+       fprintf(fout_setbias_card[rcu][branch][card],"w 0x0 0x0           # execute and update registers\n");
+       fprintf(fout_setbias_card[rcu][branch][card],"wait 1 us\n");
+       fprintf(fout_setbias_card[rcu][branch][card],"w 0x0 0x0           # execute and update registers again\n");
+       fprintf(fout_setbias_card[rcu][branch][card],"wait 1 us\n");
+       fprintf(fout_setbias_card[rcu][branch][card],"r 0x7800            # error checking\n");
+       fprintf(fout_setbias_card[rcu][branch][card],"w 0x6c01 0x 0       # clear registers\n");
+       
+
+       // in case we want to check what was written
+       if (readBack) {
+         fprintf(fout_setbias_card[rcu][branch][card],"wait 1 us\n");
+         fprintf(fout_setbias_card[rcu][branch][card],"b %s      # read-back the values also\n", cfile);
+         fprintf(fout_setbias_card[rcu][branch][card],"wait 1 us\n");
+       }
+
+
+       // close down output files (set)
+       fclose(fout_setbias_card[rcu][branch][card]);
+       
+       // readbias ending
+       fprintf(fout_readbias_card[rcu][branch][card],"w 0x%4X 0x%06X \n", 
+               rcu_addr_read, 0x390000);
+       rcu_addr_read++;
+
+       fprintf(fout_readbias_card[rcu][branch][card],"wait 1 us\n");
+       fprintf(fout_readbias_card[rcu][branch][card],"w 0x0 0x0           # execute and update registers\n");
+
+       fprintf(fout_readbias_card[rcu][branch][card],"wait 1 us\n");
+       fprintf(fout_readbias_card[rcu][branch][card],"r 0x7800            # error checking\n");
+       fprintf(fout_readbias_card[rcu][branch][card],"wait 1 us\n");
+       fprintf(fout_readbias_card[rcu][branch][card],"r 0x6000 %d( \n", NCSP);
+       fprintf(fout_readbias_card[rcu][branch][card],"wait 1 us\n");
+       fprintf(fout_readbias_card[rcu][branch][card],"r 0x7800            # error checking\n");
+       fprintf(fout_readbias_card[rcu][branch][card],"w 0x6c01 0x 0       # clear registers\n");
+       
+       // close down output files (read)
+       fclose(fout_readbias_card[rcu][branch][card]);
+
+      } // card=FEC
+    } // branch
+  } // rcu
+
+}
diff --git a/EMCAL/SMcalib/README b/EMCAL/SMcalib/README
new file mode 100644 (file)
index 0000000..af1c965
--- /dev/null
@@ -0,0 +1,89 @@
+silvermy@ornl.gov, Oct 9, 2008: 
+This README file and the associated macros are meant to help with the SuperModule calibrations.
+
+The steps below indicate how a set of bias
+values (fixed voltage, or V30 for each APD, and a 2nd iteration with gain balancing)
+for a SuperModule can be created.
+
+The necessary information that would be needed to complete the steps would be
+A) APD calibration info (csv file) - from Catania or Houston
+B) Info on which APD goes where in the different StripModules - and
+where these StripModules end up in the SuperModule.
+C) [for the balancing] A file obtained from the first analysis iteration regarding
+how the gains should be modified, for each tower.
+
+/David Silvermyr
+
+0) Compile the help classes in root or aliroot:
+----------------------------------------------
+root [0] .L AliEMCALMapAPD.cxx+
+root [1] .L AliEMCALCalibAPD.cxx+
+
+1) Generating an APD map: normal use case in a root macro for your SuperModule
+-------------------------
+//a) create a dummy space in memory:
+  gSystem->Load("AliEMCALMapAPD_cxx");
+  AliEMCALMapAPD *mapAPD = new AliEMCALMapAPD();
+
+  Int_t iSM[2] = {0,1}; // allow for two SuperModules
+  mapAPD->GenerateDummyAPDInfo(1, iSM); // space for one SuperModule, with number iSM[0] = 0
+
+//b) overwrite this memory with the actual values for the StripModules; one line for each of the 24 stripmodules (0-23)
+  mapAPD->ReadMapAPDInfoSingleStripBasis(0, 21, "APDStripModXY.txt"); 
+// "XY" should perhaps be F5 for 5th stripmodule from Frascati or something like that. F=Frascati, W=WSU, N=Nantes, C=Catania
+
+//For a "APDStripModXY.txt" file, 48 lines with 3 fields:
+//StripColumn StripRow APDNum
+//is expected..
+
+//c) write out the map for column, row, APD for the whole SM:
+  mapAPD->WriteMapAPDInfo("APDSuperModY1.txt"); // Y=Yale, G=Grenoble
+
+2) Generating a file of V30 bias values for each tower:
+------------------------------------------------------- 
+# arguments are:
+1: input APD database csv file
+2: APD map file - which tower is where in the SuperModule; from step 1) above. 
+3: defaultVoltage - use 390 if no settings can be found for some APDs
+4: outputfile
+
+root -b 'WriteBiasV30.C("APD-database.csv", "DummySuperModAPDMap.txt", 390, "BiasV30.txt")' -q 
+# aliroot also works instead of root; as you prefer
+
+3) Optional - e.g. in case you don't have the whole SuperModule APD map or what not 
+Generating a file of the same bias value for each tower:
+---------------------------------------------------------- 
+root -b 'WriteBiasFixVoltage(390, "Bias390.txt")' -q # aliroot also works..
+
+4) Generating a file of new bias values for each tower:
+- based on existing file, and a suggested gain factor change, to obtain a balanced setup
+------------------------------------------------------------
+"GainChange.txt" here contains a factor for each tower: factor 0.9 would mean a reduction
+by 10% and factor 1.1 would mean an increase by 10% relative to the file used previously,
+in this case BiasV30.txt.
+
+root -b 'WriteNewBias.C("APD-database.csv", "DummySuperModAPDMap.txt", "BiasV30.txt", "GainChange.txt", "NewBias.txt")' -q # aliroot also works..
+
+5) Converting a bias value file to a set of files that can be used by DCS/RCU: 
+-----------------------------------------------------------------------------
+Arguments are:
+1: input file with voltage per tower
+2: output directory for scripts
+3: [optional: put a non-zero value there to also ask for the values to be read back at the end of the 'set' files]
+
+mkdir APD # create output directory
+root -b 'DCSGenerateAPD.C("NewBias.txt","APD")' -q
+
+The result should be that 1 'set' and 1 'read' file for each FEC should have been created in the directory APD/.
+
+6) Use the newly produced files:
+-------------------------------
+Copy the files, and possibly biasSetup.sh into your DCS nodes 
+(e.g. with scp, or better use nfsmount on DCS cards to see some directory
+on your DAQ computer, if possible),
+rcu_0 files should be readable by RCU0 DCS, and rcu_1 files should be readable by RCU1 DCS.
+
+Then, on the DCS card, you can do something like:
+cd /dcs
+./biasSetup.sh 0 # argument is RCU (0 or 1),; we need to tell each RCU who (s)he is..
+
diff --git a/EMCAL/SMcalib/WriteBias.C b/EMCAL/SMcalib/WriteBias.C
new file mode 100644 (file)
index 0000000..479ed8e
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+Implemented modes:
+0 - write the same value for all towers
+1 - use individual V30 settings
+*/
+
+int 
+//____________________________________________________________________
+void WriteBiasFix(const int mode = 0, const int biasSetting = 390) 
+{ 
+
+  if (mode == 0) { // fixed values
+    SetAll(390);
+  }
+  else if (mode == 1) {
+  }
+
+}
+
+  gSystem->Load("AliEMCALCalibAPD_cxx");
+  AliEMCALCalibAPD *calibAPD = new AliEMCALCalibAPD();
+
+  calibAPD->ReadCalibAPDInfo(10000, "dilan-APD-database.csv");
+  //calibAPD->ReadCalibAPDInfo(10000, "paola-APD-database.csv");
+  calibAPD->WriteCalibAPDInfo("dummy.txt");
+
+  int fNCalibAPD = calibAPD->GetNCalibAPD();
+  AliEMCALCalibAPD::AliEMCALCalibAPDData * fData = calibAPD->GetCalibAPDData();
+  for (int i=0; i<fNCalibAPD; i++) {
+    cout << " i " << i
+        << " fAPDNum " << fData[i].fAPDNum 
+        << " fSerialNum " << fData[i].fSerialNum 
+        << " fDarkCurrent " << fData[i].fDarkCurrent << endl;
+  }
+
+  /*
+  // 1: create a dummy file
+  calibAPD->GenerateDummyAPDInfo(nAPD);
+  */
+
+  /*
+  // 2: test I/O
+  calibAPD->ReadCalibAPDInfo(nAPD, "dummy.txt");
+  calibAPD->WriteCalibAPDInfo("dummy2.txt");
+  */
+
+  /*
+  // 3: see if it works ok if we genarate values first, and then try to read others/overwriting
+  calibAPD->GenerateDummyAPDInfo(2*nAPD); // some extra APDs
+  calibAPD->ReadCalibAPDInfo(nAPD, "dummy.txt");
+  calibAPD->WriteCalibAPDInfo("dummy3.txt");
+  */
+
+  /*
+  // 4: other way around from #3
+  calibAPD->ReadCalibAPDInfo(nAPD, "dummy.txt");
+  calibAPD->GenerateDummyAPDInfo(2*nAPD);
+  calibAPD->WriteCalibAPDInfo("dummy4.txt");
+  */
+  
+}
+
diff --git a/EMCAL/SMcalib/WriteBiasFixVoltage.C b/EMCAL/SMcalib/WriteBiasFixVoltage.C
new file mode 100644 (file)
index 0000000..ca237af
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+*/
+
+static const int fgkEmCalRows = 24; // number of rows per module for EMCAL
+static const int fgkEmCalCols = 48; // number of columns per module for EMCAL
+
+//____________________________________________________________________
+void WriteBiasFixVoltage(const int biasVoltage, const char * txtFileName) 
+{ 
+
+  ofstream outputFile(txtFileName);
+
+  for (int icol=0; icol<fgkEmCalCols; icol++) {
+    for (int irow=0; irow<fgkEmCalRows; irow++) {
+      outputFile << icol << " " << irow << " " << biasVoltage << endl;
+    }
+  }
+
+  outputFile.close();
+}
diff --git a/EMCAL/SMcalib/WriteBiasV30.C b/EMCAL/SMcalib/WriteBiasV30.C
new file mode 100644 (file)
index 0000000..1ff95e5
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+*/
+
+static const int fgkEmCalRows = 24; // number of rows per module for EMCAL
+static const int fgkEmCalCols = 48; // number of columns per module for EMCAL
+
+int biasVoltage[fgkEmCalCols][fgkEmCalRows];
+
+//____________________________________________________________________
+void WriteBiasV30(const char * inputDBName, const char * inputMapName,
+                 const int defaultVoltage, const char * outputFileName) 
+{ 
+
+  ofstream outputFile(outputFileName);
+  SetBiasVoltage(inputDBName, inputMapName, defaultVoltage);
+
+  for (int icol=0; icol<fgkEmCalCols; icol++) {
+    for (int irow=0; irow<fgkEmCalRows; irow++) {
+      outputFile << icol << " " << irow << " " << biasVoltage[icol][irow] << endl;
+    }
+  }
+
+  outputFile.close();
+}
+
+//____________________________________________________________________
+void SetBiasVoltage(const char * inputDBName, const char * inputMapName,
+                   const int defaultVoltage) 
+{
+  gSystem->Load("AliEMCALCalibAPD_cxx");
+  AliEMCALCalibAPD *calibAPD = new AliEMCALCalibAPD();
+
+  calibAPD->ReadCalibAPDInfo(10000, inputDBName);
+  int fNCalibAPD = calibAPD->GetNCalibAPD();
+  AliEMCALCalibAPD::AliEMCALCalibAPDData * fCalib = calibAPD->GetCalibAPDData();
+
+
+  gSystem->Load("AliEMCALMapAPD_cxx");
+  AliEMCALMapAPD *mapAPD = new AliEMCALMapAPD();
+
+  int nSM = 1;
+  mapAPD->ReadMapAPDInfo(nSM, inputMapName);
+  AliEMCALMapAPD::AliEMCALSuperModuleMapAPD * fMap = mapAPD->GetSuperModuleData();
+
+  int nFound = 0;
+  for (int icol=0; icol<fgkEmCalCols; icol++) {
+    for (int irow=0; irow<fgkEmCalRows; irow++) {
+
+      int apdMap = fMap[0].fAPDNum[icol][irow]; // 0 = nSM - 1
+      int i = 0;
+      int apdCalib = -1;
+      while (i<fNCalibAPD && apdMap!=apdCalib) {
+       apdCalib = fCalib[i].fAPDNum;
+       i++;
+      }
+
+      if (apdCalib == apdMap) { // found!
+       i--; // go back to what we dound
+       biasVoltage[icol][irow] = fCalib[i].fV30;
+       nFound++;
+      }
+      else {
+       biasVoltage[icol][irow] = defaultVoltage;
+      }
+
+    }
+  }
+
+  cout << " found " << nFound << " matches " << endl;
+  return;
+}
+
diff --git a/EMCAL/SMcalib/WriteNewBias.C b/EMCAL/SMcalib/WriteNewBias.C
new file mode 100644 (file)
index 0000000..cc99189
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+*/
+
+const int kMaxHV = 395;
+
+static const int fgkEmCalRows = 24; // number of rows per module for EMCAL
+static const int fgkEmCalCols = 48; // number of columns per module for EMCAL
+
+int previousVoltage[fgkEmCalCols][fgkEmCalRows];
+Float_t gainFactor[fgkEmCalCols][fgkEmCalRows];
+int biasVoltage[fgkEmCalCols][fgkEmCalRows];
+
+//____________________________________________________________________
+void WriteNewBias(const char * inputDBName, const char * inputMapName,
+                 const char * previousVoltageFileName, const char * gainFactorFileName, 
+                 const char * outputFileName) 
+{ 
+
+  ofstream outputFile(outputFileName);
+  ReadFiles(previousVoltageFileName, gainFactorFileName);
+
+  SetBiasVoltage(inputDBName, inputMapName);
+
+  for (int icol=0; icol<fgkEmCalCols; icol++) {
+    for (int irow=0; irow<fgkEmCalRows; irow++) {
+      outputFile << icol << " " << irow << " " << biasVoltage[icol][irow] << endl;
+    }
+  }
+
+  outputFile.close();
+}
+
+//____________________________________________________________________
+void ReadFiles(const char * previousVoltageFileName, 
+              const char * gainFactorFileName)
+{
+  ifstream previousVoltageFile(previousVoltageFileName);
+  ifstream gainFactorFile(gainFactorFileName);
+
+  int icolp, irowp;
+  int icolg, irowg;
+  Float_t gFactor;
+  int pVoltage;
+
+  for (int icol=0; icol<fgkEmCalCols; icol++) {
+    for (int irow=0; irow<fgkEmCalRows; irow++) {
+      previousVoltageFile >> icolp >> irowp >> pVoltage;
+      gainFactorFile >> icolg >> irowg >> gFactor;
+
+      previousVoltage[icolp][irowp] = pVoltage;
+      gainFactor[icolg][irowg] = gFactor;
+    }
+  }
+
+  previousVoltageFile.close();
+  gainFactorFile.close();
+
+  return;
+}
+
+//____________________________________________________________________
+void SetBiasVoltage(const char * inputDBName, const char * inputMapName) 
+{
+  gSystem->Load("AliEMCALCalibAPD_cxx");
+  AliEMCALCalibAPD *calibAPD = new AliEMCALCalibAPD();
+
+  calibAPD->ReadCalibAPDInfo(10000, inputDBName);
+  int fNCalibAPD = calibAPD->GetNCalibAPD();
+  AliEMCALCalibAPD::AliEMCALCalibAPDData * fCalib = calibAPD->GetCalibAPDData();
+
+
+  gSystem->Load("AliEMCALMapAPD_cxx");
+  AliEMCALMapAPD *mapAPD = new AliEMCALMapAPD();
+
+  int nSM = 1;
+  mapAPD->ReadMapAPDInfo(nSM, inputMapName);
+  AliEMCALMapAPD::AliEMCALSuperModuleMapAPD * fMap = mapAPD->GetSuperModuleData();
+
+  int nFound = 0;
+  for (int icol=0; icol<fgkEmCalCols; icol++) {
+    for (int irow=0; irow<fgkEmCalRows; irow++) {
+
+      int apdMap = fMap[0].fAPDNum[icol][irow]; // 0 = nSM - 1
+      int i = 0;
+      int apdCalib = -1;
+      while (i<fNCalibAPD && apdMap!=apdCalib) {
+       apdCalib = fCalib[i].fAPDNum;
+       i++;
+      }
+
+      if (apdCalib == apdMap) { // found!
+       i--; // go back to what we dound
+
+       // estimate what the new/target HV should be
+       biasVoltage[icol][irow] = CalculateTargetHV(previousVoltage[icol][irow], 
+                                                   gainFactor[icol][irow], 
+                                                   fCalib[i].fPar[0], 
+                                                   fCalib[i].fPar[1], 
+                                                   fCalib[i].fPar[2]);
+       nFound++;
+      }
+      else { // no calib info, just use old settings
+       biasVoltage[icol][irow] = previousVoltage[icol][irow];
+      }
+
+    }
+  }
+
+  cout << " found " << nFound << " matches " << endl;
+  return;
+}
+
+//____________________________________________________________________
+int CalculateTargetHV(int initHV, Float_t gainChange,                 
+                     Float_t par0, Float_t par1, Float_t par2 )
+{
+  printf("parameters p0:%g p1:%g p2:%g\n", par0, par1, par2);
+
+  // figure out what new HV should be, 
+  // if we want to adjust the gain by some factor
+  Float_t initialHV = (Float_t) initHV;
+  Float_t initialGain = par0 + par1 * exp(par2*initialHV);
+  Float_t newGain = initialGain * gainChange; // = par0 + par1 * exp(par2*newHV);
+
+  printf("initialGain:%g newGain:%g\n", initialGain, newGain);
+
+  Float_t fNewHV = -1;
+  if ( par1>0 && par2>0 ) {
+    fNewHV = log ( (newGain - par0)/par1 ) / par2;
+  }
+  // round-off
+  int newHV = (int) (fNewHV + 0.5);
+  
+  // check results before returning..
+  if (newHV == -1) {
+   // conversion failed:  let's just keep the old custom value then
+    newHV = initHV;
+  }
+  if (newHV>kMaxHV) {
+    // we reached a too high voltage: let's keep the max then
+   newHV = kMaxHV;
+  }
+
+  return newHV;
+}
diff --git a/EMCAL/SMcalib/biasSetup.sh b/EMCAL/SMcalib/biasSetup.sh
new file mode 100755 (executable)
index 0000000..a8d234a
--- /dev/null
@@ -0,0 +1,45 @@
+#/bin/bash
+
+if [ $# -ne 1 ]; then
+        echo 1>&2 Usage: $0 RCU 
+        echo 1>&2 Example: $0 1
+        exit 127
+fi
+
+#what has been asked for?
+RCU=$1
+
+
+BRANCH="A"
+date 
+echo Branch $BRANCH
+FEC=1
+while [ $FEC -le 9 ]; do
+ FILE=APD/set_rcu_${RCU}_bias_branch_${BRANCH}_FEC_${FEC}.scr
+ echo
+ echo File $FILE will be used
+ echo
+ rcu-sh b $FILE
+
+ let FEC=FEC+1
+done
+
+BRANCH="B"
+date 
+echo Branch $BRANCH
+FEC=1
+while [ $FEC -le 9 ]; do
+ FILE=APD/set_rcu_${RCU}_bias_branch_${BRANCH}_FEC_${FEC}.scr
+ echo
+ echo File $FILE will be used
+ echo
+ rcu-sh b $FILE
+
+ let FEC=FEC+1
+done
+
+#fini
+date
+echo
+echo That is all. Fin.
+echo
\ No newline at end of file