Print

Print


Author: [log in to unmask]
Date: Sat Jan 31 17:18:52 2015
New Revision: 2019

Log:
1st running pedestal

Added:
    java/trunk/users/src/main/java/org/hps/users/baltzell/
    java/trunk/users/src/main/java/org/hps/users/baltzell/ECalRunningPedestalDriver.java
    java/trunk/users/src/main/java/org/hps/users/baltzell/EcalRawConverterDriver_RunPed.java
    java/trunk/users/src/main/java/org/hps/users/baltzell/EcalRawConverter_RunPed.java

Added: java/trunk/users/src/main/java/org/hps/users/baltzell/ECalRunningPedestalDriver.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/baltzell/ECalRunningPedestalDriver.java	(added)
+++ java/trunk/users/src/main/java/org/hps/users/baltzell/ECalRunningPedestalDriver.java	Sat Jan 31 17:18:52 2015
@@ -0,0 +1,213 @@
+package org.hps.users.baltzell;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hps.conditions.database.TableConstants;
+import org.hps.conditions.ecal.EcalChannel;
+import org.hps.conditions.ecal.EcalChannelConstants;
+import org.hps.conditions.ecal.EcalConditions;
+import org.hps.recon.ecal.HitExtraData;
+import org.lcsim.conditions.ConditionsManager;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.GenericObject;
+import org.lcsim.event.LCRelation;
+import org.lcsim.event.RawCalorimeterHit;
+import org.lcsim.geometry.Detector;
+import org.lcsim.util.Driver;
+
+/**
+ * Calculate a running pedestal average for every channel from Mode7 FADCs.
+ * @version $Id: ECalRunningPedestalDriver.java,v 0.0 2015/01/31 00:00:00
+ * @author <[log in to unmask]>
+ */
+public class ECalRunningPedestalDriver extends Driver {
+
+    // limit array lengths:
+    private final int limitLookbackEvents = 1000;
+    
+    // minimum number of readouts for running averages:
+    // (if not satisfied, use pedestals from database)
+    private int minLookbackEvents = 10;
+    
+    // maximum number of readouts for running averages:
+    // (if too many, discard the oldest ones)
+    private int maxLookbackEvents = 100;
+    
+    // oldest allowed time for running averages:
+    // (discard older readouts ; negative = no time limit)
+    private long maxLookbackTime = -1; // units = ms
+
+    private static final String rawCollectionName = "EcalReadoutHits";
+    private static final String extraDataRelationsName = "EcalReadoutExtraDataRelations";
+    private static final String runningPedestalsName = "EcalRunningPedestals";
+
+    // FIXME:
+    private final int nChannels = 442;
+
+    // running pedestal averages, one for each channel:
+    private List<Double> runningPedestals = new ArrayList<Double>(nChannels);
+    
+    // FIXME:
+    // recent event-by-event pedestals and timestamps:
+    private List<Integer>[] eventPedestals = (ArrayList<Integer>[]) new ArrayList[nChannels];
+    private List<Long>[] eventTimestamps = (ArrayList<Long>[]) new ArrayList[nChannels];
+
+    private EcalConditions ecalConditions = null;
+
+    
+    
+    public ECalRunningPedestalDriver() {
+        for (int ii = 0; ii < nChannels; ii++) {
+            eventPedestals[ii] = new ArrayList<>();
+            eventTimestamps[ii] = new ArrayList<>();
+            runningPedestals.add(-1.); // would like to initialize with DB pedestals, but they're not available yet
+        }
+    }
+    @Override
+    protected void startOfData() {
+    }
+
+    @Override
+    public void detectorChanged(Detector detector) {
+        ecalConditions = ConditionsManager.defaultInstance()
+                .getCachedConditions(EcalConditions.class,TableConstants.ECAL_CONDITIONS)
+                .getCachedData();
+    }
+    public void setMinLookbackEvents(int nev) {
+        minLookbackEvents = nev;
+    }
+    public void setMaxLookbackEvents(int nev) {
+        maxLookbackEvents = nev;
+    }
+    public void setMaxLookbackTime(int time) {
+        maxLookbackTime = time;
+    }
+
+
+    public double getPedestal(int channel_id) {
+        final int nped = eventPedestals[channel_id - 1].size();
+        if (nped < minLookbackEvents) return getStaticPedestal(channel_id);
+        else                          return runningPedestals.get(channel_id - 1);
+    }
+
+    public void printPedestals() {
+        for (int ii = 0; ii < nChannels; ii++) {
+            System.out.printf("(%d,%.2f,%.2f) ",ii,runningPedestals.get(ii),getStaticPedestal(ii + 1));
+        }
+        System.out.printf("\n");
+    }
+
+    @Override
+    protected void process(EventHeader event) {
+        if (!event.hasCollection(RawCalorimeterHit.class,rawCollectionName))
+            return;
+        if (!event.hasCollection(LCRelation.class,extraDataRelationsName))
+            return;
+        for (LCRelation rel : event.get(LCRelation.class,extraDataRelationsName)) {
+            RawCalorimeterHit hit = (RawCalorimeterHit) rel.getFrom();
+            GenericObject extraData = (GenericObject) rel.getTo();
+            updatePedestal(event,hit,extraData);
+        }
+
+        // quick fix until I know how to read from DB before 'process':
+        List<Double> peds = new ArrayList<Double>(nChannels);
+        for (int ii=0; ii<nChannels; ii++){
+            peds.add(ii,getPedestal(ii+1));
+        }
+        
+        //
+        // don't care right now whether this persists in output slcio,
+        // just that it is accessible during reconstruction (and it is)
+        //
+        // Another option would be to put hits' running pedestals into HitExtraData.Mode7Data
+        // Or create another LCRelation
+        // Either would also remove the need for indexing later.
+        //
+        event.put(runningPedestalsName,peds,Double.class,1,"dog");
+//        event.put(runningPedestalsName,runningPedestals,Double.class,1,"dog");
+
+//        printPedestals();
+    }
+
+    public void updatePedestal(EventHeader event, RawCalorimeterHit hit, GenericObject mode7data) {
+        final int ii = getChannelID(hit) - 1;
+        if (ii < 0 || ii >= nChannels) {
+            System.err.println(String.format("Event #%d, Invalid id: %d/%d ",
+                    event.getEventNumber(),ii + 1,+hit.getCellID()));
+        }
+
+        final long timestamp = event.getTimeStamp();
+        final int min = ((HitExtraData.Mode7Data) mode7data).getAmplLow();
+        final int max = ((HitExtraData.Mode7Data) mode7data).getAmplHigh();
+
+        // ignore if pulse at beginning of window:
+        if (max <= 0) return;
+
+        // If new timestamp is older than previous one, restart pedestals.
+        // This should never happen unless firmware counter cycles back to zero,
+        // in which case it could be dealt with if max timestamp is known.
+        if (eventTimestamps[ii].size() > 0 && eventTimestamps[ii].get(0) > timestamp) {
+            System.err.println(String.format("Event #%d, Old Timestamp:  %d < %d",
+                    event.getEventNumber(),timestamp,eventTimestamps[ii].get(0)));
+            eventPedestals[ii].clear();
+            eventTimestamps[ii].clear();
+        }
+
+        // add pedestal to the list:
+        eventPedestals[ii].add(min);
+        eventTimestamps[ii].add(timestamp);
+
+        if (eventPedestals[ii].size() > 1) {
+
+            // remove oldest pedestal if we surpassed limit on #events:
+            if (eventPedestals[ii].size() > limitLookbackEvents
+                    || (maxLookbackEvents > 0 && eventPedestals[ii].size() > maxLookbackEvents)) {
+                eventPedestals[ii].remove(0);
+                eventTimestamps[ii].remove(0);
+            }
+
+            // remove old pedestals surpassing limit on lookback time:
+            if (maxLookbackTime > 0) {
+                while (eventTimestamps[ii].size() > 0) {
+                    if (eventTimestamps[ii].get(0) < timestamp - maxLookbackTime*1e6) {
+                        eventTimestamps[ii].remove(0);
+                        eventPedestals[ii].remove(0);
+                    } else {
+                        break;
+                    }
+                }
+            }
+        }
+
+        // Update running pedestal average:
+        if (eventPedestals[ii].size() > 0) {
+            double avg = 0;
+            for (int jj = 0; jj < eventPedestals[ii].size(); jj++) {
+                avg += eventPedestals[ii].get(jj);
+            }
+            runningPedestals.set(ii,avg / eventPedestals[ii].size());
+        } else {
+            runningPedestals.set(ii,getStaticPedestal(ii+1));
+        }
+    }
+
+    public double getPedestal(RawCalorimeterHit hit) {
+        return getPedestal(getChannelID(hit));
+    }
+    private double getStaticPedestal(int channel_id) {
+        EcalChannel cc = ecalConditions.getChannelCollection().findChannel(channel_id);
+        return ecalConditions.getChannelConstants(cc).getCalibration().getPedestal();
+    }
+    private double getStaticPedestal(RawCalorimeterHit hit) {
+        return getStaticPedestal(getChannelID(hit));
+    }
+    public int getChannelID(RawCalorimeterHit hit) {
+        return findChannel(hit.getCellID()).getCalibration().getChannelId();
+    }
+    public EcalChannelConstants findChannel(long cellID) {
+        return ecalConditions.getChannelConstants(ecalConditions.getChannelCollection()
+                .findGeometric(cellID));
+    }
+
+}

