Index: /trunk/Mars/fact/processing/calibrate.C
===================================================================
--- /trunk/Mars/fact/processing/calibrate.C	(revision 15227)
+++ /trunk/Mars/fact/processing/calibrate.C	(revision 15227)
@@ -0,0 +1,288 @@
+/*
+#ifndef HAVE_ZLIB
+#define HAVE_ZLIB
+#endif
+
+#include <TMath.h>
+
+#include "fits.h"
+#include "ofits.h"
+
+#include "MArrayF.h"
+#include "MMath.h"
+*/
+
+using namespace std;
+
+bool Read(const char *fname, int *npix)
+{
+    std::ifstream fin(fname);
+
+    int l = 0;
+
+    while (1)
+    {
+        if (l>1439)
+            break;
+
+        TString line;
+        line.ReadLine(fin);
+        if (!fin)
+            break;
+
+        line = line.Strip(TString::kBoth);
+        if (line[0]=='#')
+            continue;
+
+        TObjArray *arr = line.Tokenize(' ');
+        int cbpx  = atoi(((*arr)[1])->GetName());
+        int board = atoi(((*arr)[6])->GetName());
+        int ch    = atoi(((*arr)[7])->GetName());
+        delete arr;
+
+        int hv = board*32+ch;
+        if (hv>=416)
+            return false;
+
+        int n = cbpx%10>3 ? 5 : 4;
+        if (npix[hv]>0 && npix[hv]!=n)
+            return false;
+
+        npix[hv] = n;
+        l++;
+    }
+
+    return l==1440;
+}
+
+int calibrate(UInt_t night, TString path="/fact/aux")
+{
+    int npix[416];
+    memset(npix, 0, sizeof(int)*416);
+    if (!Read("/scratch_nfs/FACTmap111030.txt", npix))
+        return 42;
+
+    UInt_t d =  night%100;
+    UInt_t m = (night/100)%100;
+    UInt_t y =  night/10000;
+
+    path += Form("/%04d/%02d/%02d/%d", y, m, d, night);
+    TString path2 = Form("/scratch_nfs/calibrated_currents/%d", night);
+
+    TString filec = path + ".FEEDBACK_CALIBRATION.fits";
+    TString fileu = path + ".BIAS_CONTROL_VOLTAGE.fits";
+    TString filei = path + ".BIAS_CONTROL_CURRENT.fits";
+    TString fileo = path2 + ".CALIBRATED_CURRENTS.fits";
+
+    cout << filec << endl;
+    cout << fileu << endl;
+    cout << filei << endl;
+    cout << fileo << endl;
+
+    fits fitsc1(filec.Data());
+    fits fitsc2(filec.Data());
+    if (!fitsc2)
+    {
+        cout << "ERROR - Open " << filec << " failed." << endl;
+        return 1;
+    }
+
+    fits fitsu1(fileu.Data());
+    fits fitsu2(fileu.Data());
+    if (!fitsu2)
+    {
+        cout << "ERROR - Open " << fileu << " failed." << endl;
+        return 2;
+    }
+
+    fits fitsi1(filei.Data());
+    fits fitsi2(filei.Data());
+    if (!fitsi2)
+    {
+        cout << "ERROR - Open " << filei << " failed." << endl;
+        return 3;
+    }
+
+    ofits fout(fileo.Data());
+    if (!fout)
+    {
+        cout << "ERROR - Open " << fileo << " failed." << endl;
+        return 4;
+    }
+
+    //const MTime now;
+    fout.SetStr(  "TELESCOP", "FACT",               "Telescope that acquired this data");
+    fout.SetStr(  "PACKAGE",  "MARS",               "Package name");
+    fout.SetStr(  "VERSION",  "1.0",                "Package description");
+    fout.SetFloat("EXTREL",   1.0,                  "Release Number");
+    //fout.SetStr(  "COMPILED", __DATE__" "__TIME__,  "Compile time");
+    fout.SetStr(  "ORIGIN",   "FACT",               "Institution that wrote the file");
+    //fout.SetStr(  "DATE",     now.GetStringFmt("%Y-%m-%dT%H:%M:%S").Data(), "File creation date");
+    //fout.SetInt(  "NIGHT",    now.GetNightAsInt(),  "Night as int");
+    fout.SetStr(  "TIMESYS",  "UTC",                "Time system");
+    fout.SetStr(  "TIMEUNIT", "d",                  "Time given in days w.r.t. to MJDREF");
+    fout.SetInt(  "MJDREF",   40587,                "MJD to UNIX time (seconds since 1970/1/1)");
+
+    fout.AddColumnDouble("Time",  "MJD", "Event time: MJD - MJDREF (= Unix Time)");
+    fout.AddColumnDouble("T_cal", "MJD", "Calibration time: MJD - MJDREF (= Unix Time)");
+    fout.AddColumnInt(   "N",     "",    "Number of valid values");
+    fout.AddColumnFloat( "I_avg", "uA",  "Average calibrated current (320 channels)");
+    fout.AddColumnFloat( "I_rms", "uA",  "RMS of calibrated current (320 channels)");
+    fout.AddColumnFloat( "I_med", "uA",  "Median of calibrated currents (320 channels)");
+    fout.AddColumnFloat( "I_dev", "uA",  "Deviation of calibrated currents (320 channels)");
+    fout.AddColumnFloat(416, "I", "uA", "My comment");
+
+    fout.WriteTableHeader("CALIBRATED");
+
+    Double_t timec, timeu, timei;
+    Double_t nextc, nextu, nexti;
+
+    if (!fitsc1.SetPtrAddress("Time", &timec))
+    {
+        cout << "ERROR couldn't get pointer to 1st Time for R" << endl;
+        return 2;
+    }
+    if (!fitsu1.SetPtrAddress("Time", &timeu))
+    {
+        cout << "ERROR couldn't get pointer to 1st Time for U" << endl;
+        return 2;
+    }
+    if (!fitsi1.SetPtrAddress("Time", &timei))
+    {
+        cout << "ERROR couldn't get pointer to 1st Time for I" << endl;
+        return 2;
+    }
+
+    if (!fitsc2.SetPtrAddress("Time", &nextc))
+    {
+        cout << "ERROR couldn't get pointer to 2nd Time for R" << endl;
+        return 2;
+    }
+    if (!fitsu2.SetPtrAddress("Time", &nextu))
+    {
+        cout << "ERROR couldn't get pointer to 2nd Time for U" << endl;
+        return 2;
+    }
+    if (!fitsi2.SetPtrAddress("Time", &nexti))
+    {
+        cout << "ERROR couldn't get pointer to 2nd Time for I" << endl;
+        return 2;
+    }
+
+    Float_t  R[416];
+    Float_t  U[416];
+    UShort_t I[416];
+
+    if (!fitsc1.SetPtrAddress("R",    R))
+    {
+        cout << "ERROR couldn't get pointer to R" << endl;
+        return 2;
+    }
+    if (!fitsu1.SetPtrAddress("Uout", U))
+    {
+        cout << "ERROR couldn't get pointer to U" << endl;
+        return 2;
+    }
+    if (!fitsi1.SetPtrAddress("I",    I))
+    {
+        cout << "ERROR couldn't get pointer to I" << endl;
+        return 2;
+    }
+
+    fitsc2.GetNextRow();
+    fitsu2.GetNextRow();
+    fitsi2.GetNextRow();
+
+    if (!fitsc1.GetNextRow())
+        return 0;
+    if (!fitsc2.GetNextRow())
+        nextc = 1e50;
+
+    while (1)
+    {
+        // First the next two rows (voltage, current)
+        // with identical time stamp
+        if (nextu<nextc && nextu<nexti)
+        {
+            if (!fitsu1.GetNextRow())
+                break;
+            fitsu2.GetNextRow();
+            continue;
+        }
+
+        if (nexti<nextc && nexti<nextu)
+        {
+            if (!fitsi1.GetNextRow())
+                break;
+            fitsi2.GetNextRow();
+            continue;
+        }
+
+        // At this point we have found currents and voltages
+        // with the same time-stamp
+        if (nexti!=nextu)
+            break;
+
+        // Now read the next row, voltages and currenst, which
+        // should be evaluated
+        if (!fitsu1.GetNextRow() || !fitsi1.GetNextRow())
+            break;
+
+        // Read also one event in advance to get the next time-stamps
+        fitsu2.GetNextRow();
+        fitsi2.GetNextRow();
+
+        // Read new calibration events as long as the difference
+        // in time to the next calibration evenet is smaller
+        // than to the current one. In this way always the
+        // closest one is used.
+        while (fabs(nextc-nextu)<fabs(timec-timeu))
+        {
+            // If there is no next one, make sure that
+            // the the condition is never met again.
+            if (!fitsc1.GetNextRow())
+            {
+                nextc=1e50;
+                break;
+            }
+            fitsc2.GetNextRow();
+        }
+
+        // Calibrate the data (subtract offset)
+        MArrayF rc(9+416);
+        MArrayF stat(416);
+
+        Float_t *cur = rc.GetArray()+9;
+
+        UInt_t cnt = 0;
+        for (int i=0; i<416; i++)
+        {
+            if (R[i]<=0)
+                continue;
+
+            // Convert dac counts to uA
+            // Measued current minus leakage current (bias crate calibration)
+            cur[i] = I[i] * 5000./4096 - U[i]/R[i]*1e6;
+
+            if (npix[i]>0)
+            {
+                cur[i] /= npix[i];
+                stat[cnt++] = cur[i];
+            }
+        }
+
+        memcpy(rc.GetArray(),   &timeu, sizeof(Double_t));
+        memcpy(rc.GetArray()+2, &timec, sizeof(Double_t));
+        memcpy(rc.GetArray()+4, &cnt,   sizeof(UInt_t));
+
+        Double_t med;
+        rc[5] = TMath::Mean(cnt, stat.GetArray());
+        rc[6] = TMath::RMS(cnt, stat.GetArray());
+        rc[8] = MMath::MedianDev(cnt, stat.GetArray(), med);
+        rc[7] = med;
+
+        fout.WriteRow(rc.GetArray(), rc.GetSize()*sizeof(Float_t));
+    }
+
+    return 0;
+}