Added: java/trunk/users/src/main/java/org/hps/users/baltzell/EcalRawConverterDriver_RunPed.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/baltzell/EcalRawConverterDriver_RunPed.java	(added)
+++ java/trunk/users/src/main/java/org/hps/users/baltzell/EcalRawConverterDriver_RunPed.java	Sat Jan 31 17:18:52 2015
@@ -0,0 +1,301 @@
+package org.hps.users.baltzell;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.hps.conditions.database.TableConstants;
+import org.hps.conditions.ecal.EcalChannelConstants;
+import org.hps.conditions.ecal.EcalConditions;
+import org.lcsim.conditions.ConditionsManager;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.GenericObject;
+import org.lcsim.event.LCRelation;
+import org.lcsim.event.RawCalorimeterHit;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.geometry.Detector;
+import org.lcsim.lcio.LCIOConstants;
+import org.lcsim.util.Driver;
+
+/**
+ *
+ * @version $Id: HPSEcalRawConverterDriver.java,v 1.2 2012/05/03 00:17:54
+ * phansson Exp $
+ */
+public class EcalRawConverterDriver_RunPed extends Driver {
+
+    // To import database conditions
+    private EcalConditions ecalConditions = null;
+
+    private EcalRawConverter_RunPed converter = null;
+    private String rawCollectionName = "EcalReadoutHits";
+    private final String ecalReadoutName = "EcalHits";
+    private String ecalCollectionName = "EcalCalHits";
+
+    private static final String extraDataRelationsName = "EcalReadoutExtraDataRelations";
+//    private static final String extraDataCollectionName = "EcalReadoutExtraData";
+
+    private int integralWindow = 30; //A.C. on 12/14/2014 8:44 after discussion with Nathan.
+    private boolean debug = false;
+    private double threshold = Double.NEGATIVE_INFINITY;
+    private boolean applyBadCrystalMap = true;
+    private boolean dropBadFADC = false;
+    private boolean runBackwards = false;
+    private boolean useTimestamps = false;
+    private boolean useTruthTime = false;
+
+    public EcalRawConverterDriver_RunPed() {
+        converter = new EcalRawConverter_RunPed();
+    }
+
+    public void setUse2014Gain(boolean use2014Gain) {
+        converter.setUse2014Gain(use2014Gain);
+    }
+
+    public void setUseRunningPedestal(boolean useRunningPedestal) {
+        converter.setUseRunningPedestal(useRunningPedestal);
+    }
+    public void setRunBackwards(boolean runBackwards) {
+        this.runBackwards = runBackwards;
+    }
+
+    public void setDropBadFADC(boolean dropBadFADC) {
+        this.dropBadFADC = dropBadFADC;
+    }
+
+    public void setThreshold(double threshold) {
+        this.threshold = threshold;
+    }
+
+    public void setGain(double gain) {
+        converter.setGain(gain);
+    }
+
+    public void setIntegralWindow(int integralWindow) {
+        this.integralWindow = integralWindow;
+    }
+
+    public void setEcalCollectionName(String ecalCollectionName) {
+        this.ecalCollectionName = ecalCollectionName;
+    }
+
+    public void setRawCollectionName(String rawCollectionName) {
+        this.rawCollectionName = rawCollectionName;
+    }
+
+    public void setApplyBadCrystalMap(boolean apply) {
+        this.applyBadCrystalMap = apply;
+    }
+
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    public void setUseTimestamps(boolean useTimestamps) {
+        this.useTimestamps = useTimestamps;
+    }
+
+    public void setUseTruthTime(boolean useTruthTime) {
+        this.useTruthTime = useTruthTime;
+    }
+
+    @Override
+    public void startOfData() {
+        if (ecalCollectionName == null) {
+            throw new RuntimeException("The parameter ecalCollectionName was not set!");
+        }
+    }
+
+    @Override
+    public void detectorChanged(Detector detector) {
+
+        // set the detector for the converter
+        // FIXME: This method doesn't even need the detector object and does not use it.
+        converter.setDetector(detector);
+
+        // ECAL combined conditions object.
+        ecalConditions = ConditionsManager.defaultInstance()
+                .getCachedConditions(EcalConditions.class, TableConstants.ECAL_CONDITIONS).getCachedData();
+    }
+
+    /**
+     * @return false if the channel is a good one, true if it is a bad one
+     * @param CalorimeterHit
+     */
+    public boolean isBadCrystal(CalorimeterHit hit) {
+        // Get the channel data.
+        EcalChannelConstants channelData = findChannel(hit.getCellID());
+
+        return channelData.isBadChannel();
+    }
+
+    /**
+     * @return false if the ADC is a good one, true if it is a bad one
+     * @param CalorimeterHit
+     */
+    public boolean isBadFADC(CalorimeterHit hit) {
+        return (getCrate(hit.getCellID()) == 1 && getSlot(hit.getCellID()) == 3);
+    }
+
+    private static double getTimestamp(int system, EventHeader event) { //FIXME: copied from org.hps.readout.ecal.ReadoutTimestamp
+        if (event.hasCollection(GenericObject.class, "ReadoutTimestamps")) {
+            List<GenericObject> timestamps = event.get(GenericObject.class, "ReadoutTimestamps");
+            for (GenericObject timestamp : timestamps) {
+                if (timestamp.getIntVal(0) == system) {
+                    return timestamp.getDoubleVal(0);
+                }
+            }
+            return 0;
+        } else {
+            return 0;
+        }
+    }
+
+    @Override
+    public void process(EventHeader event) {
+        final int SYSTEM_TRIGGER = 0;
+        final int SYSTEM_TRACKER = 1;
+        final int SYSTEM_ECAL = 2;
+
+        double timeOffset = 0.0;
+        if (useTimestamps) {
+            double t0ECal = getTimestamp(SYSTEM_ECAL, event);
+            double t0Trig = getTimestamp(SYSTEM_TRIGGER, event);
+            timeOffset += (t0ECal - t0Trig) + 200.0;
+        }
+        if (useTruthTime) {
+            double t0ECal = getTimestamp(SYSTEM_ECAL, event);
+            timeOffset += ((t0ECal + 250.0) % 500.0) - 250.0;
+        }
+
+        int flags = 0;
+        flags += 1 << LCIOConstants.RCHBIT_TIME; //store hit time
+        flags += 1 << LCIOConstants.RCHBIT_LONG; //store hit position; this flag has no effect for RawCalorimeterHits
+
+        if (!runBackwards) {
+            ArrayList<CalorimeterHit> newHits = new ArrayList<CalorimeterHit>();
+
+            // Get the list of ECal hits.
+            if (event.hasCollection(RawTrackerHit.class, rawCollectionName)) {
+                List<RawTrackerHit> hits = event.get(RawTrackerHit.class, rawCollectionName);
+
+                for (RawTrackerHit hit : hits) {
+                    CalorimeterHit newHit = converter.HitDtoA(hit);
+
+                    // Get the channel data.
+                    EcalChannelConstants channelData = findChannel(newHit.getCellID());
+
+                    if (applyBadCrystalMap && channelData.isBadChannel()) {
+                        continue;
+                    }
+                    if (dropBadFADC && isBadFADC(newHit)) {
+                        continue;
+                    }
+                    if (newHit.getRawEnergy() > threshold) {
+                        newHits.add(newHit);
+                    }
+                }
+                event.put(ecalCollectionName, newHits, CalorimeterHit.class, flags, ecalReadoutName);
+            }
+            if (event.hasCollection(RawCalorimeterHit.class, rawCollectionName)) { //A.C. this is the case of the RAW pulse hits
+                if (event.hasCollection(LCRelation.class, extraDataRelationsName)) { // extra information available from mode 7 readout
+                    List<LCRelation> extraDataRelations = event.get(LCRelation.class, extraDataRelationsName);
+                    for (LCRelation rel : extraDataRelations) {
+                        RawCalorimeterHit hit = (RawCalorimeterHit) rel.getFrom();
+                        if (debug) {
+                            System.out.format("old hit energy %d\n", hit.getAmplitude());
+                        }
+                        GenericObject extraData = (GenericObject) rel.getTo();
+                        CalorimeterHit newHit;
+                        newHit = converter.HitDtoA(event, hit, extraData, integralWindow, timeOffset);
+                        if (newHit.getRawEnergy() > threshold) {
+                            if (applyBadCrystalMap && isBadCrystal(newHit)) {
+                                continue;
+                            }
+                            if (dropBadFADC && isBadFADC(newHit)) {
+                                continue;
+                            }
+                            if (debug) {
+                                System.out.format("new hit energy %f\n", newHit.getRawEnergy());
+                            }
+                            newHits.add(newHit);
+                        }
+
+                    }
+                } else {
+                    List<RawCalorimeterHit> hits = event.get(RawCalorimeterHit.class, rawCollectionName);
+                    for (RawCalorimeterHit hit : hits) {
+                        if (debug) {
+                            System.out.format("old hit energy %d\n", hit.getAmplitude());
+                        }
+                        CalorimeterHit newHit;
+                        newHit = converter.HitDtoA(hit, integralWindow, timeOffset);
+                        if (newHit.getRawEnergy() > threshold) {
+                            if (applyBadCrystalMap && isBadCrystal(newHit)) {
+                                continue;
+                            }
+                            if (dropBadFADC && isBadFADC(newHit)) {
+                                continue;
+                            }
+                            if (debug) {
+                                System.out.format("new hit energy %f\n", newHit.getRawEnergy());
+                            }
+                            newHits.add(newHit);
+                        }
+                    }
+                }
+                event.put(ecalCollectionName, newHits, CalorimeterHit.class, flags, ecalReadoutName);
+            }
+        } else {
+            ArrayList<RawCalorimeterHit> newHits = new ArrayList<RawCalorimeterHit>();
+            if (event.hasCollection(CalorimeterHit.class, ecalCollectionName)) {
+                List<CalorimeterHit> hits = event.get(CalorimeterHit.class, ecalCollectionName);
+
+                for (CalorimeterHit hit : hits) {
+                    if (debug) {
+                        System.out.format("old hit energy %f\n", hit.getRawEnergy());
+                    }
+                    RawCalorimeterHit newHit = converter.HitAtoD(hit, integralWindow);
+                    if (newHit.getAmplitude() > 0) {
+                        if (debug) {
+                            System.out.format("new hit energy %d\n", newHit.getAmplitude());
+                        }
+                        newHits.add(newHit);
+                    }
+                }
+                event.put(rawCollectionName, newHits, RawCalorimeterHit.class, flags, ecalReadoutName);
+            }
+        }
+    }
+
+    /**
+     * Convert physical ID to gain value.
+     *
+     * @param cellID (long)
+     * @return channel constants (EcalChannelConstants)
+     */
+    private EcalChannelConstants findChannel(long cellID) {
+        return ecalConditions.getChannelConstants(ecalConditions.getChannelCollection().findGeometric(cellID));
+    }
+
+    /**
+     * Return crate number from cellID
+     *
+     * @param cellID (long)
+     * @return Crate number (int)
+     */
+    private int getCrate(long cellID) {
+        // Find the ECAL channel and return the crate number.
+        return ecalConditions.getChannelCollection().findGeometric(cellID).getCrate();
+    }
+
+    /**
+     * Return slot number from cellID
+     *
+     * @param cellID (long)
+     * @return Slot number (int)
+     */
+    private int getSlot(long cellID) {
+        // Find the ECAL channel and return the slot number.
+        return ecalConditions.getChannelCollection().findGeometric(cellID).getSlot();
+    }
+}

Added: java/trunk/users/src/main/java/org/hps/users/baltzell/EcalRawConverter_RunPed.java
 =============================================================================
--- java/trunk/users/src/main/java/org/hps/users/baltzell/EcalRawConverter_RunPed.java	(added)
+++ java/trunk/users/src/main/java/org/hps/users/baltzell/EcalRawConverter_RunPed.java	Sat Jan 31 17:18:52 2015
@@ -0,0 +1,184 @@
+package org.hps.users.baltzell;
+
+import java.util.List;
+
+import org.hps.conditions.database.TableConstants;
+import org.hps.conditions.ecal.EcalCalibration;
+import org.hps.conditions.ecal.EcalChannelConstants;
+import org.hps.conditions.ecal.EcalConditions;
+import org.hps.recon.ecal.CalorimeterHitUtilities;
+import org.hps.recon.ecal.ECalUtils;
+import org.lcsim.conditions.ConditionsManager;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.GenericObject;
+import org.lcsim.event.RawCalorimeterHit;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.event.base.BaseRawCalorimeterHit;
+import org.lcsim.geometry.Detector;
+
+/**
+ * This class is used to convert {@link org.lcsim.event.RawCalorimeterHit}
+ * objects to {@link org.lcsim.event.CalorimeterHit} objects with energy
+ * information. It has methods to convert pedestal subtracted ADC counts to
+ * energy.
+ * 
+ * Temporary:  NAB January 31, 2015, just for testing running pedestal
+ *
+ * @author Sho Uemura <[log in to unmask]>
+ * @author Jeremy McCormick <[log in to unmask]>
+ * @author Andrea Celentano <[log in to unmask]>
+ */
+public class EcalRawConverter_RunPed {
+
+    private boolean useRunningPedestal = false;
+    private boolean constantGain = false;
+    private double gain;
+    private boolean use2014Gain = true;
+
+    private EcalConditions ecalConditions = null;
+
+    public EcalRawConverter_RunPed() {
+    }
+
+    public void setGain(double gain) {
+        constantGain = true;
+        this.gain = gain;
+    }
+
+    public void setUse2014Gain(boolean use2014Gain) {
+        this.use2014Gain = use2014Gain;
+    }
+
+    public void setUseRunningPedestal(boolean useRunningPedestal) {
+        this.useRunningPedestal=useRunningPedestal;
+    }
+   
+    // NAB January 2015
+    // Choose whether to use static pedestal from database or running pedestal:
+    public double getPedestal(EventHeader event, long cellID) {
+        EcalCalibration calib = findChannel(cellID).getCalibration();
+        if (useRunningPedestal) {
+            // works, but remove indexing by using LCRelation or adding to Mode7Data
+            if (event.hasCollection(Double.class,"EcalRunningPedestals")) {
+                List<Double> peds = event.get(Double.class,"EcalRunningPedestals");
+                final int cid = calib.getChannelId()-1;
+                if (cid < 0 || cid>=peds.size()) {
+                    // logger, or throw exception, ...
+                    System.err.println("EcalRawConverter::getPedestal Bad Channel_id: "+cid);
+                } else {
+                    // System.out.println(String.format("%d -  %.2f",channel_id-1,peds.get(cid)));
+                    return peds.get(cid);
+                }
+            }
+        }
+        // pedestal from database:
+        return calib.getPedestal();
+    }
+
+    public short sumADC(RawTrackerHit hit) {
+        EcalChannelConstants channelData = findChannel(hit.getCellID());
+        double pedestal = channelData.getCalibration().getPedestal();
+        short sum = 0;
+        short samples[] = hit.getADCValues();
+        for (int isample = 0; isample < samples.length; ++isample) {
+            sum += (samples[isample] - pedestal);
+        }
+        return sum;
+    }
+
+    public CalorimeterHit HitDtoA(RawTrackerHit hit) {
+        double time = hit.getTime();
+        long id = hit.getCellID();
+        double rawEnergy = adcToEnergy(sumADC(hit), id);
+        return CalorimeterHitUtilities.create(rawEnergy, time, id);
+    }
+
+    public CalorimeterHit HitDtoA(RawCalorimeterHit hit, int window, double timeOffset) {
+        if (hit.getTimeStamp() % 64 != 0) {
+            System.out.println("unexpected timestamp " + hit.getTimeStamp());
+        }
+        double time = hit.getTimeStamp() / 16.0;
+        long id = hit.getCellID();
+        // Get the channel data.
+        EcalChannelConstants channelData = findChannel(id);
+        double adcSum = hit.getAmplitude() - window * channelData.getCalibration().getPedestal();
+        double rawEnergy = adcToEnergy(adcSum, id);
+        return CalorimeterHitUtilities.create(rawEnergy, time + timeOffset, id);
+        //return h2;
+    }
+
+    // NAB Januray 2015, mod for running pedestal
+    public CalorimeterHit HitDtoA(EventHeader event,RawCalorimeterHit hit, GenericObject mode7Data, int window, double timeOffset) {
+        double time = hit.getTimeStamp() / 16.0; //timestamps use the full 62.5 ps resolution
+        long id = hit.getCellID();
+//        // Get the channel data.
+        EcalChannelConstants channelData = findChannel(id);
+//        double adcSum = hit.getAmplitude() - window * channelData.getCalibration().getPedestal();
+//        double adcSum = hit.getAmplitude() - window * Mode7Data.getAmplLow(mode7Data);                              //A.C. is this the proper way to pedestal subtract in mode 7?
+        double adcSum = hit.getAmplitude() - window * getPedestal(event,id);
+        double rawEnergy = adcToEnergy(adcSum, id);        
+        return CalorimeterHitUtilities.create(rawEnergy, time + timeOffset, id);
+                       
+        //return h2;
+    }
+
+    public RawCalorimeterHit HitAtoD(CalorimeterHit hit, int window) {
+        int time = (int) (Math.round(hit.getTime() / 4.0) * 64.0);
+        long id = hit.getCellID();
+        // Get the channel data.
+        EcalChannelConstants channelData = findChannel(id);
+        int amplitude;
+        if (constantGain) {
+            amplitude = (int) Math.round((hit.getRawEnergy() / ECalUtils.MeV) / gain + window * channelData.getCalibration().getPedestal());
+        } else {
+            amplitude = (int) Math.round((hit.getRawEnergy() / ECalUtils.MeV) / channelData.getGain().getGain() + window * channelData.getCalibration().getPedestal());
+        }
+        RawCalorimeterHit h = new BaseRawCalorimeterHit(id, amplitude, time);
+        return h;
+    }
+
+    /*
+     * return energy (units of GeV) corresponding to the ADC sum and crystal ID
+     */
+    private double adcToEnergy(double adcSum, long cellID) {
+
+        // Get the channel data.
+        EcalChannelConstants channelData = findChannel(cellID);
+
+        if (use2014Gain) {
+            if (constantGain) {
+                return adcSum * ECalUtils.gainFactor * ECalUtils.ecalReadoutPeriod;
+            } else {
+                return channelData.getGain().getGain() * adcSum * ECalUtils.gainFactor * ECalUtils.ecalReadoutPeriod; // should not be used for the moment (2014/02)
+            }
+        } else {
+            if (constantGain) {
+                return gain * adcSum * ECalUtils.MeV;
+            } else {
+                return channelData.getGain().getGain() * adcSum * ECalUtils.MeV; //gain is defined as MeV/integrated ADC
+            }
+        }
+    }
+
+    /**
+     * Must be set when an object EcalRawConverter is created.
+     *
+     * @param detector (long)
+     */
+    public void setDetector(Detector detector) {
+        // ECAL combined conditions object.
+        ecalConditions = ConditionsManager.defaultInstance()
+                .getCachedConditions(EcalConditions.class, TableConstants.ECAL_CONDITIONS).getCachedData();
+    }
+
+    /**
+     * Convert physical ID to gain value.
+     *
+     * @param cellID (long)
+     * @return channel constants (EcalChannelConstants)
+     */
+    public EcalChannelConstants findChannel(long cellID) {
+        return ecalConditions.getChannelConstants(ecalConditions.getChannelCollection().findGeometric(cellID));
+    }    
+}