diff --git a/cmake/GENIESetup.cmake b/cmake/GENIESetup.cmake
index 11c64b3..0dfd88e 100644
--- a/cmake/GENIESetup.cmake
+++ b/cmake/GENIESetup.cmake
@@ -1,168 +1,166 @@
 # Copyright 2016 L. Pickering, P Stowell, R. Terri, C. Wilkinson, C. Wret
 
 ################################################################################
 #    This file is part of NUISANCE.
 #
 #    NUISANCE is free software: you can redistribute it and/or modify
 #    it under the terms of the GNU General Public License as published by
 #    the Free Software Foundation, either version 3 of the License, or
 #    (at your option) any later version.
 #
 #    NUISANCE is distributed in the hope that it will be useful,
 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 #    GNU General Public License for more details.
 #
 #    You should have received a copy of the GNU General Public License
 #    along with NUISANCE.  If not, see <http://www.gnu.org/licenses/>.
 ################################################################################
 
 # TODO
 # check system for libxml2
 # check whether we need the includes
 # check if we can use a subset of the GENIE libraries
 
 ################################################################################
 #                            Check Dependencies
 ################################################################################
 
 #################################  GENIE  ######################################
 if(GENIE STREQUAL "")
   cmessage(FATAL_ERROR "Variable GENIE is not defined. "
     "The location of a pre-built GENIE install must be defined either as"
     " $ cmake -DGENIE=/path/to/GENIE or as and environment vairable"
     " $ export GENIE=/path/to/GENIE")
 endif()
 
 if (BUILD_GEVGEN)
   cmessage(STATUS "Building custom gevgen")
   LIST(APPEND EXTRA_CXX_FLAGS -D__GEVGEN_ENABLED__)
 endif()
 
 # Extract GENIE VERSION
 if (GENIE_VERSION STREQUAL "AUTO")
    execute_process (COMMAND ${CMAKE_SOURCE_DIR}/cmake/getgenieversion.sh ${GENIE}
    OUTPUT_VARIABLE GENIE_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
 endif()
 
 execute_process (COMMAND genie-config
   --libs OUTPUT_VARIABLE GENIE_LD_FLAGS_STR OUTPUT_STRIP_TRAILING_WHITESPACE)
 execute_process (COMMAND genie-config
   --topsrcdir OUTPUT_VARIABLE GENIE_INCLUDES_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
 
 string(REGEX MATCH "-L\([^ ]+\) \(.*\)$" PARSE_GENIE_LIBS_MATCH ${GENIE_LD_FLAGS_STR})
 
 cmessage(DEBUG "genie-config --libs: ${GENIE_LD_FLAGS_STR}")
 
 if(NOT PARSE_GENIE_LIBS_MATCH)
   cmessage(FATAL_ERROR "Expected to be able to parse the result of genie-config --libs to a lib directory and a list of libraries to include, but got: \"${GENIE_LD_FLAGS_STR}\"")
 endif()
 
 set(GENIE_LIB_DIR ${CMAKE_MATCH_1})
 set(GENIE_LIBS_RAW ${CMAKE_MATCH_2})
 string(REPLACE "-l" "" GENIE_LIBS_STRIPED "${GENIE_LIBS_RAW}")
 
 cmessage(STATUS "GENIE version : ${GENIE_VERSION}")
 cmessage(STATUS "GENIE libdir  : ${GENIE_LIB_DIR}")
 cmessage(STATUS "GENIE libs    : ${GENIE_LIBS_STRIPED}")
 
 string(REGEX MATCH "ReinSeghal" WASMATCHED ${GENIE_LIBS_STRIPED})
 if(WASMATCHED AND GENIE_VERSION STREQUAL "210")
   set(GENIE_SEHGAL ${GENIE_LIBS_STRIPED})
   STRING(REPLACE "ReinSeghal" "ReinSehgal" GENIE_LIBS_STRIPED ${GENIE_SEHGAL})
   cmessage(DEBUG "Fixed inconsistency in library naming: ${GENIE_LIBS_STRIPED}")
 endif()
 
 string(REGEX MATCH "ReWeight" WASMATCHED ${GENIE_LIBS_STRIPED})
 if(NOT WASMATCHED)
   set(GENIE_LIBS_STRIPED "GReWeight ${GENIE_LIBS_STRIPED}")
   cmessage(DEBUG "Force added ReWeight library: ${GENIE_LIBS_STRIPED}")
 endif()
 
 string(REPLACE " " ";" GENIE_LIBS_LIST "-Wl,--start-group ${GENIE_LIBS_STRIPED} -Wl,--end-group")
 cmessage(DEBUG "genie-config --libs -- MATCH1: ${CMAKE_MATCH_1}")
 cmessage(DEBUG "genie-config --libs -- MATCH2: ${CMAKE_MATCH_2}")
 cmessage(DEBUG "genie-config --libs -- libs stripped: ${GENIE_LIBS_STRIPED}")
 cmessage(DEBUG "genie-config --libs -- libs list: ${GENIE_LIBS_LIST}")
 
 ################################  LHAPDF  ######################################
 if(LHAPDF_LIB STREQUAL "")
   cmessage(FATAL_ERROR "Variable LHAPDF_LIB is not defined. The location of a pre-built lhapdf install must be defined either as $ cmake -DLHAPDF_LIB=/path/to/LHAPDF_libraries or as and environment vairable $ export LHAPDF_LIB=/path/to/LHAPDF_libraries")
 endif()
 
 if(LHAPDF_INC STREQUAL "")
   cmessage(FATAL_ERROR "Variable LHAPDF_INC is not defined. The location of a pre-built lhapdf install must be defined either as $ cmake -DLHAPDF_INC=/path/to/LHAPDF_includes or as and environment vairable $ export LHAPDF_INC=/path/to/LHAPDF_includes")
 endif()
 
 if(LHAPATH STREQUAL "")
   cmessage(FATAL_ERROR "Variable LHAPATH is not defined. The location of a the LHAPATH directory must be defined either as $ cmake -DLHAPATH=/path/to/LHAPATH or as and environment variable $ export LHAPATH=/path/to/LHAPATH")
 endif()
 
 ################################  LIBXML  ######################################
 if(LIBXML2_LIB STREQUAL "")
   cmessage(FATAL_ERROR "Variable LIBXML2_LIB is not defined. The location of a pre-built libxml2 install must be defined either as $ cmake -DLIBXML2_LIB=/path/to/LIBXML2_libraries or as and environment vairable $ export LIBXML2_LIB=/path/to/LIBXML2_libraries")
 endif()
 
 if(LIBXML2_INC STREQUAL "")
   cmessage(FATAL_ERROR "Variable LIBXML2_INC is not defined. The location of a pre-built libxml2 install must be defined either as $ cmake -DLIBXML2_INC=/path/to/LIBXML2_includes or as and environment vairable $ export LIBXML2_INC=/path/to/LIBXML2_includes")
 endif()
 ###############################  log4cpp  ######################################
 if(LOG4CPP_LIB STREQUAL "")
   find_program(LOG4CPPCFG log4cpp-config)
   if(NOT LOG4CPPCFG STREQUAL "LOG4CPPCFG-NOTFOUND")
     execute_process (COMMAND ${LOG4CPPCFG}
     --pkglibdir OUTPUT_VARIABLE LOG4CPP_LIB OUTPUT_STRIP_TRAILING_WHITESPACE)
   else()
     message(FATAL_ERROR "Variable LOG4CPP_LIB is not defined. The location of a pre-built log4cpp install must be defined either as $ cmake -DLOG4CPP_LIB=/path/to/LOG4CPP_libraries or as and environment vairable $ export LOG4CPP_LIB=/path/to/LOG4CPP_libraries")
   endif()
 endif()
 
 if(LOG4CPP_INC  STREQUAL "")
   find_program(LOG4CPPCFG log4cpp-config)
   if(NOT LOG4CPPCFG STREQUAL "LOG4CPPCFG-NOTFOUND")
     execute_process (COMMAND ${LOG4CPPCFG}
     --pkgincludedir OUTPUT_VARIABLE LOG4CPP_INC OUTPUT_STRIP_TRAILING_WHITESPACE)
   else()
     message(FATAL_ERROR "Variable LOG4CPP_INC is not defined. The location of a pre-built log4cpp install must be defined either as $ cmake -DGENIE_LOG4CPP_INC=/path/to/LOG4CPP_includes or as and environment vairable $ export LOG4CPP_INC=/path/to/LOG4CPP_includes")
   endif()
 endif()
 ################################################################################
 
 LIST(APPEND EXTRA_CXX_FLAGS -D__GENIE_ENABLED__ -D__GENIE_VERSION__=${GENIE_VERSION})
 
 LIST(APPEND RWENGINE_INCLUDE_DIRECTORIES
   ${GENIE_INCLUDES_DIR}
   ${GENIE_INCLUDES_DIR}/GHEP
   ${GENIE_INCLUDES_DIR}/Ntuple
   ${GENIE_INCLUDES_DIR}/ReWeight
   ${GENIE_INCLUDES_DIR}/Apps
   ${GENIE_INCLUDES_DIR}/FluxDrivers
   ${GENIE_INCLUDES_DIR}/EVGDrivers
   ${LHAPDF_INC}
   ${LIBXML2_INC}
   ${LOG4CPP_INC})
 
 SAYVARS()
 
 LIST(APPEND EXTRA_LINK_DIRS
   ${GENIE_LIB_DIR}
   ${LHAPDF_LIB}
   ${LIBXML2_LIB}
   ${LOG4CPP_LIB})
 
-LIST(APPEND EXTRA_LIBS -Wl,--start-group)
 LIST(APPEND EXTRA_LIBS ${GENIE_LIBS_LIST})
-LIST(APPEND EXTRA_LIBS -Wl,--end-group)
 
 LIST(APPEND EXTRA_LIBS LHAPDF xml2 log4cpp)
 
 if(USE_PYTHIA8)
   set(NEED_PYTHIA8 TRUE)
   set(NEED_ROOTPYTHIA8 TRUE)
 else()
   set(NEED_PYTHIA6 TRUE)
   set(NEED_ROOTPYTHIA6 TRUE)
 endif()
 set(NEED_ROOTEVEGEN TRUE)
 
 SET(USE_GENIE TRUE CACHE BOOL "Whether to enable GENIE (reweight) support. Requires external libraries. <FALSE>" FORCE)
diff --git a/src/FitBase/Measurement1D.cxx b/src/FitBase/Measurement1D.cxx
index 3306167..5140ffd 100644
--- a/src/FitBase/Measurement1D.cxx
+++ b/src/FitBase/Measurement1D.cxx
@@ -1,1905 +1,1904 @@
 // Copyright 2016 L. Pickering, P. Stowell, R. Terri, C. Wilkinson, C. Wret
 
 /*******************************************************************************
 *    This ile is part of NUISANCE.
 *
 *    NUISANCE is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    NUISANCE is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with NUISANCE.  If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/
 #include "Measurement1D.h"
 
 
 //********************************************************************
 Measurement1D::Measurement1D(void) {
 //********************************************************************
 
   // XSec Scalings
   fScaleFactor = -1.0;
   fCurrentNorm = 1.0;
 
   // Histograms
   fDataHist = NULL;
   fDataTrue = NULL;
 
   fMCHist = NULL;
   fMCFine = NULL;
   fMCWeighted = NULL;
 
   fMaskHist = NULL;
 
   // Covar
   covar = NULL;
   fFullCovar = NULL;
   fShapeCovar = NULL;
 
   fCovar  = NULL;
   fInvert = NULL;
   fDecomp = NULL;
 
   // Fake Data
   fFakeDataInput = "";
   fFakeDataFile  = NULL;
 
   // Options
   fDefaultTypes = "FIX/FULL/CHI2";
   fAllowedTypes =
     "FIX,FREE,SHAPE/FULL,DIAG/CHI2/NORM/ENUCORR/Q2CORR/ENU1D/MASK/NOWIDTH";
 
   fIsFix = false;
   fIsShape = false;
   fIsFree = false;
   fIsDiag = false;
   fIsFull = false;
   fAddNormPen = false;
   fIsMask = false;
   fIsChi2SVD = false;
   fIsRawEvents = false;
   fIsNoWidth = false;
   fIsDifXSec = false;
   fIsEnu1D = false;
 
   // Inputs
   fInput = NULL;
   fRW = NULL;
 
   // Extra Histograms
   fMCHist_Modes = NULL;
 
 }
 
 //********************************************************************
 Measurement1D::~Measurement1D(void) {
 //********************************************************************
 
   if (fDataHist)   delete fDataHist;
   if (fDataTrue)   delete fDataTrue;
   if (fMCHist)     delete fMCHist;
   if (fMCFine)     delete fMCFine;
   if (fMCWeighted) delete fMCWeighted;
   if (fMaskHist)   delete fMaskHist;
   if (covar)       delete covar;
   if (fFullCovar)  delete fFullCovar;
   if (fShapeCovar) delete fShapeCovar;
   if (fCovar)      delete fCovar;
   if (fInvert)     delete fInvert;
   if (fDecomp)     delete fDecomp;
 
 }
 
 //********************************************************************
 void Measurement1D::FinaliseSampleSettings() {
 //********************************************************************
 
   MeasurementBase::FinaliseSampleSettings();
 
   // Setup naming + renaming
   fName = fSettings.GetName();
   fSettings.SetS("originalname", fName);
   if (fSettings.Has("rename")) {
     fName = fSettings.GetS("rename");
     fSettings.SetS("name", fName);
   }
 
   // Setup all other options
   LOG(SAM) << "Finalising Sample Settings: " << fName << std::endl;
 
   if ((fSettings.GetS("originalname").find("Evt") != std::string::npos)) {
     fIsRawEvents = true;
     LOG(SAM) << "Found event rate measurement but using poisson likelihoods."
              << std::endl;
   }
 
   if (fSettings.GetS("originalname").find("XSec_1DEnu") != std::string::npos) {
     fIsEnu1D = true;
     LOG(SAM) << "::" << fName << "::" << std::endl;
     LOG(SAM) << "Found XSec Enu measurement, applying flux integrated scaling, "
              << "not flux averaged!" << std::endl;
   }
 
   if (fIsEnu1D && fIsRawEvents) {
     LOG(SAM) << "Found 1D Enu XSec distribution AND fIsRawEvents, is this "
              "really correct?!"
              << std::endl;
     LOG(SAM) << "Check experiment constructor for " << fName
              << " and correct this!" << std::endl;
     LOG(SAM) << "I live in " << __FILE__ << ":" << __LINE__ << std::endl;
     exit(-1);
   }
 
   if (!fRW) fRW = FitBase::GetRW();
   if (!fInput and !fIsJoint) SetupInputs(fSettings.GetS("input"));
 
   // Setup options
   SetFitOptions(fDefaultTypes); // defaults
   SetFitOptions(fSettings.GetS("type")); // user specified
 
   EnuMin = GeneralUtils::StrToDbl(fSettings.GetS("enu_min"));
   EnuMax = GeneralUtils::StrToDbl(fSettings.GetS("enu_max"));
 
   if (fAddNormPen) {
     if (fNormError <= 0.0) {
       ERR(WRN) << "Norm error for class " << fName << " is 0.0!" << std::endl;
       ERR(WRN) << "If you want to use it please add fNormError=VAL" << std::endl;
       throw;
     }
   }
-
 }
 
 //********************************************************************
 void Measurement1D::CreateDataHistogram(int dimx, double* binx) {
 //********************************************************************
 
   if (fDataHist) delete fDataHist;
 
   fDataHist = new TH1D( (fSettings.GetName() + "_data").c_str(), (fSettings.GetFullTitles()).c_str(),
                         dimx, binx) ;
 
 }
 
 
 //********************************************************************
 void Measurement1D::SetDataFromTextFile(std::string datafile) {
 //********************************************************************
 
   LOG(SAM) << "Reading data from text file: " << datafile << std::endl;
   fDataHist = PlotUtils::GetTH1DFromFile(datafile,
                                          fSettings.GetName() + "_data",
                                          fSettings.GetFullTitles());
 }
 
 //********************************************************************
 void Measurement1D::SetDataFromRootFile(std::string datafile,
                                         std::string histname) {
 //********************************************************************
 
   LOG(SAM) << "Reading data from root file: " << datafile << ";" << histname << std::endl;
   fDataHist = PlotUtils::GetTH1DFromRootFile(datafile, histname);
   fDataHist->SetNameTitle((fSettings.GetName() + "_data").c_str(),
                           (fSettings.GetFullTitles()).c_str());
 
   return;
 };
 
 //********************************************************************
 void Measurement1D::SetEmptyData(){
 //********************************************************************
 
   fDataHist = new TH1D("EMPTY_DATA","EMPTY_DATA",1,0.0,1.0);
 }
 
 //********************************************************************
 void Measurement1D::SetPoissonErrors() {
 //********************************************************************
 
   if (!fDataHist) {
     ERR(FTL) << "Need a data hist to setup possion errors! " << std::endl;
     ERR(FTL) << "Setup Data First!" << std::endl;
     throw;
   }
 
   for (int i = 0; i < fDataHist->GetNbinsX() + 1; i++) {
     fDataHist->SetBinError(i + 1, sqrt(fDataHist->GetBinContent(i + 1)));
   }
 }
 
 //********************************************************************
 void Measurement1D::SetCovarFromDiagonal(TH1D* data) {
 //********************************************************************
 
   if (!data and fDataHist) {
     data = fDataHist;
   }
 
   if (data) {
     LOG(SAM) << "Setting diagonal covariance for: " << data->GetName() << std::endl;
     fFullCovar = StatUtils::MakeDiagonalCovarMatrix(data);
     covar      = StatUtils::GetInvert(fFullCovar);
     fDecomp    = StatUtils::GetDecomp(fFullCovar);
   } else {
     ERR(FTL) << "No data input provided to set diagonal covar from!" << std::endl;
 
   }
 
   // if (!fIsDiag) {
   //   ERR(FTL) << "SetCovarMatrixFromDiag called for measurement "
   //            << "that is not set as diagonal." << std::endl;
   //   throw;
   // }
 
 }
 
 //********************************************************************
 void Measurement1D::SetCovarFromTextFile(std::string covfile, int dim) {
 //********************************************************************
 
   if (dim == -1) {
     dim = fDataHist->GetNbinsX();
   }
 
   LOG(SAM) << "Reading covariance from text file: " << covfile << std::endl;
   fFullCovar = StatUtils::GetCovarFromTextFile(covfile, dim);
   covar      = StatUtils::GetInvert(fFullCovar);
   fDecomp    = StatUtils::GetDecomp(fFullCovar);
 
 }
 
 
 //********************************************************************
 void Measurement1D::SetCovarFromMultipleTextFiles(std::string covfiles, int dim) {
 //********************************************************************
 
   if (dim == -1) {
     dim = fDataHist->GetNbinsX();
   }
 
   std::vector<std::string> covList = GeneralUtils::ParseToStr(covfiles, ";");
 
   fFullCovar = new TMatrixDSym(dim);
   for (uint i = 0; i < covList.size(); ++i){
     LOG(SAM) << "Reading covariance from text file: " << covList[i] << std::endl;
     TMatrixDSym* temp_cov = StatUtils::GetCovarFromTextFile(covList[i], dim);
     (*fFullCovar) += (*temp_cov);
     delete temp_cov;
   }
   covar      = StatUtils::GetInvert(fFullCovar);
   fDecomp    = StatUtils::GetDecomp(fFullCovar);
 
 }
 
 
 //********************************************************************
 void Measurement1D::SetCovarFromRootFile(std::string covfile, std::string histname) {
 //********************************************************************
 
   LOG(SAM) << "Reading covariance from text file: " << covfile << ";" << histname << std::endl;
   fFullCovar = StatUtils::GetCovarFromRootFile(covfile, histname);
   covar      = StatUtils::GetInvert(fFullCovar);
   fDecomp    = StatUtils::GetDecomp(fFullCovar);
 
 }
 
 //********************************************************************
 void Measurement1D::SetCovarInvertFromTextFile(std::string covfile, int dim) {
 //********************************************************************
 
   if (dim == -1) {
     dim = fDataHist->GetNbinsX();
   }
 
   LOG(SAM) << "Reading inverted covariance from text file: " << covfile << std::endl;
   covar       = StatUtils::GetCovarFromTextFile(covfile, dim);
   fFullCovar  = StatUtils::GetInvert(covar);
   fDecomp     = StatUtils::GetDecomp(fFullCovar);
 
 }
 
 //********************************************************************
 void Measurement1D::SetCovarInvertFromRootFile(std::string covfile, std::string histname) {
 //********************************************************************
 
   LOG(SAM) << "Reading inverted covariance from text file: " << covfile << ";" << histname << std::endl;
   covar      = StatUtils::GetCovarFromRootFile(covfile, histname);
   fFullCovar = StatUtils::GetInvert(covar);
   fDecomp    = StatUtils::GetDecomp(fFullCovar);
 
 }
 
 //********************************************************************
 void Measurement1D::SetCorrelationFromTextFile(std::string covfile, int dim) {
 //********************************************************************
 
   if (dim == -1) dim = fDataHist->GetNbinsX();
   LOG(SAM) << "Reading data correlations from text file: " << covfile << ";" << dim << std::endl;
   TMatrixDSym* correlation = StatUtils::GetCovarFromTextFile(covfile, dim);
 
   if (!fDataHist) {
     ERR(FTL) << "Trying to set correlations from text file but there is no data to build it from. \n"
              << "In constructor make sure data is set before SetCorrelationFromTextFile is called. \n" << std::endl;
     throw;
   }
 
   // Fill covar from data errors and correlations
   fFullCovar = new TMatrixDSym(dim);
   for (int i = 0; i < fDataHist->GetNbinsX(); i++) {
     for (int j = 0; j < fDataHist->GetNbinsX(); j++) {
       (*fFullCovar)(i, j) = (*correlation)(i, j) * fDataHist->GetBinError(i + 1) * fDataHist->GetBinError(j + 1) * 1.E76;
     }
   }
 
   // Fill other covars.
   covar   = StatUtils::GetInvert(fFullCovar);
   fDecomp = StatUtils::GetDecomp(fFullCovar);
 
   delete correlation;
 }
 
 //********************************************************************
 void Measurement1D::SetCorrelationFromMultipleTextFiles(std::string corrfiles, int dim) {
 //********************************************************************
 
   if (dim == -1) {
     dim = fDataHist->GetNbinsX();
   }
 
   std::vector<std::string> corrList = GeneralUtils::ParseToStr(corrfiles, ";");
 
   fFullCovar = new TMatrixDSym(dim);
   for (uint i = 0; i < corrList.size(); ++i){
     LOG(SAM) << "Reading covariance from text file: " << corrList[i] << std::endl;
     TMatrixDSym* temp_cov = StatUtils::GetCovarFromTextFile(corrList[i], dim);
 
     for (int i = 0; i < fDataHist->GetNbinsX(); i++) {
       for (int j = 0; j < fDataHist->GetNbinsX(); j++) {
 	(*temp_cov)(i, j) = (*temp_cov)(i, j) * fDataHist->GetBinError(i + 1) * fDataHist->GetBinError(j + 1) * 1.E76;
       }
     }
 
     (*fFullCovar) += (*temp_cov);
     delete temp_cov;
   }
   covar      = StatUtils::GetInvert(fFullCovar);
   fDecomp    = StatUtils::GetDecomp(fFullCovar);
 
 }
 
 
 //********************************************************************
 void Measurement1D::SetCorrelationFromRootFile(std::string covfile, std::string histname) {
 //********************************************************************
 
   LOG(SAM) << "Reading data correlations from text file: " << covfile << ";" << histname << std::endl;
   TMatrixDSym* correlation = StatUtils::GetCovarFromRootFile(covfile, histname);
 
   if (!fDataHist) {
     ERR(FTL) << "Trying to set correlations from text file but there is no data to build it from. \n"
              << "In constructor make sure data is set before SetCorrelationFromTextFile is called. \n" << std::endl;
     throw;
   }
 
   // Fill covar from data errors and correlations
   fFullCovar = new TMatrixDSym(fDataHist->GetNbinsX());
   for (int i = 0; i < fDataHist->GetNbinsX(); i++) {
     for (int j = 0; j < fDataHist->GetNbinsX(); j++) {
       (*fFullCovar)(i, j) = (*correlation)(i, j) * fDataHist->GetBinError(i + 1) * fDataHist->GetBinError(j + 1) * 1.E76;
     }
   }
 
   // Fill other covars.
   covar   = StatUtils::GetInvert(fFullCovar);
   fDecomp = StatUtils::GetDecomp(fFullCovar);
 
   delete correlation;
 }
 
 
 //********************************************************************
 void Measurement1D::SetCholDecompFromTextFile(std::string covfile, int dim) {
 //********************************************************************
 
   if (dim == -1) {
     dim = fDataHist->GetNbinsX();
   }
 
   LOG(SAM) << "Reading cholesky from text file: " << covfile << std::endl;
   TMatrixD* temp = StatUtils::GetMatrixFromTextFile(covfile, dim, dim);
 
   TMatrixD* trans = (TMatrixD*)temp->Clone();
   trans->T();
   (*trans) *= (*temp);
 
   fFullCovar  = new TMatrixDSym(dim, trans->GetMatrixArray(), "");
   covar       = StatUtils::GetInvert(fFullCovar);
   fDecomp     = StatUtils::GetDecomp(fFullCovar);
 
   delete temp;
   delete trans;
 
 }
 
 //********************************************************************
 void Measurement1D::SetCholDecompFromRootFile(std::string covfile, std::string histname) {
 //********************************************************************
 
   LOG(SAM) << "Reading cholesky decomp from root file: " << covfile << ";" << histname << std::endl;
   TMatrixD* temp = StatUtils::GetMatrixFromRootFile(covfile, histname);
 
   TMatrixD* trans = (TMatrixD*)temp->Clone();
   trans->T();
   (*trans) *= (*temp);
 
   fFullCovar  = new TMatrixDSym(temp->GetNrows(), trans->GetMatrixArray(), "");
   covar       = StatUtils::GetInvert(fFullCovar);
   fDecomp     = StatUtils::GetDecomp(fFullCovar);
 
   delete temp;
   delete trans;
 }
 
 void Measurement1D::SetShapeCovar(){
 
   // Return if this is missing any pre-requisites
   if (!fFullCovar) return;
   if (!fDataHist) return;
 
   // Also return if it's bloody stupid under the circumstances
   if (fIsDiag) return;
 
   fShapeCovar = StatUtils::ExtractShapeOnlyCovar(fFullCovar, fDataHist);
   return;
 }
 
 //********************************************************************
 void Measurement1D::ScaleData(double scale) {
 //********************************************************************
   fDataHist->Scale(scale);
 }
 
 
 //********************************************************************
 void Measurement1D::ScaleDataErrors(double scale) {
 //********************************************************************
   for (int i = 0; i < fDataHist->GetNbinsX(); i++) {
     fDataHist->SetBinError(i + 1, fDataHist->GetBinError(i + 1) * scale);
   }
 }
 
 
 
 //********************************************************************
 void Measurement1D::ScaleCovar(double scale) {
 //********************************************************************
   (*fFullCovar) *= scale;
   (*covar) *= 1.0 / scale;
   (*fDecomp) *= sqrt(scale);
 }
 
 
 //********************************************************************
 void Measurement1D::SetBinMask(std::string maskfile) {
 //********************************************************************
 
   if (!fIsMask) return;
   LOG(SAM) << "Reading bin mask from file: " << maskfile << std::endl;
 
   // Create a mask histogram with dim of data
   int nbins = fDataHist->GetNbinsX();
   fMaskHist =
     new TH1I((fSettings.GetName() + "_BINMASK").c_str(),
              (fSettings.GetName() + "_BINMASK; Bin; Mask?").c_str(), nbins, 0, nbins);
   std::string line;
   std::ifstream mask(maskfile.c_str(), std::ifstream::in);
 
   if (!mask.is_open()) {
     LOG(FTL) << " Cannot find mask file." << std::endl;
     throw;
   }
 
   while (std::getline(mask >> std::ws, line, '\n')) {
     std::vector<int> entries = GeneralUtils::ParseToInt(line, " ");
 
     // Skip lines with poorly formatted lines
     if (entries.size() < 2) {
       LOG(WRN) << "Measurement1D::SetBinMask(), couldn't parse line: " << line
                << std::endl;
       continue;
     }
 
     // The first index should be the bin number, the second should be the mask
     // value.
     int val = 0;
     if (entries[1] > 0) val = 1;
     fMaskHist->SetBinContent(entries[0], val);
   }
 
   // Apply masking by setting masked data bins to zero
   PlotUtils::MaskBins(fDataHist, fMaskHist);
 
   return;
 }
 
 
 
 //********************************************************************
 void Measurement1D::FinaliseMeasurement() {
 //********************************************************************
 
   LOG(SAM) << "Finalising Measurement: " << fName << std::endl;
 
   if (fSettings.GetB("onlymc")){
     if (fDataHist) delete fDataHist;
     fDataHist = new TH1D("empty_data","empty_data",1,0.0,1.0);
   }
 
   // Make sure data is setup
   if (!fDataHist) {
     ERR(FTL) << "No data has been setup inside " << fName << " constructor!" << std::endl;
     throw;
   }
 
   // Make sure covariances are setup
   if (!fFullCovar) {
     fIsDiag = true;
     SetCovarFromDiagonal(fDataHist);
   }
 
   if (!covar) {
     covar = StatUtils::GetInvert(fFullCovar);
   }
 
   if (!fDecomp) {
     fDecomp = StatUtils::GetDecomp(fFullCovar);
   }
 
   // Push the diagonals of fFullCovar onto the data histogram
   // Comment this out until the covariance/data scaling is consistent!
   StatUtils::SetDataErrorFromCov(fDataHist, fFullCovar, 1E-38);
 
   // If shape only, set covar and fDecomp using the shape-only matrix (if set)
   if (fIsShape && fShapeCovar and FitPar::Config().GetParB("UseShapeCovar")){
     if (covar) delete covar;
     covar = StatUtils::GetInvert(fShapeCovar);
     if (fDecomp) delete fDecomp;
     fDecomp = StatUtils::GetDecomp(fFullCovar);
   }
 
   // Setup fMCHist from data
   fMCHist = (TH1D*)fDataHist->Clone();
   fMCHist->SetNameTitle((fSettings.GetName() + "_MC").c_str(),
                         (fSettings.GetFullTitles()).c_str());
   fMCHist->Reset();
 
   // Setup fMCFine
   fMCFine = new TH1D("mcfine", "mcfine", fDataHist->GetNbinsX() * 8,
                      fMCHist->GetBinLowEdge(1),
                      fMCHist->GetBinLowEdge(fDataHist->GetNbinsX() + 1));
   fMCFine->SetNameTitle((fSettings.GetName() + "_MC_FINE").c_str(),
                         (fSettings.GetFullTitles()).c_str());
   fMCFine->Reset();
 
   // Setup MC Stat
   fMCStat = (TH1D*)fMCHist->Clone();
   fMCStat->Reset();
 
   // Search drawopts for possible types to include by default
   std::string drawopts = FitPar::Config().GetParS("drawopts");
   if (drawopts.find("MODES") != std::string::npos) {
     fMCHist_Modes = new TrueModeStack( (fSettings.GetName() + "_MODES").c_str(),
                                        ("True Channels"), fMCHist);
     SetAutoProcessTH1(fMCHist_Modes, kCMD_Reset, kCMD_Norm, kCMD_Write);
   }
 
   // Setup bin masks using sample name
   if (fIsMask) {
 
     std::string curname  = fName;
     std::string origname = fSettings.GetS("originalname");
 
     // Check rename.mask
     std::string maskloc = FitPar::Config().GetParDIR(curname + ".mask");
 
     // Check origname.mask
     if (maskloc.empty()) maskloc = FitPar::Config().GetParDIR(origname + ".mask");
 
     // Check database
     if (maskloc.empty()) {
       maskloc = FitPar::GetDataBase() + "/masks/" + origname + ".mask";
     }
 
     // Setup Bin Mask
     SetBinMask(maskloc);
   }
 
   if (fScaleFactor < 0) {
     ERR(FTL) << "I found a negative fScaleFactor in " << __FILE__ << ":" << __LINE__ << std::endl;
     ERR(FTL) << "fScaleFactor = " << fScaleFactor << std::endl;
     ERR(FTL) << "EXITING" << std::endl;
     throw;
   }
 
   // Create and fill Weighted Histogram
   if (!fMCWeighted) {
 
     fMCWeighted = (TH1D*)fMCHist->Clone();
     fMCWeighted->SetNameTitle((fName + "_MCWGHTS").c_str(),
                               (fName + "_MCWGHTS" + fPlotTitles).c_str());
     fMCWeighted->GetYaxis()->SetTitle("Weighted Events");
 
   }
 
 
 }
 
 //********************************************************************
 void Measurement1D::SetFitOptions(std::string opt) {
 //********************************************************************
 
   // Do nothing if default given
   if (opt == "DEFAULT") return;
 
   // CHECK Conflicting Fit Options
   std::vector<std::string> fit_option_allow =
     GeneralUtils::ParseToStr(fAllowedTypes, "/");
 
   for (UInt_t i = 0; i < fit_option_allow.size(); i++) {
     std::vector<std::string> fit_option_section =
       GeneralUtils::ParseToStr(fit_option_allow.at(i), ",");
 
     bool found_option = false;
 
     for (UInt_t j = 0; j < fit_option_section.size(); j++) {
       std::string av_opt = fit_option_section.at(j);
 
       if (!found_option and opt.find(av_opt) != std::string::npos) {
         found_option = true;
 
       } else if (found_option and opt.find(av_opt) != std::string::npos) {
         ERR(FTL) << "ERROR: Conflicting fit options provided: "
                  << opt << std::endl
                  << "Conflicting group = " << fit_option_section.at(i) << std::endl
                  << "You should only supply one of these options in card file." << std::endl;
         throw;
       }
     }
   }
 
   // Check all options are allowed
   std::vector<std::string> fit_options_input =
     GeneralUtils::ParseToStr(opt, "/");
   for (UInt_t i = 0; i < fit_options_input.size(); i++) {
     if (fAllowedTypes.find(fit_options_input.at(i)) == std::string::npos) {
       ERR(FTL) << "ERROR: Fit Option '" << fit_options_input.at(i)
                << "' Provided is not allowed for this measurement."
                << std::endl;
       ERR(FTL) << "Fit Options should be provided as a '/' seperated list "
                "(e.g. FREE/DIAG/NORM)"
                << std::endl;
       ERR(FTL) << "Available options for " << fName << " are '" << fAllowedTypes
                << "'" << std::endl;
 
       throw;
     }
   }
 
   // Set TYPE
   fFitType = opt;
 
   // FIX,SHAPE,FREE
   if (opt.find("FIX") != std::string::npos) {
     fIsFree = fIsShape = false;
     fIsFix = true;
   } else if (opt.find("SHAPE") != std::string::npos) {
     fIsFree = fIsFix = false;
     fIsShape = true;
   } else if (opt.find("FREE") != std::string::npos) {
     fIsFix = fIsShape = false;
     fIsFree = true;
   }
 
   // DIAG,FULL (or default to full)
   if (opt.find("DIAG") != std::string::npos) {
     fIsDiag = true;
     fIsFull = false;
   } else if (opt.find("FULL") != std::string::npos) {
     fIsDiag = false;
     fIsFull = true;
   }
 
   // CHI2/LL (OTHERS?)
   if (opt.find("LOG") != std::string::npos) {
     fIsChi2 = false;
 
     ERR(FTL) << "No other LIKELIHOODS properly supported!" << std::endl;
     ERR(FTL) << "Try to use a chi2!" << std::endl;
     throw;
 
   } else {
     fIsChi2 = true;
   }
 
   // EXTRAS
   if (opt.find("RAW") != std::string::npos) fIsRawEvents = true;
   if (opt.find("NOWIDTH") != std::string::npos) fIsNoWidth = true;
   if (opt.find("DIF") != std::string::npos) fIsDifXSec = true;
   if (opt.find("ENU1D") != std::string::npos) fIsEnu1D = true;
   if (opt.find("NORM") != std::string::npos) fAddNormPen = true;
   if (opt.find("MASK") != std::string::npos) fIsMask = true;
 
   return;
 };
 
 
 //********************************************************************
 void Measurement1D::SetSmearingMatrix(std::string smearfile, int truedim,
                                       int recodim) {
   //********************************************************************
 
   // The smearing matrix describes the migration from true bins (rows) to reco
   // bins (columns)
   // Counter over the true bins!
   int row = 0;
 
   std::string line;
   std::ifstream smear(smearfile.c_str(), std::ifstream::in);
 
   // Note that the smearing matrix may be rectangular.
   fSmearMatrix = new TMatrixD(truedim, recodim);
 
   if (smear.is_open())
     LOG(SAM) << "Reading smearing matrix from file: " << smearfile << std::endl;
   else
     ERR(FTL) << "Smearing matrix provided is incorrect: " << smearfile
              << std::endl;
 
   while (std::getline(smear >> std::ws, line, '\n')) {
     int column = 0;
 
     std::vector<double> entries = GeneralUtils::ParseToDbl(line, " ");
     for (std::vector<double>::iterator iter = entries.begin();
          iter != entries.end(); iter++) {
       (*fSmearMatrix)(row, column) =
         (*iter) / 100.;  // Convert to fraction from
       // percentage (this may not be
       // general enough)
       column++;
     }
     row++;
   }
   return;
 }
 
 //********************************************************************
 void Measurement1D::ApplySmearingMatrix() {
 //********************************************************************
 
   if (!fSmearMatrix) {
     ERR(WRN) << fName
              << ": attempted to apply smearing matrix, but none was set"
              << std::endl;
     return;
   }
 
   TH1D* unsmeared = (TH1D*)fMCHist->Clone();
   TH1D* smeared = (TH1D*)fMCHist->Clone();
   smeared->Reset();
 
   // Loop over reconstructed bins
   // true = row; reco = column
   for (int rbin = 0; rbin < fSmearMatrix->GetNcols(); ++rbin) {
     // Sum up the constributions from all true bins
     double rBinVal = 0;
 
     // Loop over true bins
     for (int tbin = 0; tbin < fSmearMatrix->GetNrows(); ++tbin) {
       rBinVal +=
         (*fSmearMatrix)(tbin, rbin) * unsmeared->GetBinContent(tbin + 1);
     }
     smeared->SetBinContent(rbin + 1, rBinVal);
   }
   fMCHist = (TH1D*)smeared->Clone();
 
   return;
 }
 
 /*
    Reconfigure LOOP
 */
 //********************************************************************
 void Measurement1D::ResetAll() {
 //********************************************************************
 
   fMCHist->Reset();
   fMCFine->Reset();
   fMCStat->Reset();
 
   return;
 };
 
 //********************************************************************
 void Measurement1D::FillHistograms() {
   //********************************************************************
 
   if (Signal) {
 
     QLOG(DEB, "Fill MCHist: " << fXVar << ", " << Weight);
 
     fMCHist->Fill(fXVar, Weight);
     fMCFine->Fill(fXVar, Weight);
     fMCStat->Fill(fXVar, 1.0);
 
     if (fMCHist_Modes) fMCHist_Modes->Fill(Mode, fXVar, Weight);
   }
 
   return;
 };
 
 //********************************************************************
 void Measurement1D::ScaleEvents() {
 //********************************************************************
 
   // Fill MCWeighted;
   // for (int i = 0; i < fMCHist->GetNbinsX(); i++) {
   //   fMCWeighted->SetBinContent(i + 1, fMCHist->GetBinContent(i + 1));
   //   fMCWeighted->SetBinError(i + 1,   fMCHist->GetBinError(i + 1));
   // }
 
 
   // Setup Stat ratios for MC and MC Fine
   double* statratio     = new double[fMCHist->GetNbinsX()];
   for (int i = 0; i < fMCHist->GetNbinsX(); i++) {
     if (fMCHist->GetBinContent(i + 1) != 0) {
       statratio[i] = fMCHist->GetBinError(i + 1) / fMCHist->GetBinContent(i + 1);
     } else {
       statratio[i] = 0.0;
     }
   }
 
   double* statratiofine = new double[fMCFine->GetNbinsX()];
   for (int i = 0; i < fMCFine->GetNbinsX(); i++) {
     if (fMCFine->GetBinContent(i + 1) != 0) {
       statratiofine[i] = fMCFine->GetBinError(i + 1) / fMCFine->GetBinContent(i + 1);
     } else {
       statratiofine[i] = 0.0;
     }
   }
 
 
   // Scaling for raw event rates
   if (fIsRawEvents) {
     double datamcratio = fDataHist->Integral() / fMCHist->Integral();
 
     fMCHist->Scale(datamcratio);
     fMCFine->Scale(datamcratio);
 
     if (fMCHist_Modes) fMCHist_Modes->Scale(datamcratio);
 
     // Scaling for XSec as function of Enu
   } else if (fIsEnu1D) {
 
     PlotUtils::FluxUnfoldedScaling(fMCHist, GetFluxHistogram(),
                                    GetEventHistogram(), fScaleFactor,
                                    fNEvents);
     PlotUtils::FluxUnfoldedScaling(fMCFine, GetFluxHistogram(),
                                    GetEventHistogram(), fScaleFactor,
                                    fNEvents);
 
 
     // if (fMCHist_Modes) {
     // PlotUtils::FluxUnfoldedScaling(fMCHist_Modes, GetFluxHistogram(),
     // GetEventHistogram(), fScaleFactor,
     // fNEvents);
     // }
 
   } else if (fIsNoWidth) {
     fMCHist->Scale(fScaleFactor);
     fMCFine->Scale(fScaleFactor);
     if (fMCHist_Modes) fMCHist_Modes->Scale(fScaleFactor);
     // Any other differential scaling
   } else {
     fMCHist->Scale(fScaleFactor, "width");
     fMCFine->Scale(fScaleFactor, "width");
 
     if (fMCHist_Modes) fMCHist_Modes->Scale(fScaleFactor, "width");
   }
 
 
   // Proper error scaling - ROOT Freaks out with xsec weights sometimes
   for (int i = 0; i < fMCStat->GetNbinsX(); i++) {
     fMCHist->SetBinError(i + 1, fMCHist->GetBinContent(i + 1) * statratio[i]);
   }
 
   for (int i = 0; i < fMCFine->GetNbinsX(); i++) {
     fMCFine->SetBinError(i + 1, fMCFine->GetBinContent(i + 1) * statratiofine[i]);
   }
 
 
   // Clean up
   delete statratio;
   delete statratiofine;
 
   return;
 };
 
 //********************************************************************
 void Measurement1D::ApplyNormScale(double norm) {
 //********************************************************************
 
   fCurrentNorm = norm;
 
   fMCHist->Scale(1.0 / norm);
   fMCFine->Scale(1.0 / norm);
 
   return;
 };
 
 
 
 /*
    Statistic Functions - Outsources to StatUtils
 */
 
 //********************************************************************
 int Measurement1D::GetNDOF() {
   //********************************************************************
   int ndof = fDataHist->GetNbinsX();
   if (fMaskHist and fIsMask) ndof -= fMaskHist->Integral();
   return ndof;
 }
 
 //********************************************************************
 double Measurement1D::GetLikelihood() {
 //********************************************************************
 
   // If this is for a ratio, there is no data histogram to compare to!
   if (fNoData || !fDataHist) return 0.;
 
   // Apply Masking to MC if Required.
   if (fIsMask and fMaskHist) {
     PlotUtils::MaskBins(fMCHist, fMaskHist);
   }
 
 
   // Sort Shape Scaling
   double scaleF = 0.0;
   // TODO Include !fIsRawEvents
   if (fIsShape) {
     if (fMCHist->Integral(1, fMCHist->GetNbinsX(), "width")) {
       scaleF = fDataHist->Integral(1, fDataHist->GetNbinsX(), "width") /
       	fMCHist->Integral(1, fMCHist->GetNbinsX(), "width");
       fMCHist->Scale(scaleF);
       fMCFine->Scale(scaleF);
     }
   }
 
 
   // Likelihood Calculation
   double stat = 0.;
   if (fIsChi2) {
 
     if (fIsRawEvents) {
       stat = StatUtils::GetChi2FromEventRate(fDataHist, fMCHist, fMaskHist);
     } else if (fIsDiag) {
       stat = StatUtils::GetChi2FromDiag(fDataHist, fMCHist, fMaskHist);
     } else if (!fIsDiag and !fIsRawEvents) {
       stat = StatUtils::GetChi2FromCov(fDataHist, fMCHist, covar, fMaskHist);
     }
 
   }
 
   // Sort Penalty Terms
   if (fAddNormPen) {
     double penalty =
       (1. - fCurrentNorm) * (1. - fCurrentNorm) / (fNormError * fNormError);
 
     stat += penalty;
   }
 
   // Return to normal scaling
   if (fIsShape) { // and !FitPar::Config().GetParB("saveshapescaling")) {
     fMCHist->Scale(1. / scaleF);
     fMCFine->Scale(1. / scaleF);
   }
 
   fLikelihood = stat;
 
   return stat;
 }
 
 
 /*
   Fake Data Functions
 */
 //********************************************************************
 void Measurement1D::SetFakeDataValues(std::string fakeOption) {
 //********************************************************************
 
   // Setup original/datatrue
   TH1D* tempdata = (TH1D*) fDataHist->Clone();
 
   if (!fIsFakeData) {
     fIsFakeData = true;
 
     // Make a copy of the original data histogram.
     if (!fDataOrig) fDataOrig = (TH1D*)fDataHist->Clone((fName + "_data_original").c_str());
 
   } else {
     ResetFakeData();
 
   }
 
   // Setup Inputs
   fFakeDataInput = fakeOption;
   LOG(SAM) << "Setting fake data from : " << fFakeDataInput << std::endl;
 
   // From MC
   if (fFakeDataInput.compare("MC") == 0) {
     fDataHist = (TH1D*)fMCHist->Clone((fName + "_MC").c_str());
 
     // Fake File
   } else {
     if (!fFakeDataFile) fFakeDataFile = new TFile(fFakeDataInput.c_str(), "READ");
     fDataHist = (TH1D*)fFakeDataFile->Get((fName + "_MC").c_str());
 
   }
 
   // Setup Data Hist
   fDataHist->SetNameTitle((fName + "_FAKE").c_str(),
                           (fName + fPlotTitles).c_str());
 
   // Replace Data True
   if (fDataTrue) delete fDataTrue;
   fDataTrue = (TH1D*)fDataHist->Clone();
   fDataTrue->SetNameTitle((fName + "_FAKE_TRUE").c_str(),
                           (fName + fPlotTitles).c_str());
 
 
   // Make a new covariance for fake data hist.
   int nbins = fDataHist->GetNbinsX();
   double alpha_i = 0.0;
   double alpha_j = 0.0;
 
   for (int i = 0; i < nbins; i++) {
     for (int j = 0; j < nbins; j++) {
       alpha_i = fDataHist->GetBinContent(i + 1) / tempdata->GetBinContent(i + 1);
       alpha_j = fDataHist->GetBinContent(j + 1) / tempdata->GetBinContent(j + 1);
 
       (*fFullCovar)(i, j) = alpha_i * alpha_j * (*fFullCovar)(i, j);
     }
   }
 
   // Setup Covariances
   if (covar) delete covar;
   covar   = StatUtils::GetInvert(fFullCovar);
 
   if (fDecomp) delete fDecomp;
   fDecomp = StatUtils::GetInvert(fFullCovar);
 
   delete tempdata;
 
   return;
 };
 
 //********************************************************************
 void Measurement1D::ResetFakeData() {
 //********************************************************************
 
   if (fIsFakeData) {
     if (fDataHist) delete fDataHist;
     fDataHist = (TH1D*)fDataTrue->Clone((fSettings.GetName() + "_FKDAT").c_str());
   }
 
 }
 
 //********************************************************************
 void Measurement1D::ResetData() {
 //********************************************************************
 
   if (fIsFakeData) {
     if (fDataHist) delete fDataHist;
     fDataHist = (TH1D*)fDataOrig->Clone((fSettings.GetName() + "_data").c_str());
   }
 
   fIsFakeData = false;
 }
 
 //********************************************************************
 void Measurement1D::ThrowCovariance() {
 //********************************************************************
 
   // Take a fDecomposition and use it to throw the current dataset.
   // Requires fDataTrue also be set incase used repeatedly.
 
   if (!fDataTrue) fDataTrue = (TH1D*) fDataHist->Clone();
   if (fDataHist) delete fDataHist;
   fDataHist = StatUtils::ThrowHistogram(fDataTrue, fFullCovar);
 
   return;
 };
 
 
 //********************************************************************
 void Measurement1D::ThrowDataToy(){
 //********************************************************************
   if (!fDataTrue) fDataTrue = (TH1D*) fDataHist->Clone();
   if (fMCHist) delete fMCHist;
   fMCHist = StatUtils::ThrowHistogram(fDataTrue, fFullCovar);
 }
 
 /*
    Access Functions
 */
 
 //********************************************************************
 TH1D* Measurement1D::GetMCHistogram() {
 //********************************************************************
 
   if (!fMCHist) return fMCHist;
 
   std::ostringstream chi2;
   chi2 << std::setprecision(5) << this->GetLikelihood();
 
   int linecolor = kRed;
   int linestyle = 1;
   int linewidth = 1;
 
   int fillcolor = 0;
   int fillstyle = 1001;
 
   // if (fSettings.Has("linecolor")) linecolor = fSettings.GetI("linecolor");
   // if (fSettings.Has("linestyle")) linestyle = fSettings.GetI("linestyle");
   // if (fSettings.Has("linewidth")) linewidth = fSettings.GetI("linewidth");
 
   // if (fSettings.Has("fillcolor")) fillcolor = fSettings.GetI("fillcolor");
   // if (fSettings.Has("fillstyle")) fillstyle = fSettings.GetI("fillstyle");
 
   fMCHist->SetTitle(chi2.str().c_str());
 
   fMCHist->SetLineColor(linecolor);
   fMCHist->SetLineStyle(linestyle);
   fMCHist->SetLineWidth(linewidth);
 
   fMCHist->SetFillColor(fillcolor);
   fMCHist->SetFillStyle(fillstyle);
 
   return fMCHist;
 };
 
 //********************************************************************
 TH1D* Measurement1D::GetDataHistogram() {
 //********************************************************************
 
   if (!fDataHist) return fDataHist;
 
   int datacolor = kBlack;
   int datastyle = 1;
   int datawidth = 1;
 
   // if (fSettings.Has("datacolor")) datacolor = fSettings.GetI("datacolor");
   // if (fSettings.Has("datastyle")) datastyle = fSettings.GetI("datastyle");
   // if (fSettings.Has("datawidth")) datawidth = fSettings.GetI("datawidth");
 
   fDataHist->SetLineColor(datacolor);
   fDataHist->SetLineWidth(datawidth);
   fDataHist->SetMarkerStyle(datastyle);
 
   return fDataHist;
 };
 
 
 /*
    Write Functions
 */
 
 // Save all the histograms at once
 //********************************************************************
 void Measurement1D::Write(std::string drawOpt) {
 //********************************************************************
 
   // Get Draw Options
   drawOpt = FitPar::Config().GetParS("drawopts");
 
   // Write Settigns
   if (drawOpt.find("SETTINGS") != std::string::npos){
     fSettings.Set("#chi^{2}",fLikelihood);
     fSettings.Set("NDOF", this->GetNDOF() );
     fSettings.Set("#chi^{2}/NDOF", fLikelihood / this->GetNDOF() );
     fSettings.Write();
   }
 
   // Write Data/MC
   GetDataList().at(0)->Write();
   GetMCList().at(0)->Write();
 
   if((fEvtRateScaleFactor != 0xdeadbeef) && GetMCList().at(0)){
     TH1D * PredictedEvtRate = static_cast<TH1D *>(GetMCList().at(0)->Clone());
     PredictedEvtRate->Scale(fEvtRateScaleFactor);
     PredictedEvtRate->GetYaxis()->SetTitle("Predicted event rate");
     PredictedEvtRate->Write();
   }
 
 
   // Write Fine Histogram
   if (drawOpt.find("FINE") != std::string::npos)
     GetFineList().at(0)->Write();
 
   // Write Weighted Histogram
   if (drawOpt.find("WEIGHTS") != std::string::npos && fMCWeighted)
     fMCWeighted->Write();
 
 
   // Save Flux/Evt if no event manager
   if (!FitPar::Config().GetParB("EventManager")) {
 
     if (drawOpt.find("FLUX") != std::string::npos && GetFluxHistogram())
       GetFluxHistogram()->Write();
 
     if (drawOpt.find("EVT") != std::string::npos && GetEventHistogram())
       GetEventHistogram()->Write();
 
     if (drawOpt.find("XSEC") != std::string::npos && GetEventHistogram())
       GetXSecHistogram()->Write();
 
   }
 
   // Write Mask
   if (fIsMask && (drawOpt.find("MASK") != std::string::npos)) {
     fMaskHist->Write();
   }
 
 
   // Write Covariances
   if (drawOpt.find("COV") != std::string::npos && fFullCovar) {
     PlotUtils::GetFullCovarPlot(fFullCovar, fSettings.GetName());
   }
 
   if (drawOpt.find("INVCOV") != std::string::npos && covar) {
     PlotUtils::GetInvCovarPlot(covar, fSettings.GetName());
   }
 
   if (drawOpt.find("DECOMP") != std::string::npos && fDecomp) {
     PlotUtils::GetDecompCovarPlot(fDecomp, fSettings.GetName());
   }
 
   // // Likelihood residual plots
   // if (drawOpt.find("RESIDUAL") != std::string::npos) {
   //   WriteResidualPlots();
   // }
 
   // Ratio and Shape Plots
   if (drawOpt.find("RATIO") != std::string::npos) {
     WriteRatioPlot();
   }
 
   if (drawOpt.find("SHAPE") != std::string::npos) {
     WriteShapePlot();
     if (drawOpt.find("RATIO") != std::string::npos)
       WriteShapeRatioPlot();
   }
 
   // // RATIO
   // if (drawOpt.find("CANVMC") != std::string::npos) {
   //   TCanvas* c1 = WriteMCCanvas(fDataHist, fMCHist);
   //   c1->Write();
   //   delete c1;
   // }
 
   // // PDG
   // if (drawOpt.find("CANVPDG") != std::string::npos && fMCHist_Modes) {
   //   TCanvas* c2 = WritePDGCanvas(fDataHist, fMCHist, fMCHist_Modes);
   //   c2->Write();
   //   delete c2;
   // }
 
   // Write Extra Histograms
   AutoWriteExtraTH1();
   WriteExtraHistograms();
 
   // Returning
   LOG(SAM) << "Written Histograms: " << fName << std::endl;
   return;
 }
 
 //********************************************************************
 void Measurement1D::WriteRatioPlot() {
 //********************************************************************
 
   // Setup mc data ratios
   TH1D* dataRatio = (TH1D*)fDataHist->Clone((fName + "_data_RATIO").c_str());
   TH1D* mcRatio   = (TH1D*)fMCHist->Clone((fName + "_MC_RATIO").c_str());
 
   // Extra MC Data Ratios
   for (int i = 0; i < mcRatio->GetNbinsX(); i++) {
 
     dataRatio->SetBinContent(i + 1, fDataHist->GetBinContent(i + 1) / fMCHist->GetBinContent(i + 1));
     dataRatio->SetBinError(i + 1,   fDataHist->GetBinError(i + 1)   / fMCHist->GetBinContent(i + 1));
 
     mcRatio->SetBinContent(i + 1, fMCHist->GetBinContent(i + 1) / fMCHist->GetBinContent(i + 1));
     mcRatio->SetBinError(i + 1,   fMCHist->GetBinError(i + 1)   / fMCHist->GetBinContent(i + 1));
 
   }
 
   // Write ratios
   mcRatio->Write();
   dataRatio->Write();
 
   delete mcRatio;
   delete dataRatio;
 }
 
 
 //********************************************************************
 void Measurement1D::WriteShapePlot() {
 //********************************************************************
 
   TH1D* mcShape = (TH1D*)fMCHist->Clone((fName + "_MC_SHAPE").c_str());
 
   TH1D* dataShape = (TH1D*)fDataHist->Clone((fName + "_data_SHAPE").c_str());
   if (fShapeCovar) StatUtils::SetDataErrorFromCov(dataShape, fShapeCovar, 1E-38);
 
   double shapeScale = 1.0;
   if (fIsRawEvents) {
     shapeScale = fDataHist->Integral() / fMCHist->Integral();
   } else {
     shapeScale = fDataHist->Integral("width") / fMCHist->Integral("width");
   }
 
   mcShape->Scale(shapeScale);
 
   std::stringstream ss;
   ss << shapeScale;
   mcShape->SetTitle(ss.str().c_str());
 
   mcShape->SetLineWidth(3);
   mcShape->SetLineStyle(7);
 
   mcShape->Write();
   dataShape->Write();
 
   delete mcShape;
 
 }
 
 //********************************************************************
 void Measurement1D::WriteShapeRatioPlot() {
 //********************************************************************
 
   // Get a mcshape histogram
   TH1D* mcShape = (TH1D*)fMCHist->Clone((fName + "_MC_SHAPE").c_str());
 
   double shapeScale = 1.0;
   if (fIsRawEvents) {
     shapeScale = fDataHist->Integral() / fMCHist->Integral();
   } else {
     shapeScale = fDataHist->Integral("width") / fMCHist->Integral("width");
   }
 
   mcShape->Scale(shapeScale);
 
   // Create shape ratio histograms
   TH1D* mcShapeRatio   = (TH1D*)mcShape->Clone((fName + "_MC_SHAPE_RATIO").c_str());
   TH1D* dataShapeRatio = (TH1D*)fDataHist->Clone((fName + "_data_SHAPE_RATIO").c_str());
 
   // Divide the histograms
   mcShapeRatio->Divide(mcShape);
   dataShapeRatio->Divide(mcShape);
 
   // Colour the shape ratio plots
   mcShapeRatio->SetLineWidth(3);
   mcShapeRatio->SetLineStyle(7);
 
   mcShapeRatio->Write();
   dataShapeRatio->Write();
 
   delete mcShapeRatio;
   delete dataShapeRatio;
 
 }
 
 
 
 
 //// CRAP TO BE REMOVED
 
 
 //********************************************************************
 void Measurement1D::SetupMeasurement(std::string inputfile, std::string type,
                                      FitWeight * rw, std::string fkdt) {
   //********************************************************************
 
 
   nuiskey samplekey = Config::CreateKey("sample");
   samplekey.Set("name", fName);
   samplekey.Set("type",type);
   samplekey.Set("input",inputfile);
   fSettings = LoadSampleSettings(samplekey);
 
   // Reset everything to NULL
   // Init();
 
   // Check if name contains Evt, indicating that it is a raw number of events
   // measurements and should thus be treated as once
   fIsRawEvents = false;
   if ((fName.find("Evt") != std::string::npos) && fIsRawEvents == false) {
     fIsRawEvents = true;
     LOG(SAM) << "Found event rate measurement but fIsRawEvents == false!"
              << std::endl;
     LOG(SAM) << "Overriding this and setting fIsRawEvents == true!"
              << std::endl;
   }
 
   fIsEnu1D = false;
   if (fName.find("XSec_1DEnu") != std::string::npos) {
     fIsEnu1D = true;
     LOG(SAM) << "::" << fName << "::" << std::endl;
     LOG(SAM) << "Found XSec Enu measurement, applying flux integrated scaling, "
              "not flux averaged!"
              << std::endl;
   }
 
   if (fIsEnu1D && fIsRawEvents) {
     LOG(SAM) << "Found 1D Enu XSec distribution AND fIsRawEvents, is this "
              "really correct?!"
              << std::endl;
     LOG(SAM) << "Check experiment constructor for " << fName
              << " and correct this!" << std::endl;
     LOG(SAM) << "I live in " << __FILE__ << ":" << __LINE__ << std::endl;
     exit(-1);
   }
 
   fRW = rw;
 
   if (!fInput and !fIsJoint) SetupInputs(inputfile);
 
   // Set Default Options
   SetFitOptions(fDefaultTypes);
 
   // Set Passed Options
   SetFitOptions(type);
 
   // Still adding support for flat flux inputs
   //  // Set Enu Flux Scaling
   //  if (isFlatFluxFolding) this->Input()->ApplyFluxFolding(
   //  this->defaultFluxHist );
 
   // FinaliseMeasurement();
 }
 
 //********************************************************************
 void Measurement1D::SetupDefaultHist() {
   //********************************************************************
 
   // Setup fMCHist
   fMCHist = (TH1D*)fDataHist->Clone();
   fMCHist->SetNameTitle((fName + "_MC").c_str(),
                         (fName + "_MC" + fPlotTitles).c_str());
 
   // Setup fMCFine
   Int_t nBins = fMCHist->GetNbinsX();
   fMCFine = new TH1D(
     (fName + "_MC_FINE").c_str(), (fName + "_MC_FINE" + fPlotTitles).c_str(),
     nBins * 6, fMCHist->GetBinLowEdge(1), fMCHist->GetBinLowEdge(nBins + 1));
 
   fMCStat = (TH1D*)fMCHist->Clone();
   fMCStat->Reset();
 
   fMCHist->Reset();
   fMCFine->Reset();
 
   // Setup the NEUT Mode Array
   PlotUtils::CreateNeutModeArray((TH1D*)fMCHist, (TH1**)fMCHist_PDG);
   PlotUtils::ResetNeutModeArray((TH1**)fMCHist_PDG);
 
   // Setup bin masks using sample name
   if (fIsMask) {
     std::string maskloc = FitPar::Config().GetParDIR(fName + ".mask");
     if (maskloc.empty()) {
       maskloc = FitPar::GetDataBase() + "/masks/" + fName + ".mask";
     }
 
     SetBinMask(maskloc);
   }
 
   fMCHist_Modes = new TrueModeStack( (fName + "_MODES").c_str(), ("True Channels"), fMCHist);
   SetAutoProcessTH1(fMCHist_Modes, kCMD_Reset, kCMD_Norm, kCMD_Write);
 
   return;
 }
 
 
 
 
 
 //********************************************************************
 void Measurement1D::SetDataValues(std::string dataFile) {
   //********************************************************************
 
   // Override this function if the input file isn't in a suitable format
   LOG(SAM) << "Reading data from: " << dataFile.c_str() << std::endl;
   fDataHist =
     PlotUtils::GetTH1DFromFile(dataFile, (fName + "_data"), fPlotTitles);
   fDataTrue = (TH1D*)fDataHist->Clone();
 
   // Number of data points is number of bins
   fNDataPointsX = fDataHist->GetXaxis()->GetNbins();
 
   return;
 };
 
 
 
 
 
 //********************************************************************
 void Measurement1D::SetDataFromDatabase(std::string inhistfile,
                                         std::string histname) {
   //********************************************************************
 
   LOG(SAM) << "Filling histogram from " << inhistfile << "->" << histname
            << std::endl;
   fDataHist = PlotUtils::GetTH1DFromRootFile(
                 (GeneralUtils::GetTopLevelDir() + "/data/" + inhistfile), histname);
   fDataHist->SetNameTitle((fName + "_data").c_str(), (fName + "_data").c_str());
 
   return;
 };
 
 //********************************************************************
 void Measurement1D::SetDataFromFile(std::string inhistfile,
                                     std::string histname) {
   //********************************************************************
 
   LOG(SAM) << "Filling histogram from " << inhistfile << "->" << histname
            << std::endl;
   fDataHist = PlotUtils::GetTH1DFromRootFile((inhistfile), histname);
   fDataHist->SetNameTitle((fName + "_data").c_str(), (fName + "_data").c_str());
 
   return;
 };
 
 //********************************************************************
 void Measurement1D::SetCovarMatrix(std::string covarFile) {
   //********************************************************************
 
   // Covariance function, only really used when reading in the MB Covariances.
 
   TFile* tempFile = new TFile(covarFile.c_str(), "READ");
 
   TH2D* covarPlot = new TH2D();
   //  TH2D* decmpPlot = new TH2D();
   TH2D* covarInvPlot = new TH2D();
   TH2D* fFullCovarPlot = new TH2D();
   std::string covName = "";
   std::string covOption = FitPar::Config().GetParS("thrown_covariance");
 
   if (fIsShape || fIsFree) covName = "shp_";
   if (fIsDiag)
     covName += "diag";
   else
     covName += "full";
 
   covarPlot = (TH2D*)tempFile->Get((covName + "cov").c_str());
   covarInvPlot = (TH2D*)tempFile->Get((covName + "covinv").c_str());
 
   if (!covOption.compare("SUB"))
     fFullCovarPlot = (TH2D*)tempFile->Get((covName + "cov").c_str());
   else if (!covOption.compare("FULL"))
     fFullCovarPlot = (TH2D*)tempFile->Get("fullcov");
   else
     ERR(WRN) << "Incorrect thrown_covariance option in parameters."
              << std::endl;
 
   int dim = int(fDataHist->GetNbinsX());  //-this->masked->Integral());
   int covdim = int(fDataHist->GetNbinsX());
 
   this->covar = new TMatrixDSym(dim);
   fFullCovar = new TMatrixDSym(dim);
   fDecomp = new TMatrixDSym(dim);
 
   int row, column = 0;
   row = 0;
   column = 0;
   for (Int_t i = 0; i < covdim; i++) {
     // if (this->masked->GetBinContent(i+1) > 0) continue;
 
     for (Int_t j = 0; j < covdim; j++) {
       //   if (this->masked->GetBinContent(j+1) > 0) continue;
 
       (*this->covar)(row, column) = covarPlot->GetBinContent(i + 1, j + 1);
       (*fFullCovar)(row, column) = fFullCovarPlot->GetBinContent(i + 1, j + 1);
 
       column++;
     }
     column = 0;
     row++;
   }
 
   // Set bin errors on data
   if (!fIsDiag) {
     StatUtils::SetDataErrorFromCov(fDataHist, fFullCovar);
   }
 
   // Get Deteriminant and inverse matrix
   // fCovDet = this->covar->Determinant();
 
   TDecompSVD LU = TDecompSVD(*this->covar);
   this->covar = new TMatrixDSym(dim, LU.Invert().GetMatrixArray(), "");
 
   return;
 };
 
 //********************************************************************
 // Sets the covariance matrix from a provided file in a text format
 // scale is a multiplicative pre-factor to apply in the case where the
 // covariance is given in some unit (e.g. 1E-38)
 void Measurement1D::SetCovarMatrixFromText(std::string covarFile, int dim,
     double scale) {
   //********************************************************************
 
   // Make a counter to track the line number
   int row = 0;
 
   std::string line;
   std::ifstream covarread(covarFile.c_str(), std::ifstream::in);
 
   this->covar = new TMatrixDSym(dim);
   fFullCovar = new TMatrixDSym(dim);
   if (covarread.is_open())
     LOG(SAM) << "Reading covariance matrix from file: " << covarFile
              << std::endl;
   else
     ERR(FTL) << "Covariance matrix provided is incorrect: " << covarFile
              << std::endl;
 
   // Loop over the lines in the file
   while (std::getline(covarread >> std::ws, line, '\n')) {
     int column = 0;
 
     // Loop over entries and insert them into matrix
     std::vector<double> entries = GeneralUtils::ParseToDbl(line, " ");
 
     if (entries.size() <= 1) {
       ERR(WRN) << "SetCovarMatrixFromText -> Covariance matrix only has <= 1 "
                "entries on this line: "
                << row << std::endl;
     }
 
     for (std::vector<double>::iterator iter = entries.begin();
          iter != entries.end(); iter++) {
       (*covar)(row, column) = *iter;
       (*fFullCovar)(row, column) = *iter;
 
       column++;
     }
 
     row++;
   }
   covarread.close();
 
   // Scale the actualy covariance matrix by some multiplicative factor
   (*fFullCovar) *= scale;
 
   // Robust matrix inversion method
   TDecompSVD LU = TDecompSVD(*this->covar);
   // THIS IS ACTUALLY THE INVERSE COVARIANCE MATRIXA AAAAARGH
   delete this->covar;
   this->covar = new TMatrixDSym(dim, LU.Invert().GetMatrixArray(), "");
 
   // Now need to multiply by the scaling factor
   // If the covariance
   (*this->covar) *= 1. / (scale);
 
   return;
 };
 
 //********************************************************************
 void Measurement1D::SetCovarMatrixFromCorrText(std::string corrFile, int dim) {
   //********************************************************************
 
   // Make a counter to track the line number
   int row = 0;
 
   std::string line;
   std::ifstream corr(corrFile.c_str(), std::ifstream::in);
 
   this->covar = new TMatrixDSym(dim);
   this->fFullCovar = new TMatrixDSym(dim);
   if (corr.is_open())
     LOG(SAM) << "Reading and converting correlation matrix from file: "
              << corrFile << std::endl;
   else {
     ERR(FTL) << "Correlation matrix provided is incorrect: " << corrFile
              << std::endl;
     exit(-1);
   }
 
   while (std::getline(corr >> std::ws, line, '\n')) {
     int column = 0;
 
     // Loop over entries and insert them into matrix
     // Multiply by the errors to get the covariance, rather than the correlation
     // matrix
     std::vector<double> entries = GeneralUtils::ParseToDbl(line, " ");
     for (std::vector<double>::iterator iter = entries.begin();
          iter != entries.end(); iter++) {
       double val = (*iter) * this->fDataHist->GetBinError(row + 1) * 1E38 *
                    this->fDataHist->GetBinError(column + 1) * 1E38;
       if (val == 0) {
         ERR(FTL) << "Found a zero value in the covariance matrix, assuming "
                  "this is an error!"
                  << std::endl;
         exit(-1);
       }
 
       (*this->covar)(row, column) = val;
       (*this->fFullCovar)(row, column) = val;
 
       column++;
     }
 
     row++;
   }
 
   // Robust matrix inversion method
   TDecompSVD LU = TDecompSVD(*this->covar);
   delete this->covar;
   this->covar = new TMatrixDSym(dim, LU.Invert().GetMatrixArray(), "");
 
   return;
 };
 
 
 
 
 
 
 //********************************************************************
 // FullUnits refers to if we have "real" unscaled units in the covariance matrix, e.g. 1E-76.
 // If this is the case we need to scale it so that the chi2 contribution is correct
 // NUISANCE internally assumes the covariance matrix has units of 1E76
 void Measurement1D::SetCovarFromDataFile(std::string covarFile,
     std::string covName, bool FullUnits) {
   //********************************************************************
 
   LOG(SAM) << "Getting covariance from " << covarFile << "->" << covName
            << std::endl;
 
   TFile* tempFile = new TFile(covarFile.c_str(), "READ");
   TH2D* covPlot = (TH2D*)tempFile->Get(covName.c_str());
   covPlot->SetDirectory(0);
   // Scale the covariance matrix if it comes in normal units
   if (FullUnits) {
     covPlot->Scale(1.E76);
   }
 
   int dim = covPlot->GetNbinsX();
   fFullCovar = new TMatrixDSym(dim);
 
   for (int i = 0; i < dim; i++) {
     for (int j = 0; j < dim; j++) {
       (*fFullCovar)(i, j) = covPlot->GetBinContent(i + 1, j + 1);
     }
   }
 
   this->covar = (TMatrixDSym*)fFullCovar->Clone();
   fDecomp = (TMatrixDSym*)fFullCovar->Clone();
 
   TDecompSVD LU = TDecompSVD(*this->covar);
   this->covar = new TMatrixDSym(dim, LU.Invert().GetMatrixArray(), "");
 
   TDecompChol LUChol = TDecompChol(*fDecomp);
   LUChol.Decompose();
   fDecomp = new TMatrixDSym(dim, LU.GetU().GetMatrixArray(), "");
 
   return;
 };
 
 // //********************************************************************
 // void Measurement1D::SetBinMask(std::string maskFile) {
 //   //********************************************************************
 
 //   // Create a mask histogram.
 //   int nbins = fDataHist->GetNbinsX();
 //   fMaskHist =
 //     new TH1I((fName + "_fMaskHist").c_str(),
 //              (fName + "_fMaskHist; Bin; Mask?").c_str(), nbins, 0, nbins);
 //   std::string line;
 //   std::ifstream mask(maskFile.c_str(), std::ifstream::in);
 
 //   if (mask.is_open())
 //     LOG(SAM) << "Reading bin mask from file: " << maskFile << std::endl;
 //   else
 //     LOG(FTL) << " Cannot find mask file." << std::endl;
 
 //   while (std::getline(mask >> std::ws, line, '\n')) {
 //     std::vector<int> entries = GeneralUtils::ParseToInt(line, " ");
 
 //     // Skip lines with poorly formatted lines
 //     if (entries.size() < 2) {
 //       LOG(WRN) << "Measurement1D::SetBinMask(), couldn't parse line: " << line
 //                << std::endl;
 //       continue;
 //     }
 
 //     // The first index should be the bin number, the second should be the mask
 //     // value.
 //     fMaskHist->SetBinContent(entries[0], entries[1]);
 //   }
 
 //   // Set masked data bins to zero
 //   PlotUtils::MaskBins(fDataHist, fMaskHist);
 
 //   return;
 // }
 
 // //********************************************************************
 // void Measurement1D::GetBinContents(std::vector<double>& cont,
 //                                    std::vector<double>& err) {
 //   //********************************************************************
 
 //   // Return a vector of the main bin contents
 //   for (int i = 0; i < fMCHist->GetNbinsX(); i++) {
 //     cont.push_back(fMCHist->GetBinContent(i + 1));
 //     err.push_back(fMCHist->GetBinError(i + 1));
 //   }
 
 //   return;
 // };
 
 
 /*
    XSec Functions
    */
 
 // //********************************************************************
 // void Measurement1D::SetFluxHistogram(std::string fluxFile, int minE, int
 // maxE,
 //     double fluxNorm) {
 //   //********************************************************************
 
 //   // Note this expects the flux bins to be given in terms of MeV
 //   LOG(SAM) << "Reading flux from file: " << fluxFile << std::endl;
 
 //   TGraph f(fluxFile.c_str(), "%lg %lg");
 
 //   fFluxHist =
 //     new TH1D((fName + "_flux").c_str(), (fName + "; E_{#nu} (GeV)").c_str(),
 //         f.GetN() - 1, minE, maxE);
 
 //   Double_t* yVal = f.GetY();
 
 //   for (int i = 0; i < fFluxHist->GetNbinsX(); ++i)
 //     fFluxHist->SetBinContent(i + 1, yVal[i] * fluxNorm);
 // };
 
 // //********************************************************************
 // double Measurement1D::TotalIntegratedFlux(std::string intOpt, double low,
 //     double high) {
 //   //********************************************************************
 
 //   if (fInput->GetType() == kGiBUU) {
 //     return 1.0;
 //   }
 
 //   // The default case of low = -9999.9 and high = -9999.9
 //   if (low == -9999.9) low = this->EnuMin;
 //   if (high == -9999.9) high = this->EnuMax;
 
 //   int minBin = fFluxHist->GetXaxis()->FindBin(low);
 //   int maxBin = fFluxHist->GetXaxis()->FindBin(high);
 
 //   // Get integral over custom range
 //   double integral = fFluxHist->Integral(minBin, maxBin + 1, intOpt.c_str());
 
 //   return integral;
 // };
 
diff --git a/src/FitBase/SampleSettings.h b/src/FitBase/SampleSettings.h
index 358a584..086187d 100644
--- a/src/FitBase/SampleSettings.h
+++ b/src/FitBase/SampleSettings.h
@@ -1,77 +1,75 @@
 #ifndef SAMPLESETTINGS_H
 #define SAMPLESETTINGS_H
 #include "NuisConfig.h"
 #include "NuisKey.h"
 #include "TH1D.h"
 #include "BeamUtils.h"
 #include "TPaveText.h"
 #include "TCanvas.h"
 
 class SampleSettings {
 public:
 	SampleSettings();
 	SampleSettings(nuiskey key);
 
 	inline std::string Name(){return GetName();};
 	std::string GetName();
 	void SetS(std::string name, std::string val);
 	void SetXTitle(std::string name);
 	void SetYTitle(std::string name);
 	void SetZTitle(std::string name);
 	void SetNormError(double norm);
 	double GetNormError();
 
 	void SetAllowedTypes(std::string allowed, std::string defaulttype="FIX");
 	void SetEnuRangeFromFlux(TH1D* fluxhist);
 	void SetEnuRange(double min, double max);
 	std::string Title();
 	void DefineAllowedTargets(std::string targ);
 
 	void FoundFill(std::string name, std::string substr, bool& cont, bool def);
 	// void FoundFill(std::string name, std::string substr, double& val, double )
 	bool Found(std::string name, std::string substr);
 	void SetTitle(std::string val);
 	void SetDataInput(std::string val);
 	void SetErrorInput(std::string val);
 	std::string GetErrorInput();
 
 	std::string GetMapInput();
 	void SetMapInput(std::string val);
 	void SetCovarInput(std::string val);
 	void SetShapeCovarInput(std::string val);
 
 	void SetDefault(std::string name, std::string val);
 	void SetDefault(std::string name, double val);
 	void SetHasExtraHistograms(bool opt = true);
 	void DefineAllowedSpecies(std::string species);
 	void SetSuggestedFlux(std::string str);
 	void SetDescription(std::string str);
 
 	void Write(std::string name="");
 
 	std::string GetFullTitles();
 	
 	bool Has(std::string name){return fKeyValues.Has(name);};
 
 	std::string GetDataInput();
 	std::string PlotTitles();
 	std::string GetS(std::string name);
 	int GetI(std::string name);
 	double GetD(std::string name);
 	std::string GetCovarInput();
 	void SetOnlyMC(bool state=true);
 	bool GetB(std::string name);
 
 	void Set(std::string name, int i);
 	void Set(std::string name, std::string s);
 	void Set(std::string name, double d);
 
-	
-
 	std::vector<int> fAllowedTargets;
 	std::vector<int> fAllowedSpecies;
   	nuiskey fKeyValues;
   	bool fHasExtraHistograms;
 };
 
 #endif
diff --git a/src/Statistical/StatUtils.cxx b/src/Statistical/StatUtils.cxx
index e052685..b2745f3 100644
--- a/src/Statistical/StatUtils.cxx
+++ b/src/Statistical/StatUtils.cxx
@@ -1,1304 +1,1328 @@
 // Copyright 2016 L. Pickering, P Stowell, R. Terri, C. Wilkinson, C. Wret
 
 /*******************************************************************************
 *    This file is part of NUISANCE.
 *
 *    NUISANCE is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    NUISANCE is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with NUISANCE.  If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/
 
 #include "StatUtils.h"
 #include "GeneralUtils.h"
 #include "NuisConfig.h"
 #include "TH1D.h"
 
 //*******************************************************************
 Double_t StatUtils::GetChi2FromDiag(TH1D* data, TH1D* mc, TH1I* mask) {
   //*******************************************************************
 
   Double_t Chi2 = 0.0;
   TH1D* calc_data = (TH1D*)data->Clone();
   TH1D* calc_mc = (TH1D*)mc->Clone();
 
   // Add MC Error to data if required
   if (FitPar::Config().GetParB("addmcerror")) {
     for (int i = 0; i < calc_data->GetNbinsX(); i++) {
       double dterr = calc_data->GetBinError(i + 1);
       double mcerr = calc_mc->GetBinError(i + 1);
 
       if (dterr > 0.0) {
         calc_data->SetBinError(i + 1, sqrt(dterr * dterr + mcerr * mcerr));
       }
     }
   }
 
   // Apply masking if required
   if (mask) {
     calc_data = ApplyHistogramMasking(data, mask);
     calc_mc = ApplyHistogramMasking(mc, mask);
   }
 
   // Iterate over bins in X
   for (int i = 0; i < calc_data->GetNbinsX(); i++) {
     // Ignore bins with zero data or zero bin error
     if (calc_data->GetBinError(i + 1) <= 0.0 ||
         calc_data->GetBinContent(i + 1) == 0.0)
       continue;
 
     // Take mc data difference
     double diff =
         calc_data->GetBinContent(i + 1) - calc_mc->GetBinContent(i + 1);
     double err = calc_data->GetBinError(i + 1);
     Chi2 += (diff * diff) / (err * err);
   }
 
   // cleanup
   delete calc_data;
   delete calc_mc;
 
   return Chi2;
 };
 
 //*******************************************************************
 Double_t StatUtils::GetChi2FromDiag(TH2D* data, TH2D* mc, TH2I* map,
                                     TH2I* mask) {
   //*******************************************************************
 
   // Generate a simple map
   if (!map) map = GenerateMap(data);
 
   // Convert to 1D Histograms
   TH1D* data_1D = MapToTH1D(data, map);
   TH1D* mc_1D = MapToTH1D(mc, map);
   TH1I* mask_1D = MapToMask(mask, map);
 
   // Calculate 1D chi2 from 1D Plots
   Double_t Chi2 = StatUtils::GetChi2FromDiag(data_1D, mc_1D, mask_1D);
 
   // CleanUp
   delete data_1D;
   delete mc_1D;
   delete mask_1D;
 
   return Chi2;
 };
 
 //*******************************************************************
 Double_t StatUtils::GetChi2FromCov(TH1D* data, TH1D* mc, TMatrixDSym* invcov,
                                    TH1I* mask, double data_scale,
                                    double covar_scale) {
   //*******************************************************************
 
   Double_t Chi2 = 0.0;
   TMatrixDSym* calc_cov = (TMatrixDSym*)invcov->Clone();
   TH1D* calc_data = (TH1D*)data->Clone();
   TH1D* calc_mc = (TH1D*)mc->Clone();
 
   // If a mask if applied we need to apply it before the matrix is inverted
   if (mask) {
     calc_cov = ApplyInvertedMatrixMasking(invcov, mask);
     calc_data = ApplyHistogramMasking(data, mask);
     calc_mc = ApplyHistogramMasking(mc, mask);
   }
 
   // Add MC Error to data if required
   if (FitPar::Config().GetParB("statutils.addmcerror")) {
     // Make temp cov
     TMatrixDSym* newcov = StatUtils::GetInvert(calc_cov);
 
     // Add MC err to diag
     for (int i = 0; i < calc_data->GetNbinsX(); i++) {
       double mcerr = calc_mc->GetBinError(i + 1) * sqrt(covar_scale);
       double oldval = (*newcov)(i, i);
 
       std::cout << "Adding cov stat " << mcerr * mcerr << " to "
                 << (*newcov)(i, i) << std::endl;
       (*newcov)(i, i) = oldval + mcerr * mcerr;
     }
 
     // Reset the calc_cov to new invert
     delete calc_cov;
     calc_cov = GetInvert(newcov);
 
     // Delete the tempcov
     delete newcov;
   }
 
   calc_data->Scale(data_scale);
   calc_mc->Scale(data_scale);
   (*calc_cov) *= covar_scale;
 
   // iterate over bins in X (i,j)
   QLOG(DEB, "START Chi2 Calculation=================");
   for (int i = 0; i < calc_data->GetNbinsX(); i++) {
     QLOG(DEB,
          "[CHI2] i = " << i << " ["
                        << calc_data->GetXaxis()->GetBinLowEdge(i + 1) << " -- "
                        << calc_data->GetXaxis()->GetBinUpEdge(i + 1) << "].");
     for (int j = 0; j < calc_data->GetNbinsX(); j++) {
       QLOG(DEB, "[CHI2]\t j = "
                     << i << " [" << calc_data->GetXaxis()->GetBinLowEdge(j + 1)
                     << " -- " << calc_data->GetXaxis()->GetBinUpEdge(j + 1)
                     << "].");
       if ((calc_data->GetBinContent(i + 1) != 0 ||
            calc_mc->GetBinContent(i + 1) != 0) &&
           ((*calc_cov)(i, j) != 0)) {
         QLOG(DEB, "[CHI2]\t\t Chi2 contribution (i,j) = (" << i << "," << j
                                                            << ")");
         QLOG(DEB, "[CHI2]\t\t Data - MC(i) = "
                       << calc_data->GetBinContent(i + 1) << " - "
                       << calc_mc->GetBinContent(i + 1) << "  = "
                       << (calc_data->GetBinContent(i + 1) -
                           calc_mc->GetBinContent(i + 1)));
 
         QLOG(DEB, "[CHI2]\t\t Data - MC(j) = "
                       << calc_data->GetBinContent(j + 1) << " - "
                       << calc_mc->GetBinContent(j + 1) << "  = "
                       << (calc_data->GetBinContent(j + 1) -
                           calc_mc->GetBinContent(j + 1)));
 
         QLOG(DEB, "[CHI2]\t\t Covar = " << (*calc_cov)(i, j));
 
         QLOG(DEB, "[CHI2]\t\t Cont chi2 = "
                       << ((calc_data->GetBinContent(i + 1) -
                            calc_mc->GetBinContent(i + 1)) *
                           (*calc_cov)(i, j) * (calc_data->GetBinContent(j + 1) -
                                                calc_mc->GetBinContent(j + 1)))
                       << " " << Chi2);
 
         Chi2 +=
             ((calc_data->GetBinContent(i + 1) - calc_mc->GetBinContent(i + 1)) *
              (*calc_cov)(i, j) *
              (calc_data->GetBinContent(j + 1) - calc_mc->GetBinContent(j + 1)));
 
       } else {
         QLOG(DEB, "Skipping chi2 contribution (i,j) = ("
                       << i << "," << j
                       << "), Data = " << calc_data->GetBinContent(i + 1)
                       << ", MC = " << calc_mc->GetBinContent(i + 1)
                       << ", Cov = " << (*calc_cov)(i, j));
         Chi2 += 0.;
       }
     }
   }
 
   // Cleanup
   delete calc_cov;
   delete calc_data;
   delete calc_mc;
 
   return Chi2;
 }
 
 //*******************************************************************
 Double_t StatUtils::GetChi2FromCov(TH2D* data, TH2D* mc, TMatrixDSym* invcov,
                                    TH2I* map, TH2I* mask) {
   //*******************************************************************
 
   // Generate a simple map
   if (!map) {
     map = StatUtils::GenerateMap(data);
   }
 
   // Convert to 1D Histograms
   TH1D* data_1D = MapToTH1D(data, map);
   TH1D* mc_1D = MapToTH1D(mc, map);
   TH1I* mask_1D = MapToMask(mask, map);
 
   // Calculate 1D chi2 from 1D Plots
   Double_t Chi2 = StatUtils::GetChi2FromCov(data_1D, mc_1D, invcov, mask_1D);
 
   // CleanUp
   delete data_1D;
   delete mc_1D;
   delete mask_1D;
 
   return Chi2;
 }
 
 //*******************************************************************
 Double_t StatUtils::GetChi2FromSVD(TH1D* data, TH1D* mc, TMatrixDSym* cov,
                                    TH1I* mask) {
   //*******************************************************************
 
   Double_t Chi2 = 0.0;
   TMatrixDSym* calc_cov = (TMatrixDSym*)cov->Clone();
   TH1D* calc_data = (TH1D*)data->Clone();
   TH1D* calc_mc = (TH1D*)mc->Clone();
 
   // If a mask if applied we need to apply it before the matrix is inverted
   if (mask) {
     calc_cov = StatUtils::ApplyMatrixMasking(cov, mask);
     calc_data = StatUtils::ApplyHistogramMasking(data, mask);
     calc_mc = StatUtils::ApplyHistogramMasking(mc, mask);
   }
 
   // Decompose matrix
   TDecompSVD LU = TDecompSVD((*calc_cov));
   LU.Decompose();
   TMatrixDSym* cov_U =
       new TMatrixDSym(calc_data->GetNbinsX(), LU.GetU().GetMatrixArray(), "");
   TVectorD* cov_S = new TVectorD(LU.GetSig());
 
   // Apply basis rotation before adding up chi2
   Double_t rotated_difference = 0.0;
 
   for (int i = 0; i < calc_data->GetNbinsX(); i++) {
     rotated_difference = 0.0;
 
     // Rotate basis of Data - MC
     for (int j = 0; j < calc_data->GetNbinsY(); j++)
       rotated_difference +=
           (calc_data->GetBinContent(j + 1) - calc_mc->GetBinContent(j + 1)) *
           (*cov_U)(j, i);
 
     // Divide by rotated error cov_S
     Chi2 += rotated_difference * rotated_difference * 1E76 / (*cov_S)(i);
   }
 
   // Cleanup
   delete calc_cov;
   delete calc_data;
   delete calc_mc;
   delete cov_U;
   delete cov_S;
 
   return Chi2;
 }
 
 //*******************************************************************
 Double_t StatUtils::GetChi2FromSVD(TH2D* data, TH2D* mc, TMatrixDSym* cov,
                                    TH2I* map, TH2I* mask) {
   //*******************************************************************
 
   // Generate a simple map
   if (!map) map = StatUtils::GenerateMap(data);
 
   // Convert to 1D Histograms
   TH1D* data_1D = MapToTH1D(data, map);
   TH1D* mc_1D = MapToTH1D(mc, map);
   TH1I* mask_1D = MapToMask(mask, map);
 
   // Calculate from 1D
   Double_t Chi2 = StatUtils::GetChi2FromSVD(data_1D, mc_1D, cov, mask_1D);
 
   // CleanUp
   delete data_1D;
   delete mc_1D;
   delete mask_1D;
 
   return Chi2;
 }
 
 //*******************************************************************
 double StatUtils::GetChi2FromEventRate(TH1D* data, TH1D* mc, TH1I* mask) {
   //*******************************************************************
 
   // If just an event rate, for chi2 just use Poission Likelihood to calculate
   // the chi2 component
   double chi2 = 0.0;
   TH1D* calc_data = (TH1D*)data->Clone();
   TH1D* calc_mc = (TH1D*)mc->Clone();
 
   // Apply masking if required
   if (mask) {
     calc_data = ApplyHistogramMasking(data, mask);
     calc_mc = ApplyHistogramMasking(mc, mask);
   }
 
   // Iterate over bins in X
   for (int i = 0; i < calc_data->GetNbinsX(); i++) {
     double dt = calc_data->GetBinContent(i + 1);
     double mc = calc_mc->GetBinContent(i + 1);
 
     if (mc <= 0) continue;
 
     if (dt <= 0) {
       // Only add difference
       chi2 += 2 * (mc - dt);
     } else {
       // Do the chi2 for Poisson distributions
       chi2 += 2 * (mc - dt + (dt * log(dt / mc)));
     }
 
     /*
         LOG(REC)<<"Evt Chi2 cont = "<<i<<" "
           <<mc<<" "<<dt<<" "
           <<2 * (mc - dt + (dt+0.) * log((dt+0.) / (mc+0.)))
           <<" "<<Chi2<<std::endl;
     */
   }
 
   // cleanup
   delete calc_data;
   delete calc_mc;
 
   return chi2;
 }
 
 //*******************************************************************
 Double_t StatUtils::GetChi2FromEventRate(TH2D* data, TH2D* mc, TH2I* map,
                                          TH2I* mask) {
   //*******************************************************************
 
   // Generate a simple map
   if (!map) map = StatUtils::GenerateMap(data);
 
   // Convert to 1D Histograms
   TH1D* data_1D = MapToTH1D(data, map);
   TH1D* mc_1D = MapToTH1D(mc, map);
   TH1I* mask_1D = MapToMask(mask, map);
 
   // Calculate from 1D
   Double_t Chi2 = StatUtils::GetChi2FromEventRate(data_1D, mc_1D, mask_1D);
 
   // CleanUp
   delete data_1D;
   delete mc_1D;
   delete mask_1D;
 
   return Chi2;
 }
 
 //*******************************************************************
 Double_t StatUtils::GetLikelihoodFromDiag(TH1D* data, TH1D* mc, TH1I* mask) {
   //*******************************************************************
   // Currently just a placeholder!
   (void)data;
   (void)mc;
   (void)mask;
   return 0.0;
 };
 
 //*******************************************************************
 Double_t StatUtils::GetLikelihoodFromDiag(TH2D* data, TH2D* mc, TH2I* map,
                                           TH2I* mask) {
   //*******************************************************************
 
   // Generate a simple map
   if (!map) map = StatUtils::GenerateMap(data);
 
   // Convert to 1D Histograms
   TH1D* data_1D = MapToTH1D(data, map);
   TH1D* mc_1D = MapToTH1D(mc, map);
   TH1I* mask_1D = MapToMask(mask, map);
 
   // Calculate from 1D
   Double_t MLE = StatUtils::GetLikelihoodFromDiag(data_1D, mc_1D, mask_1D);
 
   // CleanUp
   delete data_1D;
   delete mc_1D;
   delete mask_1D;
 
   return MLE;
 };
 
 //*******************************************************************
 Double_t StatUtils::GetLikelihoodFromCov(TH1D* data, TH1D* mc,
                                          TMatrixDSym* invcov, TH1I* mask) {
   //*******************************************************************
   // Currently just a placeholder !
   (void)data;
   (void)mc;
   (void)invcov;
   (void)mask;
 
   return 0.0;
 };
 
 //*******************************************************************
 Double_t StatUtils::GetLikelihoodFromCov(TH2D* data, TH2D* mc,
                                          TMatrixDSym* invcov, TH2I* map,
                                          TH2I* mask) {
   //*******************************************************************
 
   // Generate a simple map
   if (!map) map = StatUtils::GenerateMap(data);
 
   // Convert to 1D Histograms
   TH1D* data_1D = MapToTH1D(data, map);
   TH1D* mc_1D = MapToTH1D(mc, map);
   TH1I* mask_1D = MapToMask(mask, map);
 
   // Calculate from 1D
   Double_t MLE =
       StatUtils::GetLikelihoodFromCov(data_1D, mc_1D, invcov, mask_1D);
 
   // CleanUp
   delete data_1D;
   delete mc_1D;
   delete mask_1D;
 
   return MLE;
 };
 
 //*******************************************************************
 Double_t StatUtils::GetLikelihoodFromSVD(TH1D* data, TH1D* mc, TMatrixDSym* cov,
                                          TH1I* mask) {
   //*******************************************************************
   // Currently just a placeholder!
   (void)data;
   (void)mc;
   (void)cov;
   (void)mask;
 
   return 0.0;
 };
 
 //*******************************************************************
 Double_t StatUtils::GetLikelihoodFromSVD(TH2D* data, TH2D* mc, TMatrixDSym* cov,
                                          TH2I* map, TH2I* mask) {
   //*******************************************************************
 
   // Generate a simple map
   if (!map) map = StatUtils::GenerateMap(data);
 
   // Convert to 1D Histograms
   TH1D* data_1D = MapToTH1D(data, map);
   TH1D* mc_1D = MapToTH1D(mc, map);
   TH1I* mask_1D = MapToMask(mask, map);
 
   // Calculate from 1D
   Double_t MLE = StatUtils::GetLikelihoodFromSVD(data_1D, mc_1D, cov, mask_1D);
 
   // CleanUp
   delete data_1D;
   delete mc_1D;
   delete mask_1D;
 
   return MLE;
 };
 
 //*******************************************************************
 Double_t StatUtils::GetLikelihoodFromEventRate(TH1D* data, TH1D* mc,
                                                TH1I* mask) {
   //*******************************************************************
   // Currently just a placeholder!
   (void)data;
   (void)mc;
   (void)mask;
 
   return 0.0;
 };
 
 //*******************************************************************
 Double_t StatUtils::GetLikelihoodFromEventRate(TH2D* data, TH2D* mc, TH2I* map,
                                                TH2I* mask) {
   //*******************************************************************
 
   // Generate a simple map
   if (!map) map = StatUtils::GenerateMap(data);
 
   // Convert to 1D Histograms
   TH1D* data_1D = MapToTH1D(data, map);
   TH1D* mc_1D = MapToTH1D(mc, map);
   TH1I* mask_1D = MapToMask(mask, map);
 
   // Calculate from 1D
   Double_t MLE = StatUtils::GetChi2FromEventRate(data_1D, mc_1D, mask_1D);
 
   // CleanUp
   delete data_1D;
   delete mc_1D;
   delete mask_1D;
 
   return MLE;
 };
 
 //*******************************************************************
 Int_t StatUtils::GetNDOF(TH1D* hist, TH1I* mask) {
   //*******************************************************************
 
   TH1D* calc_hist = (TH1D*)hist->Clone();
 
   // If a mask is provided we need to apply it before getting NDOF
   if (mask) {
     calc_hist = StatUtils::ApplyHistogramMasking(hist, mask);
   }
 
   // NDOF is defined as total number of bins with non-zero errors
   Int_t NDOF = 0;
   for (int i = 0; i < calc_hist->GetNbinsX(); i++) {
     if (calc_hist->GetBinError(i + 1) > 0.0) NDOF++;
   }
 
   delete calc_hist;
 
   return NDOF;
 };
 
 //*******************************************************************
 Int_t StatUtils::GetNDOF(TH2D* hist, TH2I* map, TH2I* mask) {
   //*******************************************************************
 
   Int_t NDOF = 0;
   if (!map) map = StatUtils::GenerateMap(hist);
 
   for (int i = 0; i < hist->GetNbinsX(); i++) {
     for (int j = 0; j < hist->GetNbinsY(); j++) {
       if (mask->GetBinContent(i + 1, j + 1)) continue;
       if (map->GetBinContent(i + 1, j + 1) <= 0) continue;
 
       NDOF++;
     }
   }
 
   return NDOF;
 };
 
 //*******************************************************************
 TH1D* StatUtils::ThrowHistogram(TH1D* hist, TMatrixDSym* cov, bool throwdiag,
                                 TH1I* mask) {
   //*******************************************************************
 
   TH1D* calc_hist =
       (TH1D*)hist->Clone((std::string(hist->GetName()) + "_THROW").c_str());
   TMatrixDSym* calc_cov = (TMatrixDSym*)cov->Clone();
   Double_t correl_val = 0.0;
 
   // If a mask if applied we need to apply it before the matrix is decomposed
   if (mask) {
     calc_cov = ApplyMatrixMasking(cov, mask);
     calc_hist = ApplyHistogramMasking(calc_hist, mask);
   }
 
   // If a covariance is provided we need a preset random vector and a decomp
   std::vector<Double_t> rand_val;
   TMatrixDSym* decomp_cov;
 
   if (cov) {
     for (int i = 0; i < hist->GetNbinsX(); i++) {
       rand_val.push_back(gRandom->Gaus(0.0, 1.0));
     }
 
     // Decomp the matrix
     decomp_cov = StatUtils::GetDecomp(calc_cov);
   }
 
   // iterate over bins
   for (int i = 0; i < hist->GetNbinsX(); i++) {
-    // By Default the errors on the histogram are thrown uncorrelated to the
-    // other errors
-    //    if (throwdiag) {
-    //      calc_hist->SetBinContent(i + 1, (calc_hist->GetBinContent(i + 1) + \
-    //				       gRandom->Gaus(0.0, 1.0) * calc_hist->GetBinError(i + 1)) );
-    //    }
+    // By Default the errors on the histogram are thrown uncorrelated to the other errors
+    /*
+    if (throwdiag) {
+      calc_hist->SetBinContent(i + 1, (calc_hist->GetBinContent(i + 1) + \
+           gRandom->Gaus(0.0, 1.0) * calc_hist->GetBinError(i + 1)) );
+    }
+    */
 
     // If a covariance is provided that is also thrown
     if (cov) {
       correl_val = 0.0;
 
       for (int j = 0; j < hist->GetNbinsX(); j++) {
         correl_val += rand_val[j] * (*decomp_cov)(j, i);
       }
       calc_hist->SetBinContent(
           i + 1, (calc_hist->GetBinContent(i + 1) + correl_val * 1E-38));
     }
   }
 
   delete calc_cov;
   delete decomp_cov;
 
   // return this new thrown data
   return calc_hist;
 };
 
 //*******************************************************************
 TH2D* StatUtils::ThrowHistogram(TH2D* hist, TMatrixDSym* cov, TH2I* map,
                                 bool throwdiag, TH2I* mask) {
   //*******************************************************************
 
   // PLACEHOLDER!!!!!!!!!
   // Currently no support for throwing 2D Histograms from a covariance
   (void)hist;
   (void)cov;
   (void)map;
   (void)throwdiag;
   (void)mask;
 
   // /todo
   // Sort maps if required
   // Throw the covariance for a 1D plot
   // Unmap back to 2D Histogram
 
   return hist;
 }
 
 //*******************************************************************
 TH1D* StatUtils::ApplyHistogramMasking(TH1D* hist, TH1I* mask) {
   //*******************************************************************
 
   if (!mask) return ((TH1D*)hist->Clone());
 
   // This masking is only sufficient for chi2 calculations, and will have dodgy
   // bin edges.
 
   // Get New Bin Count
   Int_t NBins = 0;
   for (int i = 0; i < hist->GetNbinsX(); i++) {
     if (mask->GetBinContent(i + 1)) continue;
     NBins++;
   }
 
   // Make new hist
   std::string newmaskname = std::string(hist->GetName()) + "_MSKD";
   TH1D* calc_hist =
       new TH1D(newmaskname.c_str(), newmaskname.c_str(), NBins, 0, NBins);
 
   // fill new hist
   int binindex = 0;
   for (int i = 0; i < hist->GetNbinsX(); i++) {
     if (mask->GetBinContent(i + 1)) {
       LOG(REC) << "Applying mask to bin " << i + 1 << " " << hist->GetName()
                << std::endl;
       continue;
     }
     calc_hist->SetBinContent(binindex + 1, hist->GetBinContent(i + 1));
     calc_hist->SetBinError(binindex + 1, hist->GetBinError(i + 1));
     binindex++;
   }
 
   return calc_hist;
 };
 
 //*******************************************************************
 TH2D* StatUtils::ApplyHistogramMasking(TH2D* hist, TH2I* mask) {
   //*******************************************************************
 
   TH2D* newhist = (TH2D*)hist->Clone();
 
   if (!mask) return newhist;
 
   for (int i = 0; i < hist->GetNbinsX(); i++) {
     for (int j = 0; j < hist->GetNbinsY(); j++) {
       if (mask->GetBinContent(i + 1, j + 1) > 0) {
         newhist->SetBinContent(i + 1, j + 1, 0.0);
         newhist->SetBinContent(i + 1, j + 1, 0.0);
       }
     }
   }
 
   return newhist;
 }
 
 //*******************************************************************
 TMatrixDSym* StatUtils::ApplyMatrixMasking(TMatrixDSym* mat, TH1I* mask) {
   //*******************************************************************
 
   if (!mask) return (TMatrixDSym*)(mat->Clone());
 
   // Get New Bin Count
   Int_t NBins = 0;
   for (int i = 0; i < mask->GetNbinsX(); i++) {
     if (mask->GetBinContent(i + 1)) continue;
     NBins++;
   }
 
   // make new matrix
   TMatrixDSym* calc_mat = new TMatrixDSym(NBins);
   int col, row;
 
   // Need to mask out bins in the current matrix
   row = 0;
   for (int i = 0; i < mask->GetNbinsX(); i++) {
     col = 0;
 
     // skip if masked
     if (mask->GetBinContent(i + 1) > 0.5) continue;
 
     for (int j = 0; j < mask->GetNbinsX(); j++) {
       // skip if masked
       if (mask->GetBinContent(j + 1) > 0.5) continue;
 
       (*calc_mat)(row, col) = (*mat)(i, j);
       col++;
     }
     row++;
   }
 
   return calc_mat;
 };
 
 //*******************************************************************
 TMatrixDSym* StatUtils::ApplyMatrixMasking(TMatrixDSym* mat, TH2D* data,
                                            TH2I* mask, TH2I* map) {
   //*******************************************************************
 
   if (!map) map = StatUtils::GenerateMap(data);
   TH1I* mask_1D = StatUtils::MapToMask(mask, map);
 
   TMatrixDSym* newmat = StatUtils::ApplyMatrixMasking(mat, mask_1D);
 
   delete mask_1D;
   return newmat;
 }
 
 //*******************************************************************
 TMatrixDSym* StatUtils::ApplyInvertedMatrixMasking(TMatrixDSym* mat,
                                                    TH1I* mask) {
   //*******************************************************************
 
   TMatrixDSym* new_mat = GetInvert(mat);
   TMatrixDSym* masked_mat = ApplyMatrixMasking(new_mat, mask);
 
   TMatrixDSym* inverted_mat = GetInvert(masked_mat);
 
   delete masked_mat;
   delete new_mat;
 
   return inverted_mat;
 };
 
 //*******************************************************************
 TMatrixDSym* StatUtils::ApplyInvertedMatrixMasking(TMatrixDSym* mat, TH2D* data,
                                                    TH2I* mask, TH2I* map) {
   //*******************************************************************
 
   if (!map) map = StatUtils::GenerateMap(data);
   TH1I* mask_1D = StatUtils::MapToMask(mask, map);
 
   TMatrixDSym* newmat = ApplyInvertedMatrixMasking(mat, mask_1D);
 
   delete mask_1D;
   return newmat;
 }
 
 //*******************************************************************
 TMatrixDSym* StatUtils::GetInvert(TMatrixDSym* mat) {
   //*******************************************************************
 
   TMatrixDSym* new_mat = (TMatrixDSym*)mat->Clone();
 
   // Check for diagonal
   bool non_diagonal = false;
   for (int i = 0; i < new_mat->GetNrows(); i++) {
     for (int j = 0; j < new_mat->GetNrows(); j++) {
       if (i == j) continue;
 
       if ((*new_mat)(i, j) != 0.0) {
         non_diagonal = true;
         break;
       }
     }
   }
 
   // If diag, just flip the diag
   if (!non_diagonal or new_mat->GetNrows() == 1) {
     for (int i = 0; i < new_mat->GetNrows(); i++) {
       if ((*new_mat)(i, i) != 0.0)
         (*new_mat)(i, i) = 1.0 / (*new_mat)(i, i);
       else
         (*new_mat)(i, i) = 0.0;
     }
     return new_mat;
   }
 
   // Invert full matrix
   TDecompSVD LU = TDecompSVD((*new_mat));
   new_mat =
       new TMatrixDSym(new_mat->GetNrows(), LU.Invert().GetMatrixArray(), "");
 
   return new_mat;
 }
 
 //*******************************************************************
 TMatrixDSym* StatUtils::GetDecomp(TMatrixDSym* mat) {
   //*******************************************************************
 
   TMatrixDSym* new_mat = (TMatrixDSym*)mat->Clone();
   int nrows = new_mat->GetNrows();
 
   // Check for diagonal
   bool diagonal = true;
   for (int i = 0; i < nrows; i++) {
     for (int j = 0; j < nrows; j++) {
       if (i == j) continue;
 
       if ((*new_mat)(i, j) != 0.0) {
         diagonal = false;
         break;
       }
     }
   }
 
   // If diag, just flip the diag
   if (diagonal or nrows == 1) {
     for (int i = 0; i < nrows; i++) {
       if ((*new_mat)(i, i) > 0.0)
         (*new_mat)(i, i) = sqrt((*new_mat)(i, i));
       else
         (*new_mat)(i, i) = 0.0;
     }
     return new_mat;
   }
 
   TDecompChol LU = TDecompChol(*new_mat);
   LU.Decompose();
   delete new_mat;
 
   TMatrixDSym* dec_mat = new TMatrixDSym(nrows, LU.GetU().GetMatrixArray(), "");
 
   return dec_mat;
 }
 
 //*******************************************************************
 void StatUtils::ForceNormIntoCovar(TMatrixDSym* mat, TH1D* hist, double norm) {
   //*******************************************************************
 
   if (!mat) mat = MakeDiagonalCovarMatrix(hist);
 
   int nbins = mat->GetNrows();
   TMatrixDSym* new_mat = new TMatrixDSym(nbins);
 
   for (int i = 0; i < nbins; i++) {
     for (int j = 0; j < nbins; j++) {
       double valx = hist->GetBinContent(i + 1) * 1E38;
       double valy = hist->GetBinContent(j + 1) * 1E38;
 
       (*new_mat)(i, j) = (*mat)(i, j) + norm * norm * valx * valy;
     }
   }
 
   // Swap the two
   delete mat;
   mat = new_mat;
 
   return;
 };
 
 //*******************************************************************
 void StatUtils::ForceNormIntoCovar(TMatrixDSym* mat, TH2D* data, double norm,
                                    TH2I* map) {
   //*******************************************************************
 
   if (!map) map = StatUtils::GenerateMap(data);
   TH1D* data_1D = MapToTH1D(data, map);
 
   StatUtils::ForceNormIntoCovar(mat, data_1D, norm);
   delete data_1D;
 
   return;
 }
 
 //*******************************************************************
 TMatrixDSym* StatUtils::MakeDiagonalCovarMatrix(TH1D* data, double scaleF) {
   //*******************************************************************
 
   TMatrixDSym* newmat = new TMatrixDSym(data->GetNbinsX());
 
   for (int i = 0; i < data->GetNbinsX(); i++) {
     (*newmat)(i, i) =
         data->GetBinError(i + 1) * data->GetBinError(i + 1) * scaleF * scaleF;
   }
 
   return newmat;
 }
 
 //*******************************************************************
 TMatrixDSym* StatUtils::MakeDiagonalCovarMatrix(TH2D* data, TH2I* map,
                                                 double scaleF) {
   //*******************************************************************
 
   if (!map) map = StatUtils::GenerateMap(data);
   TH1D* data_1D = MapToTH1D(data, map);
 
   return StatUtils::MakeDiagonalCovarMatrix(data_1D, scaleF);
 };
 
 //*******************************************************************
 void StatUtils::SetDataErrorFromCov(TH1D* data, TMatrixDSym* cov,
                                     double scale) {
   //*******************************************************************
 
   // Check
   if (cov->GetNrows() != data->GetNbinsX()) {
-    ERR(WRN) << "Nrows in cov don't match nbins in data for SetDataErrorFromCov"
-             << std::endl;
+    ERR(FTL) << "Nrows in cov don't match nbins in data for SetDataErrorFromCov" << std::endl;
+    ERR(FTL) << "Nrows = " << cov->GetNrows() << std::endl;
+    ERR(FTL) << "Nbins = " << data->GetNbinsX() << std::endl;
+    //throw;
   }
 
   // Set bin errors form cov diag
+  // Check if the errors are set
+  bool ErrorsSet = false;
   for (int i = 0; i < data->GetNbinsX(); i++) {
-    data->SetBinError(i + 1, sqrt((*cov)(i, i)) * scale);
+    if (ErrorsSet == true) break;
+    if (data->GetBinError(i+1) != 0) ErrorsSet = true;
+  }
+
+  // Now loop over
+  if (ErrorsSet) {
+    for (int i = 0; i < data->GetNbinsX(); i++) {
+      double dataerr = data->GetBinError(i + 1);
+      double coverr = sqrt((*cov)(i, i))*scale;
+      if (fabs(dataerr-coverr) > 1E-44) {
+        ERR(FTL) << "Data error does not match covariance error for bin " << i+1 << " (" << data->GetXaxis()->GetBinLowEdge(i+1) << "-" << data->GetXaxis()->GetBinLowEdge(i+2) << ")" << std::endl;
+        ERR(FTL) << "Data error: " << dataerr << std::endl;
+        ERR(FTL) << "Cov error:  " << coverr << std::endl;
+      }
+    }
+    // Else blindly trust the covariance
+  } else {
+    for (int i = 0; i < data->GetNbinsX(); i++) {
+      data->SetBinError(i+1, sqrt((*cov)(i,i))*scale);
+    }
   }
 
   return;
 }
 
 //*******************************************************************
 void StatUtils::SetDataErrorFromCov(TH2D* data, TMatrixDSym* cov, TH2I* map,
-                                    double scale) {
+    double scale) {
   //*******************************************************************
 
   // Create map if required
   if (!map) map = StatUtils::GenerateMap(data);
 
   // Set Bin Errors from cov diag
   int count = 0;
   for (int i = 0; i < data->GetNbinsX(); i++) {
     for (int j = 0; j < data->GetNbinsY(); j++) {
       if (data->GetBinContent(i + 1, j + 1) == 0.0) continue;
 
       count = map->GetBinContent(i + 1, j + 1) - 1;
       data->SetBinError(i + 1, j + 1, sqrt((*cov)(count, count)) * scale);
     }
   }
 
   return;
 }
 
 TMatrixDSym* StatUtils::ExtractShapeOnlyCovar(TMatrixDSym* full_covar,
-                                              TH1* data_hist,
-                                              double data_scale) {
+    TH1* data_hist,
+    double data_scale) {
   int nbins = full_covar->GetNrows();
   TMatrixDSym* shape_covar = new TMatrixDSym(nbins);
 
   // Check nobody is being silly
   if (data_hist->GetNbinsX() != nbins) {
     ERR(WRN) << "Inconsistent matrix and data histogram passed to "
-                "StatUtils::ExtractShapeOnlyCovar!"
-             << std::endl;
+      "StatUtils::ExtractShapeOnlyCovar!"
+      << std::endl;
     ERR(WRN) << "data_hist has " << data_hist->GetNbinsX() << " matrix has "
-             << nbins << std::endl;
+      << nbins << std::endl;
     int err_bins = data_hist->GetNbinsX();
     if (nbins > err_bins) err_bins = nbins;
     for (int i = 0; i < err_bins; ++i) {
       ERR(WRN) << "Matrix diag. = " << (*full_covar)(i, i)
-               << " data = " << data_hist->GetBinContent(i + 1) << std::endl;
+        << " data = " << data_hist->GetBinContent(i + 1) << std::endl;
     }
     return NULL;
   }
 
   double total_data = 0;
   double total_covar = 0;
 
   // Initial loop to calculate some constants
   for (int i = 0; i < nbins; ++i) {
     total_data += data_hist->GetBinContent(i + 1) * data_scale;
     for (int j = 0; j < nbins; ++j) {
       total_covar += (*full_covar)(i, j);
     }
   }
 
   if (total_data == 0 || total_covar == 0) {
     ERR(WRN) << "Stupid matrix or data histogram passed to "
-                "StatUtils::ExtractShapeOnlyCovar! Ignoring..."
-             << std::endl;
+      "StatUtils::ExtractShapeOnlyCovar! Ignoring..."
+      << std::endl;
     return NULL;
   }
 
   LOG(SAM) << "Norm error = " << sqrt(total_covar) / total_data << std::endl;
 
   // Now loop over and calculate the shape-only matrix
   for (int i = 0; i < nbins; ++i) {
     double data_i = data_hist->GetBinContent(i + 1) * data_scale;
 
     for (int j = 0; j < nbins; ++j) {
       double data_j = data_hist->GetBinContent(j + 1) * data_scale;
 
       double norm_term =
-          data_i * data_j * total_covar / total_data / total_data;
+        data_i * data_j * total_covar / total_data / total_data;
       double mix_sum1 = 0;
       double mix_sum2 = 0;
 
       for (int k = 0; k < nbins; ++k) {
         mix_sum1 += (*full_covar)(k, j);
         mix_sum2 += (*full_covar)(i, k);
       }
 
       double mix_term1 =
-          data_i * (mix_sum1 / total_data -
-                    total_covar * data_j / total_data / total_data);
+        data_i * (mix_sum1 / total_data -
+            total_covar * data_j / total_data / total_data);
       double mix_term2 =
-          data_j * (mix_sum2 / total_data -
-                    total_covar * data_i / total_data / total_data);
+        data_j * (mix_sum2 / total_data -
+            total_covar * data_i / total_data / total_data);
 
       (*shape_covar)(i, j) =
-          (*full_covar)(i, j) - mix_term1 - mix_term2 - norm_term;
+        (*full_covar)(i, j) - mix_term1 - mix_term2 - norm_term;
     }
   }
   return shape_covar;
 }
 
 //*******************************************************************
 TH2I* StatUtils::GenerateMap(TH2D* hist) {
   //*******************************************************************
 
   std::string maptitle = std::string(hist->GetName()) + "_MAP";
 
   TH2I* map =
-      new TH2I(maptitle.c_str(), maptitle.c_str(), hist->GetNbinsX(), 0,
-               hist->GetNbinsX(), hist->GetNbinsY(), 0, hist->GetNbinsY());
+    new TH2I(maptitle.c_str(), maptitle.c_str(), hist->GetNbinsX(), 0,
+        hist->GetNbinsX(), hist->GetNbinsY(), 0, hist->GetNbinsY());
 
   Int_t index = 1;
 
   for (int i = 0; i < hist->GetNbinsX(); i++) {
     for (int j = 0; j < hist->GetNbinsY(); j++) {
       if (hist->GetBinContent(i + 1, j + 1) > 0 &&
           hist->GetBinError(i + 1, j + 1) > 0) {
         map->SetBinContent(i + 1, j + 1, index);
         index++;
       } else {
         map->SetBinContent(i + 1, j + 1, 0);
       }
     }
   }
 
   return map;
 }
 
 //*******************************************************************
 TH1D* StatUtils::MapToTH1D(TH2D* hist, TH2I* map) {
   //*******************************************************************
 
   if (!hist) return NULL;
 
   // Get N bins for 1D plot
   Int_t Nbins = map->GetMaximum();
   std::string name1D = std::string(hist->GetName()) + "_1D";
 
   // Make new 1D Hist
   TH1D* newhist = new TH1D(name1D.c_str(), name1D.c_str(), Nbins, 0, Nbins);
 
   // map bin contents
   for (int i = 0; i < map->GetNbinsX(); i++) {
     for (int j = 0; j < map->GetNbinsY(); j++) {
       if (map->GetBinContent(i + 1, j + 1) == 0) continue;
 
       newhist->SetBinContent(map->GetBinContent(i + 1, j + 1),
-                             hist->GetBinContent(i + 1, j + 1));
+          hist->GetBinContent(i + 1, j + 1));
       newhist->SetBinError(map->GetBinContent(i + 1, j + 1),
-                           hist->GetBinError(i + 1, j + 1));
+          hist->GetBinError(i + 1, j + 1));
     }
   }
 
   // return
   return newhist;
 }
 
 //*******************************************************************
 TH1I* StatUtils::MapToMask(TH2I* hist, TH2I* map) {
   //*******************************************************************
 
   TH1I* newhist = NULL;
   if (!hist) return newhist;
 
   // Get N bins for 1D plot
   Int_t Nbins = map->GetMaximum();
   std::string name1D = std::string(hist->GetName()) + "_1D";
 
   // Make new 1D Hist
   newhist = new TH1I(name1D.c_str(), name1D.c_str(), Nbins, 0, Nbins);
 
   // map bin contents
   for (int i = 0; i < map->GetNbinsX(); i++) {
     for (int j = 0; j < map->GetNbinsY(); j++) {
       if (map->GetBinContent(i + 1, j + 1) == 0) continue;
 
       newhist->SetBinContent(map->GetBinContent(i + 1, j + 1),
-                             hist->GetBinContent(i + 1, j + 1));
+          hist->GetBinContent(i + 1, j + 1));
     }
   }
 
   // return
   return newhist;
 }
 
 TMatrixDSym* StatUtils::GetCovarFromCorrel(TMatrixDSym* correl, TH1D* data) {
   int nbins = correl->GetNrows();
   TMatrixDSym* covar = new TMatrixDSym(nbins);
 
   for (int i = 0; i < nbins; i++) {
     for (int j = 0; j < nbins; j++) {
       (*covar)(i, j) =
-          (*correl)(i, j) * data->GetBinError(i + 1) * data->GetBinError(j + 1);
+        (*correl)(i, j) * data->GetBinError(i + 1) * data->GetBinError(j + 1);
     }
   }
 
   return covar;
 }
 
 //*******************************************************************
 TMatrixD* StatUtils::GetMatrixFromTextFile(std::string covfile, int dimx,
-                                           int dimy) {
+    int dimy) {
   //*******************************************************************
 
   // Determine dim
   if (dimx == -1 and dimy == -1) {
     std::string line;
     std::ifstream covar(covfile.c_str(), std::ifstream::in);
 
     int row = 0;
     while (std::getline(covar >> std::ws, line, '\n')) {
       int column = 0;
 
       std::vector<double> entries = GeneralUtils::ParseToDbl(line, " ");
 
       if (entries.size() <= 1) {
         ERR(WRN) << "StatUtils::GetMatrixFromTextFile, matrix only has <= 1 "
-                    "entries on this line: "
-                 << row << std::endl;
+          "entries on this line: "
+          << row << std::endl;
       }
       for (std::vector<double>::iterator iter = entries.begin();
-           iter != entries.end(); iter++) {
+          iter != entries.end(); iter++) {
         column++;
 
         if (column > dimx) dimx = column;
       }
       row++;
       if (row > dimy) dimy = row;
     }
   }
 
   // Or assume symmetric
   if (dimx != -1 and dimy == -1) {
     dimy = dimx;
   }
   assert(dimy != -1 && " matrix dimy not set.");
 
   // Make new matrix
   TMatrixD* mat = new TMatrixD(dimx, dimy);
   std::string line;
   std::ifstream covar(covfile.c_str(), std::ifstream::in);
 
   int row = 0;
   while (std::getline(covar >> std::ws, line, '\n')) {
     int column = 0;
 
     std::vector<double> entries = GeneralUtils::ParseToDbl(line, " ");
     if (entries.size() <= 1) {
       ERR(WRN) << "StatUtils::GetMatrixFromTextFile, matrix only has <= 1 "
-                  "entries on this line: "
-               << row << std::endl;
+        "entries on this line: "
+        << row << std::endl;
     }
     for (std::vector<double>::iterator iter = entries.begin();
-         iter != entries.end(); iter++) {
+        iter != entries.end(); iter++) {
       // Check Rows
       // assert(row > mat->GetNrows() && " covar rows doesn't match matrix
       // rows.");
       // assert(column > mat->GetNcols() && " covar cols doesn't match matrix
       // cols.");
 
       // Fill Matrix
       (*mat)(row, column) = (*iter);
       column++;
     }
     row++;
   }
 
   return mat;
 }
 
 //*******************************************************************
 TMatrixD* StatUtils::GetMatrixFromRootFile(std::string covfile,
-                                           std::string histname) {
+    std::string histname) {
   //*******************************************************************
 
   std::string inputfile = covfile + ";" + histname;
   std::vector<std::string> splitfile = GeneralUtils::ParseToStr(inputfile, ";");
 
   if (splitfile.size() < 2) {
     ERR(FTL) << "No object name given!" << std::endl;
     throw;
   }
 
   // Get file
   TFile* tempfile = new TFile(splitfile[0].c_str(), "READ");
 
   // Get Object
   TObject* obj = tempfile->Get(splitfile[1].c_str());
   if (!obj) {
     ERR(FTL) << "Object " << splitfile[1] << " doesn't exist!" << std::endl;
     throw;
   }
 
   // Try casting
   TMatrixD* mat = dynamic_cast<TMatrixD*>(obj);
   if (mat) {
     TMatrixD* newmat = (TMatrixD*)mat->Clone();
 
     delete mat;
     tempfile->Close();
 
     return newmat;
   }
 
   TMatrixDSym* matsym = dynamic_cast<TMatrixDSym*>(obj);
   if (matsym) {
     TMatrixD* newmat = new TMatrixD(matsym->GetNrows(), matsym->GetNrows());
     for (int i = 0; i < matsym->GetNrows(); i++) {
       for (int j = 0; j < matsym->GetNrows(); j++) {
         (*newmat)(i, j) = (*matsym)(i, j);
       }
     }
 
     delete matsym;
     tempfile->Close();
 
     return newmat;
   }
 
   TH2D* mathist = dynamic_cast<TH2D*>(obj);
   if (mathist) {
     TMatrixD* newmat = new TMatrixD(mathist->GetNbinsX(), mathist->GetNbinsX());
     for (int i = 0; i < mathist->GetNbinsX(); i++) {
       for (int j = 0; j < mathist->GetNbinsX(); j++) {
         (*newmat)(i, j) = mathist->GetBinContent(i + 1, j + 1);
       }
     }
 
     delete mathist;
     tempfile->Close();
 
     return newmat;
   }
 
   return NULL;
 }
 
 //*******************************************************************
 TMatrixDSym* StatUtils::GetCovarFromTextFile(std::string covfile, int dim) {
   //*******************************************************************
 
   // Delete TempMat
   TMatrixD* tempmat = GetMatrixFromTextFile(covfile, dim, dim);
 
   // Make a symmetric covariance
   TMatrixDSym* newmat = new TMatrixDSym(tempmat->GetNrows());
   for (int i = 0; i < tempmat->GetNrows(); i++) {
     for (int j = 0; j < tempmat->GetNrows(); j++) {
       (*newmat)(i, j) = (*tempmat)(i, j);
     }
   }
 
   delete tempmat;
   return newmat;
 }
 
 //*******************************************************************
 TMatrixDSym* StatUtils::GetCovarFromRootFile(std::string covfile,
-                                             std::string histname) {
+    std::string histname) {
   //*******************************************************************
 
   TMatrixD* tempmat = GetMatrixFromRootFile(covfile, histname);
   TMatrixDSym* newmat = new TMatrixDSym(tempmat->GetNrows());
 
   for (int i = 0; i < tempmat->GetNrows(); i++) {
     for (int j = 0; j < tempmat->GetNrows(); j++) {
       (*newmat)(i, j) = (*tempmat)(i, j);
     }
   }
 
   delete tempmat;
   return newmat;
 }
diff --git a/src/T2K/T2K_CC0pinp_STV_XSec_1Ddat_nu.cxx b/src/T2K/T2K_CC0pinp_STV_XSec_1Ddat_nu.cxx
index fd5a4a6..0cc4155 100644
--- a/src/T2K/T2K_CC0pinp_STV_XSec_1Ddat_nu.cxx
+++ b/src/T2K/T2K_CC0pinp_STV_XSec_1Ddat_nu.cxx
@@ -1,90 +1,87 @@
 // Copyright 2016 L. Pickering, P Stowell, R. Terri, C. Wilkinson, C. Wret
 
 /*******************************************************************************
 *    This file is part of NUISANCE.
 *
 *    NUISANCE is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    NUISANCE is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with NUISANCE.  If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/
 
 #include "T2K_SignalDef.h"
 
 #include "T2K_CC0pinp_STV_XSec_1Ddat_nu.h"
 
 
 //********************************************************************
 T2K_CC0pinp_STV_XSec_1Ddat_nu::T2K_CC0pinp_STV_XSec_1Ddat_nu(nuiskey samplekey) {
 //********************************************************************
 
   // Sample overview ---------------------------------------------------
   std::string descrip = "T2K_CC0pinp_STV_XSec_1Ddat_nu sample. \n" \
                         "Target: CH \n" \
                         "Flux: T2K 2.5 degree off-axis (ND280)  \n" \
                         "Signal: CC0piNp (N>=1) with 450M eV < p_p < 1 GeV \n" \
                         "                            p_mu > 250 MeV \n" \
                         "                            cth_p >  0.6 \n" \
                         "                            cth_mu > -0.4 \n";
 
   // Setup common settings
   fSettings = LoadSampleSettings(samplekey);
   fSettings.SetDescription(descrip);
   fSettings.SetXTitle("#delta#it{#alpha}_{T} (GeV c^{-1})");
   fSettings.SetYTitle("#frac{d#sigma}{d#delta#it{#alpha}_{T}} (cm^{2} nucleon^{-1} rads^{-1})");
   fSettings.SetAllowedTypes("FIX,FREE,SHAPE/DIAG,FULL/NORM/MASK", "FIX/DIAG");
   fSettings.SetEnuRange(0.0, 50.0);
   fSettings.DefineAllowedTargets("C,H");
 
   // CCQELike plot information
   fSettings.SetTitle("T2K_CC0pinp_STV_XSec_1Ddat_nu");
  // fSettings.SetDataInput(  GeneralUtils::GetTopLevelDir() + "/data/T2K/T2K_CC0pinp_STV_XSec_1Ddat_nu.dat");
 
   fSettings.SetDataInput(  FitPar::GetDataBase() + "/T2K/CC0pi/STV/datResults.root;Result" );
   fSettings.SetCovarInput( FitPar::GetDataBase() + "/T2K/CC0pi/STV/datResults.root;Correlation_Matrix" );
 
   fSettings.DefineAllowedSpecies("numu");
 
   FinaliseSampleSettings();
 
   // Scaling Setup ---------------------------------------------------
   // ScaleFactor automatically setup for DiffXSec/cm2/Nucleon
   fScaleFactor = GetEventHistogram()->Integral("width") * double(1E-38) /
                 (double(fNEvents) * TotalIntegratedFlux("width"));
 
   // Plot Setup -------------------------------------------------------
   //SetDataFromTextFile( fSettings.GetDataInput() );
   //ScaleData(1E-38);
   //SetCovarFromDiagonal();
 
   SetDataFromRootFile( fSettings.GetDataInput() );
   SetCorrelationFromRootFile(fSettings.GetCovarInput() ); 
 
 
   // Final setup  ---------------------------------------------------
   FinaliseMeasurement();
 
 };
 
-
-
-
 void T2K_CC0pinp_STV_XSec_1Ddat_nu::FillEventVariables(FitEvent *event) {
   fXVar = FitUtils::Get_STV_dalphat(event, 14, true);
   return;
 };
 
 //********************************************************************
 bool T2K_CC0pinp_STV_XSec_1Ddat_nu::isSignal(FitEvent *event)
 //********************************************************************
 {
   return SignalDef::isT2K_CC0pi_STV(event, EnuMin, EnuMax);
 }
diff --git a/src/T2K/T2K_CC0pinp_STV_XSec_1Ddpt_nu.cxx b/src/T2K/T2K_CC0pinp_STV_XSec_1Ddpt_nu.cxx
index cc4f9ad..0b862ed 100644
--- a/src/T2K/T2K_CC0pinp_STV_XSec_1Ddpt_nu.cxx
+++ b/src/T2K/T2K_CC0pinp_STV_XSec_1Ddpt_nu.cxx
@@ -1,93 +1,89 @@
 // Copyright 2016 L. Pickering, P Stowell, R. Terri, C. Wilkinson, C. Wret
 
 /*******************************************************************************
 *    This file is part of NUISANCE.
 *
 *    NUISANCE is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    NUISANCE is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with NUISANCE.  If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/
 
 #include "T2K_SignalDef.h"
 
 #include "T2K_CC0pinp_STV_XSec_1Ddpt_nu.h"
 
 
 //********************************************************************
 T2K_CC0pinp_STV_XSec_1Ddpt_nu::T2K_CC0pinp_STV_XSec_1Ddpt_nu(nuiskey samplekey) {
 //********************************************************************
 
   // Sample overview ---------------------------------------------------
   std::string descrip = "T2K_CC0pinp_STV_XSec_1Ddpt_nu sample. \n" \
                         "Target: CH \n" \
                         "Flux: T2K 2.5 degree off-axis (ND280)  \n" \
                         "Signal: CC0piNp (N>=1) with 450M eV < p_p < 1 GeV \n"\
                         "                            p_mu > 250 MeV \n"\
                         "                            cth_p >  0.6 \n"\
                         "                            cth_mu > -0.4 \n";\
 
   // Setup common settings
   fSettings = LoadSampleSettings(samplekey);
   fSettings.SetDescription(descrip);
   fSettings.SetXTitle("#delta#it{p}_{T} (GeV c^{-1})");
   fSettings.SetYTitle("#frac{d#sigma}{d#delta#it{p}_{T}} (cm^{2} nucleon^{-1} GeV^{-1} c)");
   fSettings.SetAllowedTypes("FIX,FREE,SHAPE/DIAG,FULL/NORM/MASK", "FIX/DIAG");
   fSettings.SetEnuRange(0.0, 50.0);
   fSettings.DefineAllowedTargets("C,H");
 
   // CCQELike plot information
   fSettings.SetTitle("T2K_CC0pinp_STV_XSec_1Ddpt_nu");
   //fSettings.SetDataInput(  GeneralUtils::GetTopLevelDir() + "/data/T2K/T2K_CC0pinp_STV_XSec_1Ddpt_nu.dat");
 
   fSettings.SetDataInput(  FitPar::GetDataBase() + "/T2K/CC0pi/STV/dptResults.root;Result" );
   fSettings.SetCovarInput( FitPar::GetDataBase() + "/T2K/CC0pi/STV/dptResults.root;Correlation_Matrix" );
 
 
   fSettings.DefineAllowedSpecies("numu");
 
   FinaliseSampleSettings();
 
   // Scaling Setup ---------------------------------------------------
   // ScaleFactor automatically setup for DiffXSec/cm2/Nucleon
   fScaleFactor = GetEventHistogram()->Integral("width") * double(1E-38) /
                 (double(fNEvents) * TotalIntegratedFlux("width"));
 
   // Plot Setup -------------------------------------------------------
   //SetDataFromTextFile( fSettings.GetDataInput() );
   //SetCovarFromDiagonal();
   //ScaleData(1E-38);
 
 
   SetDataFromRootFile( fSettings.GetDataInput() );
   SetCorrelationFromRootFile(fSettings.GetCovarInput() );              
   //SetCovarianceFromRootFile(fSettings.GetCovarInput() );              
 
 
   // Final setup  ---------------------------------------------------
   FinaliseMeasurement();
 
 };
-
-
-
-
 void T2K_CC0pinp_STV_XSec_1Ddpt_nu::FillEventVariables(FitEvent *event) {
   fXVar = FitUtils::Get_STV_dpt(event, 14, true) / 1000.0;
   return;
 };
 
 //********************************************************************
 bool T2K_CC0pinp_STV_XSec_1Ddpt_nu::isSignal(FitEvent *event)
 //********************************************************************
 {
   return SignalDef::isT2K_CC0pi_STV(event, EnuMin, EnuMax);
 }
diff --git a/src/T2K/T2K_SignalDef.cxx b/src/T2K/T2K_SignalDef.cxx
index bfb151d..815f313 100644
--- a/src/T2K/T2K_SignalDef.cxx
+++ b/src/T2K/T2K_SignalDef.cxx
@@ -1,311 +1,310 @@
 // Copyright 2016 L. Pickering, P Stowell, R. Terri, C. Wilkinson, C. Wret
 
 /*******************************************************************************
 *    This file is part of NUISANCE.
 *
 *    NUISANCE is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    NUISANCE is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with NUISANCE.  If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/
 
 #include "FitUtils.h"
 #include "T2K_SignalDef.h"
 
 namespace SignalDef {
 
 // T2K H2O signal definition
 bool isCC1pip_T2K_H2O(FitEvent *event, double EnuMin,
                                  double EnuMax) {
 
   if (!isCC1pi(event, 14, 211, EnuMin, EnuMax)) return false;
 
   TLorentzVector Pnu = event->GetHMISParticle(14)->fP;
   TLorentzVector Pmu = event->GetHMFSParticle(13)->fP;
   TLorentzVector Ppip = event->GetHMFSParticle(211)->fP;
 
   double p_mu = FitUtils::p(Pmu) * 1000;
   double p_pi = FitUtils::p(Ppip) * 1000;
   double cos_th_mu = cos(FitUtils::th(Pnu, Pmu));
   double cos_th_pi = cos(FitUtils::th(Pnu, Ppip));
 
   if (p_mu <= 200 || p_pi <= 200 || cos_th_mu <= 0.3 || cos_th_pi <= 0.3) {
     return false;
   }
 
   return true;
 };
 
 // ******************************************************
 // T2K CC1pi+ CH analysis (Raquel's thesis)
 // Has different phase space cuts depending on if using Michel tag or not
 //
 // Essentially consists of two samples: one sample which has Michel e (which we
 // can't get pion direction from); this covers backwards angles quite well.
 // Measurements including this sample does not have include pion kinematics cuts
 //                                      one sample which has PID in FGD and TPC
 //                                      and no Michel e. These are mostly
 //                                      forward-going so require a pion
 //                                      kinematics cut
 //
 //  Essentially, cuts are:
 //                          1 negative muon
 //                          1 positive pion
 //                          Any number of nucleons
 //                          No other particles in the final state
 //
 // MOVE T2K
 bool isCC1pip_T2K_CH(FitEvent *event, double EnuMin, double EnuMax,
                                 bool MichelElectron) {
   // ******************************************************
 
   if (!isCC1pi(event, 14, 211, EnuMin, EnuMax)) return false;
 
   TLorentzVector Pnu = event->GetHMISParticle(14)->fP;
   TLorentzVector Pmu = event->GetHMFSParticle(13)->fP;
   TLorentzVector Ppip = event->GetHMFSParticle(211)->fP;
 
   // If this event passes the criteria on particle counting, enforce the T2K
   // ND280 phase space constraints
   // Will be different if Michel tag sample is included or not
   // Essentially, if there's a Michel tag we don't cut on the pion variables
 
   double p_mu = FitUtils::p(Pmu) * 1000;
   double p_pi = FitUtils::p(Ppip) * 1000;
   double cos_th_mu = cos(FitUtils::th(Pnu, Pmu));
   double cos_th_pi = cos(FitUtils::th(Pnu, Ppip));
 
   // If we're using Michel e- requirement we only care about the muon restricted
   // phase space and use full pion phase space
   if (MichelElectron) {
     // Make the cuts on the muon variables
     if (p_mu <= 200 || cos_th_mu <= 0.2) {
       return false;
     } else {
       return true;
     }
 
     // If we aren't using Michel e- (i.e. we use directional information from
     // pion) we need to impose the phase space cuts on the muon AND the pion)
   } else {
     // Make the cuts on muon and pion variables
     if (p_mu <= 200 || p_pi <= 200 || cos_th_mu <= 0.2 || cos_th_pi <= 0.2) {
       return false;
     } else {
       return true;
     }
   }
 
   // Default to false; should never fire
   return false;
 };
 
 bool isT2K_CC0pi(FitEvent *event, double EnuMin, double EnuMax,
                             bool forwardgoing) {
 
   // Require a numu CC0pi event
   if (!isCC0pi(event, 14, EnuMin, EnuMax)) return false;
 
   TLorentzVector Pnu = event->GetHMISParticle(14)->fP;
   TLorentzVector Pmu = event->GetHMFSParticle(13)->fP;
 
   double CosThetaMu = cos(Pnu.Vect().Angle(Pmu.Vect()));
   double p_mu = Pmu.Vect().Mag();
 
   // If we're doing a restricted phase space, Analysis II asks for:
   // Cos(theta_mu) > 0.0 and p_mu > 200 MeV
   if (forwardgoing) {
     if (CosThetaMu < 0.0 || p_mu < 200) return false;
   }
 
   return true;
 }
 
 bool isT2K_CC0pi1p(FitEvent *event, double EnuMin, double EnuMax) {
 
   // Require a numu CC0pi event
   if (!isCC0pi(event, 14, EnuMin, EnuMax)) return false;
 
   // Require at least one FS proton
   if (event->NumFSParticle(2212) == 0) return false;
 
   TLorentzVector pnu = event->GetHMISParticle(14)->fP;
   TLorentzVector pmu = event->GetHMFSParticle(13)->fP;
   TLorentzVector pp  = event->GetHMFSParticle(2212)->fP;
 
 
   // Proton phase space
   if (pp.Vect().Mag() < 500) {
     return false;
   }
 
   //Need exactly one proton with 500 MeV or more momentum
   std::vector<FitParticle*> protons = event->GetAllFSProton();
   int nProtonsAboveThresh=0;
   for(int i=0; i<protons.size(); i++){
     if(protons[i]->p()>500) nProtonsAboveThresh++;
   }
   if(nProtonsAboveThresh!=1) return false;
 
   return true;
 }
 
 
 //CC0pi antinu in the P0D - TN328
 bool isT2K_CC0piAnuP0D(FitEvent *event, double EnuMin, double EnuMax) {
 
   // Require a anumu CC0pi event
   if (!isCC0pi(event, -14, EnuMin, EnuMax)) return false;
 
 
   TLorentzVector pnu = event->GetHMISParticle(-14)->fP;
   TLorentzVector pmu = event->GetHMFSParticle(-13)->fP;
   double Pmu = pmu.Vect().Mag();
   double CosThetaMu = cos(pnu.Vect().Angle(pmu.Vect()));
   // Muon phase space
   if (Pmu < 400 || Pmu > 3410) return false;
   if (Pmu < 530 && CosThetaMu<0.85) return false;
   if (Pmu < 670 && CosThetaMu<0.88) return false;
   if (Pmu < 800 && CosThetaMu<0.9) return false;
   if (Pmu < 1000 && CosThetaMu<0.91) return false;
   if (Pmu < 1380 && CosThetaMu<0.92) return false;
   if (Pmu < 2010 && CosThetaMu<0.95) return false;
 
  
   return true;
 }
 
 bool isT2K_CC0piNp(FitEvent *event, double EnuMin, double EnuMax) {
 
   // Require a numu CC0pi event
   if (!isCC0pi(event, 14, EnuMin, EnuMax)) return false;
 
   // Require at least one FS proton
   if (event->NumFSParticle(2212) == 0) return false;
 
   TLorentzVector pnu = event->GetHMISParticle(14)->fP;
   TLorentzVector pmu = event->GetHMFSParticle(13)->fP;
   TLorentzVector pp  = event->GetHMFSParticle(2212)->fP;
 
-
   // Proton phase space
   if (pp.Vect().Mag() < 500) {
     return false;
   }
 
   //Need exactly one proton with 500 MeV or more momentum
   std::vector<FitParticle*> protons = event->GetAllFSProton();
   int nProtonsAboveThresh=0;
   for(int i=0; i<protons.size(); i++){
     if(protons[i]->p()>500) nProtonsAboveThresh++;
   }
   if(nProtonsAboveThresh<2) return false;
 
   return true;
 }
 
 bool isT2K_CC0pi0p(FitEvent *event, double EnuMin, double EnuMax) {
 
   // Require a numu CC0pi event
   if (!isCC0pi(event, 14, EnuMin, EnuMax)) return false;
 
   // Require at least one FS proton
   if (event->NumFSParticle(2212) == 0) return false;
 
   TLorentzVector pnu = event->GetHMISParticle(14)->fP;
   TLorentzVector pmu = event->GetHMFSParticle(13)->fP;
   TLorentzVector pp  = event->GetHMFSParticle(2212)->fP;
 
 
   // Proton phase space
   if (pp.Vect().Mag() > 500) {
     return false;
   }
 
   return true;
 }
 
 
 bool isT2K_CC0pi_STV(FitEvent *event, double EnuMin, double EnuMax) {
 
   // Require a numu CC0pi event
   if (!isCC0pi(event, 14, EnuMin, EnuMax)) return false;
 
   // Require at least one FS proton
   if (event->NumFSParticle(2212) == 0) return false;
 
   TLorentzVector pnu = event->GetHMISParticle(14)->fP;
   TLorentzVector pmu = event->GetHMFSParticle(13)->fP;
   TLorentzVector pp  = event->GetHMFSParticle(2212)->fP;
 
   // Muon phase space
   // Pmu > 250 MeV, cos(theta_mu) > -0.6 (Sweet phase space!)
   if ((pmu.Vect().Mag() < 250) || cos(pnu.Vect().Angle(pmu.Vect())) < -0.6) {
     return false;
   }
 
   // Proton phase space
   // Pprot > 450 MeV, cos(theta_proton) > 0.4
   if ((pp.Vect().Mag() < 450) || (pp.Vect().Mag() > 1E3) ||
       (cos(pnu.Vect().Angle(pp.Vect())) < 0.4)) {
     return false;
   }
 
   return true;
 }
 
 bool isT2K_CC0pi_ifk(FitEvent *event, double EnuMin, double EnuMax) {
 
   // Require a numu CC0pi event
   if (!isCC0pi(event, 14, EnuMin, EnuMax)) return false;
 
   // Require at least one FS proton
   if (event->NumFSParticle(2212) == 0) return false;
 
   TLorentzVector pnu = event->GetHMISParticle(14)->fP;
   TLorentzVector pmu = event->GetHMFSParticle(13)->fP;
   TLorentzVector pp  = event->GetHMFSParticle(2212)->fP;
 
   // Proton phase space
   // Pprot > 450 MeV, cos(theta_proton) > 0.4
   if ((pp.Vect().Mag() < 450) || (cos(pnu.Vect().Angle(pp.Vect())) < 0.4)) {
     return false;
   }
 
   return true;
 }
 
 bool isT2K_CC0pi_1bin(FitEvent *event, double EnuMin, double EnuMax) {
 
   // Require a numu CC0pi event
   if (!isCC0pi(event, 14, EnuMin, EnuMax)) return false;
 
   // Require at least one FS proton
   if (event->NumFSParticle(2212) == 0) return false;
 
   TLorentzVector pnu = event->GetHMISParticle(14)->fP;
   TLorentzVector pmu = event->GetHMFSParticle(13)->fP;
   TLorentzVector pp  = event->GetHMFSParticle(2212)->fP;
 
   // Muon phase space
   //if ((pmu.Vect().Mag() < 250) || cos(pnu.Vect().Angle(pmu.Vect())) < -0.6) {
   //  return false;
   //}
 
   // Proton phase space
   if ((pp.Vect().Mag() < 450) || (cos(pnu.Vect().Angle(pp.Vect())) < 0.4)) {
     return false;
   }
 
   return true;
 }
 
 }
diff --git a/src/Utils/PlotUtils.cxx b/src/Utils/PlotUtils.cxx
index 40d2f13..47942e6 100644
--- a/src/Utils/PlotUtils.cxx
+++ b/src/Utils/PlotUtils.cxx
@@ -1,1029 +1,1033 @@
 // Copyright 2016 L. Pickering, P Stowell, R. Terri, C. Wilkinson, C. Wret
 
 /*******************************************************************************
 *    This file is part of NUISANCE.
 *
 *    NUISANCE is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    NUISANCE is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with NUISANCE.  If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/
 
 #include "PlotUtils.h"
 #include "FitEvent.h"
 #include "StatUtils.h"
 
 // MOVE TO MB UTILS!
 // This function is intended to be modified to enforce a consistent masking for
 // all models.
 TH2D* PlotUtils::SetMaskHist(std::string type, TH2D* data) {
   TH2D* fMaskHist = (TH2D*)data->Clone("fMaskHist");
 
   for (int xBin = 0; xBin < fMaskHist->GetNbinsX(); ++xBin) {
     for (int yBin = 0; yBin < fMaskHist->GetNbinsY(); ++yBin) {
       if (data->GetBinContent(xBin + 1, yBin + 1) == 0)
         fMaskHist->SetBinContent(xBin + 1, yBin + 1, 0);
       else
         fMaskHist->SetBinContent(xBin + 1, yBin + 1, 0.5);
 
       if (!type.compare("MB_numu_2D")) {
         if (yBin == 19 && xBin < 8)
           fMaskHist->SetBinContent(xBin + 1, yBin + 1, 1.0);
       } else {
         if (yBin == 19 && xBin < 11)
           fMaskHist->SetBinContent(xBin + 1, yBin + 1, 1.0);
       }
       if (yBin == 18 && xBin < 3)
         fMaskHist->SetBinContent(xBin + 1, yBin + 1, 1.0);
       if (yBin == 17 && xBin < 2)
         fMaskHist->SetBinContent(xBin + 1, yBin + 1, 1.0);
       if (yBin == 16 && xBin < 1)
         fMaskHist->SetBinContent(xBin + 1, yBin + 1, 1.0);
     }
   }
 
   return fMaskHist;
 };
 
 // MOVE TO GENERAL UTILS?
 bool PlotUtils::CheckObjectWithName(TFile* inFile, std::string substring) {
   TIter nextkey(inFile->GetListOfKeys());
   TKey* key;
 
   while ((key = (TKey*)nextkey())) {
     std::string test(key->GetName());
     if (test.find(substring) != std::string::npos) return true;
   }
   return false;
 };
 
 // MOVE TO GENERAL UTILS?
 std::string PlotUtils::GetObjectWithName(TFile* inFile, std::string substring) {
   TIter nextkey(inFile->GetListOfKeys());
   TKey* key;
   std::string output = "";
 
   while ((key = (TKey*)nextkey())) {
     std::string test(key->GetName());
     if (test.find(substring) != std::string::npos) output = test;
   }
 
   return output;
 };
 
 void PlotUtils::CreateNeutModeArray(TH1* hist, TH1* neutarray[]) {
   for (int i = 0; i < 60; i++) {
     neutarray[i] = (TH1*)hist->Clone(Form("%s_NMODE_%i", hist->GetName(), i));
   }
   return;
 };
 
 void PlotUtils::DeleteNeutModeArray(TH1* neutarray[]) {
   for (int i = 0; i < 60; i++) {
     delete neutarray[i];
   }
   return;
 };
 
 void PlotUtils::FillNeutModeArray(TH1D* hist[], int mode, double xval,
                                   double weight) {
   if (abs(mode) > 60) return;
   hist[abs(mode)]->Fill(xval, weight);
   return;
 };
 
 void PlotUtils::FillNeutModeArray(TH2D* hist[], int mode, double xval,
                                   double yval, double weight) {
   if (abs(mode) > 60) return;
   hist[abs(mode)]->Fill(xval, yval, weight);
   return;
 };
 
 THStack PlotUtils::GetNeutModeStack(std::string title, TH1* ModeStack[],
                                     int option) {
   (void)option;
   THStack allmodes = THStack(title.c_str(), title.c_str());
 
   for (int i = 0; i < 60; i++) {
     allmodes.Add(ModeStack[i]);
   }
 
   // Credit to Clarence for copying all this out.
 
   // CC
   ModeStack[1]->SetTitle("CCQE");
   ModeStack[1]->SetFillColor(kBlue);
   // ModeStack[1]->SetFillStyle(3444);
   ModeStack[1]->SetLineColor(kBlue);
   ModeStack[2]->SetTitle("2p/2h Nieves");
   ModeStack[2]->SetFillColor(kRed);
   // ModeStack[2]->SetFillStyle(3344);
   ModeStack[2]->SetLineColor(kRed);
 
   // ModeStack[11]->SetTitle("#it{#nu + p #rightarrow l^{-} + p + #pi^{+}}");
   ModeStack[11]->SetTitle("CC1#pi^{+} on p");
   ModeStack[11]->SetFillColor(kGreen);
   // ModeStack[11]->SetFillStyle(3004);
   ModeStack[11]->SetLineColor(kGreen);
   // ModeStack[12]->SetTitle("#it{#nu + n #rightarrow l^{-} + p + #pi^{0}}");
   ModeStack[12]->SetTitle("CC1#pi^{0} on n");
   ModeStack[12]->SetFillColor(kGreen + 3);
   // ModeStack[12]->SetFillStyle(3005);
   ModeStack[12]->SetLineColor(kGreen);
   // ModeStack[13]->SetTitle("#it{#nu + n #rightarrow l^{-} + n + #pi^{+}}");
   ModeStack[13]->SetTitle("CC1#pi^{+} on n");
   ModeStack[13]->SetFillColor(kGreen - 2);
   // ModeStack[13]->SetFillStyle(3004);
   ModeStack[13]->SetLineColor(kGreen);
 
   ModeStack[16]->SetTitle("CC coherent");
   ModeStack[16]->SetFillColor(kBlue);
   // ModeStack[16]->SetFillStyle(3644);
   ModeStack[16]->SetLineColor(kBlue);
 
   // ModeStack[17]->SetTitle("#it{#nu + n #rightarrow l^{-} + p + #gamma}");
   ModeStack[17]->SetTitle("CC1#gamma");
   ModeStack[17]->SetFillColor(kMagenta);
   // ModeStack[17]->SetFillStyle(3001);
   ModeStack[17]->SetLineColor(kMagenta);
 
   ModeStack[21]->SetTitle("Multi #pi (1.3 < W < 2.0)");
   ModeStack[21]->SetFillColor(kYellow);
   // ModeStack[21]->SetFillStyle(3005);
   ModeStack[21]->SetLineColor(kYellow);
 
   // ModeStack[22]->SetTitle("#it{#nu + n #rightarrow l^{-} + p + #eta^{0}}");
   ModeStack[22]->SetTitle("CC1#eta^{0} on n");
   ModeStack[22]->SetFillColor(kYellow - 2);
   // ModeStack[22]->SetFillStyle(3013);
   ModeStack[22]->SetLineColor(kYellow - 2);
   // ModeStack[23]->SetTitle("#it{#nu + n #rightarrow l^{-} + #Lambda +
   // K^{+}}");
   ModeStack[23]->SetTitle("CC1#Labda1K^{+}");
   ModeStack[23]->SetFillColor(kYellow - 6);
   // ModeStack[23]->SetFillStyle(3013);
   ModeStack[23]->SetLineColor(kYellow - 6);
 
   ModeStack[26]->SetTitle("DIS (W > 2.0)");
   ModeStack[26]->SetFillColor(kRed);
   // ModeStack[26]->SetFillStyle(3006);
   ModeStack[26]->SetLineColor(kRed);
 
   // NC
   // ModeStack[31]->SetTitle("#it{#nu + n #rightarrow #nu + n + #pi^{0}}");
   ModeStack[31]->SetTitle("NC1#pi^{0} on n");
   ModeStack[31]->SetFillColor(kBlue);
   // ModeStack[31]->SetFillStyle(3004);
   ModeStack[31]->SetLineColor(kBlue);
   // ModeStack[32]->SetTitle("#it{#nu + p #rightarrow #nu + p + #pi^{0}}");
   ModeStack[32]->SetTitle("NC1#pi^{0} on p");
   ModeStack[32]->SetFillColor(kBlue + 3);
   // ModeStack[32]->SetFillStyle(3004);
   ModeStack[32]->SetLineColor(kBlue + 3);
   // ModeStack[33]->SetTitle("#it{#nu + n #rightarrow #nu + p + #pi^{-}}");
   ModeStack[33]->SetTitle("NC1#pi^{-} on n");
   ModeStack[33]->SetFillColor(kBlue - 2);
   // ModeStack[33]->SetFillStyle(3005);
   ModeStack[33]->SetLineColor(kBlue - 2);
   // ModeStack[34]->SetTitle("#it{#nu + p #rightarrow #nu + n + #pi^{+}}");
   ModeStack[34]->SetTitle("NC1#pi^{+} on p");
   ModeStack[34]->SetFillColor(kBlue - 8);
   // ModeStack[34]->SetFillStyle(3005);
   ModeStack[34]->SetLineColor(kBlue - 8);
 
   ModeStack[36]->SetTitle("NC Coherent");
   ModeStack[36]->SetFillColor(kBlue + 8);
   // ModeStack[36]->SetFillStyle(3644);
   ModeStack[36]->SetLineColor(kBlue + 8);
 
   // ModeStack[38]->SetTitle("#it{#nu + n #rightarrow #nu + n + #gamma}");
   ModeStack[38]->SetTitle("NC1#gamma on n");
   ModeStack[38]->SetFillColor(kMagenta);
   // ModeStack[38]->SetFillStyle(3001);
   ModeStack[38]->SetLineColor(kMagenta);
   // ModeStack[39]->SetTitle("#it{#nu + p #rightarrow #nu + p + #gamma}");
   ModeStack[39]->SetTitle("NC1#gamma on p");
   ModeStack[39]->SetFillColor(kMagenta - 10);
   // ModeStack[39]->SetFillStyle(3001);
   ModeStack[39]->SetLineColor(kMagenta - 10);
 
   ModeStack[41]->SetTitle("Multi #pi (1.3 < W < 2.0)");
   ModeStack[41]->SetFillColor(kBlue - 10);
   // ModeStack[41]->SetFillStyle(3005);
   ModeStack[41]->SetLineColor(kBlue - 10);
 
   // ModeStack[42]->SetTitle("#it{#nu + n #rightarrow #nu + n + #eta^{0}}");
   ModeStack[42]->SetTitle("NC1#eta^{0} on n");
   ModeStack[42]->SetFillColor(kYellow - 2);
   // ModeStack[42]->SetFillStyle(3013);
   ModeStack[42]->SetLineColor(kYellow - 2);
   // ModeStack[43]->SetTitle("#it{#nu + p #rightarrow #nu + p + #eta^{0}}");
   ModeStack[43]->SetTitle("NC1#eta^{0} on p");
   ModeStack[43]->SetFillColor(kYellow - 4);
   // ModeStack[43]->SetFillStyle(3013);
   ModeStack[43]->SetLineColor(kYellow - 4);
 
   // ModeStack[44]->SetTitle("#it{#nu + n #rightarrow #nu + #Lambda + K^{0}}");
   ModeStack[44]->SetTitle("NC1#Lambda1K^{0} on n");
   ModeStack[44]->SetFillColor(kYellow - 6);
   // ModeStack[44]->SetFillStyle(3014);
   ModeStack[44]->SetLineColor(kYellow - 6);
   // ModeStack[45]->SetTitle("#it{#nu + p #rightarrow #nu + #Lambda + K^{+}}");
   ModeStack[45]->SetTitle("NC1#Lambda1K^{+}");
   ModeStack[45]->SetFillColor(kYellow - 10);
   // ModeStack[45]->SetFillStyle(3014);
   ModeStack[45]->SetLineColor(kYellow - 10);
 
   ModeStack[46]->SetTitle("DIS (W > 2.0)");
   ModeStack[46]->SetFillColor(kRed);
   // ModeStack[46]->SetFillStyle(3006);
   ModeStack[46]->SetLineColor(kRed);
 
   // ModeStack[51]->SetTitle("#it{#nu + p #rightarrow #nu + p}");
   ModeStack[51]->SetTitle("NC on p");
   ModeStack[51]->SetFillColor(kBlack);
   // ModeStack[51]->SetFillStyle(3444);
   ModeStack[51]->SetLineColor(kBlack);
   // ModeStack[52]->SetTitle("#it{#nu + n #rightarrow #nu + n}");
   ModeStack[52]->SetTitle("NC on n");
   ModeStack[52]->SetFillColor(kGray);
   // ModeStack[52]->SetFillStyle(3444);
   ModeStack[52]->SetLineColor(kGray);
 
   return allmodes;
 };
 
 TLegend PlotUtils::GenerateStackLegend(THStack stack, int xlow, int ylow,
                                        int xhigh, int yhigh) {
   TLegend leg = TLegend(xlow, ylow, xhigh, yhigh);
 
   TObjArray* histarray = stack.GetStack();
 
   int nhist = histarray->GetEntries();
   for (int i = 0; i < nhist; i++) {
     TH1* hist = (TH1*)(histarray->At(i));
     leg.AddEntry((hist), ((TH1*)histarray->At(i))->GetTitle(), "fl");
   }
 
   leg.SetName(Form("%s_LEG", stack.GetName()));
 
   return leg;
 };
 
 void PlotUtils::ScaleNeutModeArray(TH1* hist[], double factor,
                                    std::string option) {
   for (int i = 0; i < 60; i++) {
     if (hist[i]) hist[i]->Scale(factor, option.c_str());
   }
 
   return;
 };
 
 void PlotUtils::ResetNeutModeArray(TH1* hist[]) {
   for (int i = 0; i < 60; i++) {
     if (hist[i]) hist[i]->Reset();
   }
 
   return;
 };
 
 //********************************************************************
 // This assumes the Enu axis is the x axis, as is the case for MiniBooNE 2D
 // distributions
 void PlotUtils::FluxUnfoldedScaling(TH2D* fMCHist, TH1D* fhist, TH1D* ehist,
                                     double scalefactor) {
   //********************************************************************
 
   // Make clones to avoid changing stuff
   TH1D* eventhist = (TH1D*)ehist->Clone();
   TH1D* fFluxHist = (TH1D*)fhist->Clone();
 
   // Undo width integral in SF
   fMCHist->Scale(scalefactor /
                  eventhist->Integral(1, eventhist->GetNbinsX() + 1, "width"));
 
   // Standardise The Flux
   eventhist->Scale(1.0 / fFluxHist->Integral());
   fFluxHist->Scale(1.0 / fFluxHist->Integral());
 
   // Do interpolation for 2D plots?
   // fFluxHist = PlotUtils::InterpolateFineHistogram(fFluxHist,100,"width");
   // eventhist = PlotUtils::InterpolateFineHistogram(eventhist,100,"width");
 
   // eventhist->Scale(1.0/fFluxHist->Integral());
   // fFluxHist->Scale(1.0/fFluxHist->Integral());
 
   // Scale fMCHist by eventhist integral
   fMCHist->Scale(eventhist->Integral(1, eventhist->GetNbinsX() + 1));
 
   // Now Get a flux PDF assuming X axis is Enu
   TH1D* pdfflux = (TH1D*)fMCHist->ProjectionX()->Clone();
   //  pdfflux->Write( (std::string(fMCHist->GetName()) + "_PROJX").c_str());
   pdfflux->Reset();
 
   // Awful MiniBooNE Check for the time being
   bool ismb =
       std::string(fMCHist->GetName()).find("MiniBooNE") != std::string::npos;
 
   for (int i = 0; i < pdfflux->GetNbinsX(); i++) {
     double Ml = pdfflux->GetXaxis()->GetBinLowEdge(i + 1);
     double Mh = pdfflux->GetXaxis()->GetBinLowEdge(i + 2);
     // double Mc = pdfflux->GetXaxis()->GetBinCenter(i+1);
     // double Mw = pdfflux->GetBinWidth(i+1);
     double fluxint = 0.0;
 
     // Scaling to match flux for MB
     if (ismb) {
       Ml /= 1.E3;
       Mh /= 1.E3;
       //  Mc /= 1.E3;
       //  Mw /= 1.E3;
     }
 
     for (int j = 0; j < fFluxHist->GetNbinsX(); j++) {
       // double Fc = fFluxHist->GetXaxis()->GetBinCenter(j+1);
       double Fl = fFluxHist->GetXaxis()->GetBinLowEdge(j + 1);
       double Fh = fFluxHist->GetXaxis()->GetBinLowEdge(j + 2);
       double Fe = fFluxHist->GetBinContent(j + 1);
       double Fw = fFluxHist->GetXaxis()->GetBinWidth(j + 1);
 
       if (Fl >= Ml and Fh <= Mh) {
         fluxint += Fe;
       } else if (Fl < Ml and Fl < Mh and Fh > Ml and Fh < Mh) {
         fluxint += Fe * (Fh - Ml) / Fw;
       } else if (Fh > Mh and Fl < Mh and Fh > Ml and Fl > Ml) {
         fluxint += Fe * (Mh - Fl) / Fw;
       } else if (Ml >= Fl and Mh <= Fh) {
         fluxint += Fe * (Mh - Ml) / Fw;
       } else {
         continue;
       }
     }
 
     pdfflux->SetBinContent(i + 1, fluxint);
   }
 
   for (int i = 0; i < fMCHist->GetNbinsX(); i++) {
     for (int j = 0; j < fMCHist->GetNbinsY(); j++) {
       if (pdfflux->GetBinContent(i + 1) == 0.0) continue;
 
       double binWidth = fMCHist->GetYaxis()->GetBinLowEdge(j + 2) -
                         fMCHist->GetYaxis()->GetBinLowEdge(j + 1);
       fMCHist->SetBinContent(i + 1, j + 1,
                              fMCHist->GetBinContent(i + 1, j + 1) /
                                  pdfflux->GetBinContent(i + 1) / binWidth);
       fMCHist->SetBinError(i + 1, j + 1, fMCHist->GetBinError(i + 1, j + 1) /
                                              pdfflux->GetBinContent(i + 1) /
                                              binWidth);
     }
   }
 
   delete eventhist;
   delete fFluxHist;
 
   return;
 };
 
 TH1D* PlotUtils::InterpolateFineHistogram(TH1D* hist, int res,
                                           std::string opt) {
   int nbins = hist->GetNbinsX();
   double elow = hist->GetXaxis()->GetBinLowEdge(1);
   double ehigh = hist->GetXaxis()->GetBinLowEdge(nbins + 1);
   bool width = true;  // opt.find("width") != std::string::npos;
 
   TH1D* fine = new TH1D("fine", "fine", nbins * res, elow, ehigh);
 
   TGraph* temp = new TGraph();
 
   for (int i = 0; i < nbins; i++) {
     double E = hist->GetXaxis()->GetBinCenter(i + 1);
     double C = hist->GetBinContent(i + 1);
     double W = hist->GetXaxis()->GetBinWidth(i + 1);
     if (!width) W = 1.0;
 
     if (W != 0.0) temp->SetPoint(temp->GetN(), E, C / W);
   }
 
   for (int i = 0; i < fine->GetNbinsX(); i++) {
     double E = fine->GetXaxis()->GetBinCenter(i + 1);
     double W = fine->GetBinWidth(i + 1);
     if (!width) W = 1.0;
 
     fine->SetBinContent(i + 1, temp->Eval(E, 0, "S") * W);
   }
 
   fine->Scale(hist->Integral(1, hist->GetNbinsX() + 1) /
               fine->Integral(1, fine->GetNbinsX() + 1));
   std::cout << "Interpolation Difference = "
             << fine->Integral(1, fine->GetNbinsX() + 1) << "/"
             << hist->Integral(1, hist->GetNbinsX() + 1) << std::endl;
 
   return fine;
 }
 
 //********************************************************************
 // This interpolates the flux by a TGraph instead of requiring the flux and MC
 // flux to have the same binning
 void PlotUtils::FluxUnfoldedScaling(TH1D* mcHist, TH1D* fhist, TH1D* ehist,
                                     double scalefactor, int nevents) {
   //********************************************************************
 
   TH1D* eventhist = (TH1D*)ehist->Clone();
   TH1D* fFluxHist = (TH1D*)fhist->Clone();
 
   if (FitPar::Config().GetParB("save_flux_debug")) {
     std::string name = std::string(mcHist->GetName());
 
     mcHist->Write((name + "_UNF_MC").c_str());
     fFluxHist->Write((name + "_UNF_FLUX").c_str());
     eventhist->Write((name + "_UNF_EVT").c_str());
 
     TH1D* scalehist = new TH1D("scalehist", "scalehist", 1, 0.0, 1.0);
     scalehist->SetBinContent(1, scalefactor);
     scalehist->SetBinContent(2, nevents);
 
     scalehist->Write((name + "_UNF_SCALE").c_str());
   }
 
   // Undo width integral in SF
   mcHist->Scale(scalefactor /
                 eventhist->Integral(1, eventhist->GetNbinsX() + 1, "width"));
 
   // Standardise The Flux
   eventhist->Scale(1.0 / fFluxHist->Integral());
   fFluxHist->Scale(1.0 / fFluxHist->Integral());
 
   // Scale mcHist by eventhist integral
   mcHist->Scale(eventhist->Integral(1, eventhist->GetNbinsX() + 1));
 
   // Now Get a flux PDF
   TH1D* pdfflux = (TH1D*)mcHist->Clone();
   pdfflux->Reset();
 
   for (int i = 0; i < mcHist->GetNbinsX(); i++) {
     double Ml = mcHist->GetXaxis()->GetBinLowEdge(i + 1);
     double Mh = mcHist->GetXaxis()->GetBinLowEdge(i + 2);
     // double Mc = mcHist->GetXaxis()->GetBinCenter(i+1);
     // double Me = mcHist->GetBinContent(i+1);
     // double Mw = mcHist->GetBinWidth(i+1);
     double fluxint = 0.0;
 
     for (int j = 0; j < fFluxHist->GetNbinsX(); j++) {
       // double Fc = fFluxHist->GetXaxis()->GetBinCenter(j+1);
       double Fl = fFluxHist->GetXaxis()->GetBinLowEdge(j + 1);
       double Fh = fFluxHist->GetXaxis()->GetBinLowEdge(j + 2);
       double Fe = fFluxHist->GetBinContent(j + 1);
       double Fw = fFluxHist->GetXaxis()->GetBinWidth(j + 1);
 
       if (Fl >= Ml and Fh <= Mh) {
         fluxint += Fe;
       } else if (Fl < Ml and Fl < Mh and Fh > Ml and Fh < Mh) {
         fluxint += Fe * (Fh - Ml) / Fw;
       } else if (Fh > Mh and Fl < Mh and Fh > Ml and Fl > Ml) {
         fluxint += Fe * (Mh - Fl) / Fw;
       } else if (Ml >= Fl and Mh <= Fh) {
         fluxint += Fe * (Mh - Ml) / Fw;
       } else {
         continue;
       }
     }
 
     pdfflux->SetBinContent(i + 1, fluxint);
   }
 
   // Scale MC hist by pdfflux
   for (int i = 0; i < mcHist->GetNbinsX(); i++) {
     if (pdfflux->GetBinContent(i + 1) == 0.0) continue;
 
     mcHist->SetBinContent(
         i + 1, mcHist->GetBinContent(i + 1) / pdfflux->GetBinContent(i + 1));
     mcHist->SetBinError(
         i + 1, mcHist->GetBinError(i + 1) / pdfflux->GetBinContent(i + 1));
   }
 
   delete eventhist;
   delete fFluxHist;
 
   return;
 };
 
 // MOVE TO GENERAL UTILS
 //********************************************************************
 void PlotUtils::Set2DHistFromText(std::string dataFile, TH2* hist, double norm,
                                   bool skipbins) {
   //********************************************************************
 
   std::string line;
   std::ifstream data(dataFile.c_str(), std::ifstream::in);
 
   int yBin = 0;
   while (std::getline(data >> std::ws, line, '\n')) {
     std::vector<double> entries = GeneralUtils::ParseToDbl(line, " ");
 
     // Loop over entries and insert them into the histogram
     for (uint xBin = 0; xBin < entries.size(); xBin++) {
       if (!skipbins or entries[xBin] != -1.0)
         hist->SetBinContent(xBin + 1, yBin + 1, entries[xBin] * norm);
     }
     yBin++;
   }
 
   return;
 }
 
 // MOVE TO GENERAL UTILS
 TH1D* PlotUtils::GetTH1DFromFile(std::string dataFile, std::string title,
                                  std::string fPlotTitles,
                                  std::string alt_name) {
   TH1D* tempPlot;
 
   // If format is a root file
   if (dataFile.find(".root") != std::string::npos) {
     TFile* temp_infile = new TFile(dataFile.c_str(), "READ");
     tempPlot = (TH1D*)temp_infile->Get(title.c_str());
     tempPlot->SetDirectory(0);
 
     temp_infile->Close();
     delete temp_infile;
 
     // Else its a space seperated txt file
   } else {
     // Make a TGraph Errors
     TGraphErrors* gr = new TGraphErrors(dataFile.c_str(), "%lg %lg %lg");
     if (gr->IsZombie()) {
       exit(-1);
     }
     double* bins = gr->GetX();
     double* values = gr->GetY();
     double* errors = gr->GetEY();
     int npoints = gr->GetN();
 
     // Fill the histogram from it
     tempPlot = new TH1D(title.c_str(), title.c_str(), npoints - 1, bins);
 
     for (int i = 0; i < npoints; ++i) {
       tempPlot->SetBinContent(i + 1, values[i]);
 
       // If only two columns are present in the input file, use the sqrt(values)
       // as the error
       // equivalent to assuming that the error is statistical
       if (!errors[i])
         tempPlot->SetBinError(i + 1, sqrt(values[i]));
       else
         tempPlot->SetBinError(i + 1, errors[i]);
     }
 
     delete gr;
   }
 
   // Allow alternate naming for root files
   if (!alt_name.empty()) {
     tempPlot->SetNameTitle(alt_name.c_str(), alt_name.c_str());
   }
 
   // Allow alternate axis titles
   if (!fPlotTitles.empty()) {
     tempPlot->SetNameTitle(
         tempPlot->GetName(),
         (std::string(tempPlot->GetTitle()) + fPlotTitles).c_str());
   }
 
   return tempPlot;
 };
 
 TH1D* PlotUtils::GetRatioPlot(TH1D* hist1, TH1D* hist2) {
   // make copy of first hist
   TH1D* new_hist = (TH1D*)hist1->Clone();
 
   // Do bins and errors ourselves as scales can go awkward
   for (int i = 0; i < new_hist->GetNbinsX(); i++) {
     if (hist2->GetBinContent(i + 1) == 0.0) {
       new_hist->SetBinContent(i + 1, 0.0);
     }
 
     new_hist->SetBinContent(
         i + 1, hist1->GetBinContent(i + 1) / hist2->GetBinContent(i + 1));
     new_hist->SetBinError(
         i + 1, hist1->GetBinError(i + 1) / hist2->GetBinContent(i + 1));
   }
 
   return new_hist;
 };
 
 TH1D* PlotUtils::GetRenormalisedPlot(TH1D* hist1, TH1D* hist2) {
   // make copy of first hist
   TH1D* new_hist = (TH1D*)hist1->Clone();
 
   if (hist1->Integral("width") == 0 or hist2->Integral("width") == 0) {
     new_hist->Reset();
     return new_hist;
   }
 
   Double_t scaleF = hist2->Integral("width") / hist1->Integral("width");
   new_hist->Scale(scaleF);
 
   return new_hist;
 };
 
 TH1D* PlotUtils::GetShapePlot(TH1D* hist1) {
   // make copy of first hist
   TH1D* new_hist = (TH1D*)hist1->Clone();
 
   if (hist1->Integral("width") == 0) {
     new_hist->Reset();
     return new_hist;
   }
 
   Double_t scaleF1 = 1.0 / hist1->Integral("width");
 
   new_hist->Scale(scaleF1);
 
   return new_hist;
 };
 
 TH1D* PlotUtils::GetShapeRatio(TH1D* hist1, TH1D* hist2) {
   TH1D* new_hist1 = GetShapePlot(hist1);
   TH1D* new_hist2 = GetShapePlot(hist2);
 
   // Do bins and errors ourselves as scales can go awkward
   for (int i = 0; i < new_hist1->GetNbinsX(); i++) {
     if (hist2->GetBinContent(i + 1) == 0) {
       new_hist1->SetBinContent(i + 1, 0.0);
     }
 
     new_hist1->SetBinContent(i + 1, new_hist1->GetBinContent(i + 1) /
                                         new_hist2->GetBinContent(i + 1));
     new_hist1->SetBinError(
         i + 1, new_hist1->GetBinError(i + 1) / new_hist2->GetBinContent(i + 1));
   }
 
   delete new_hist2;
 
   return new_hist1;
 };
 
 TH2D* PlotUtils::GetCovarPlot(TMatrixDSym* cov, std::string name,
                               std::string title) {
   TH2D* CovarPlot;
 
   if (cov)
     CovarPlot = new TH2D((*cov));
   else
     CovarPlot = new TH2D(name.c_str(), title.c_str(), 1, 0, 1, 1, 0, 1);
 
   CovarPlot->SetName(name.c_str());
   CovarPlot->SetTitle(title.c_str());
 
   return CovarPlot;
 }
 
 TH2D* PlotUtils::GetFullCovarPlot(TMatrixDSym* cov, std::string name) {
   return PlotUtils::GetCovarPlot(
       cov, name + "_COV", name + "_COV;Bins;Bins;Covariance (#times10^{-76})");
 }
 
 TH2D* PlotUtils::GetInvCovarPlot(TMatrixDSym* cov, std::string name) {
   return PlotUtils::GetCovarPlot(
       cov, name + "_INVCOV",
       name + "_INVCOV;Bins;Bins;Inv. Covariance (#times10^{-76})");
 }
 
 TH2D* PlotUtils::GetDecompCovarPlot(TMatrixDSym* cov, std::string name) {
   return PlotUtils::GetCovarPlot(
       cov, name + "_DECCOV",
       name + "_DECCOV;Bins;Bins;Decomp Covariance (#times10^{-76})");
 }
 
 TH1D* PlotUtils::GetTH1DFromRootFile(std::string file, std::string name) {
   if (name.empty()) {
     std::vector<std::string> tempfile = GeneralUtils::ParseToStr(file, ";");
     file = tempfile[0];
     name = tempfile[1];
   }
 
   TFile* rootHistFile = new TFile(file.c_str(), "READ");
   TH1D* tempHist = (TH1D*)rootHistFile->Get(name.c_str())->Clone();
+  if (tempHist == NULL) {
+    ERR(FTL) << "Could not find distribution " << name << " in file " << file << std::endl;
+    throw;
+  }
   tempHist->SetDirectory(0);
 
   rootHistFile->Close();
 
   return tempHist;
 }
 
 TH2D* PlotUtils::GetTH2DFromRootFile(std::string file, std::string name) {
   if (name.empty()) {
     std::vector<std::string> tempfile = GeneralUtils::ParseToStr(file, ";");
     file = tempfile[0];
     name = tempfile[1];
   }
 
   TFile* rootHistFile = new TFile(file.c_str(), "READ");
   TH2D* tempHist = (TH2D*)rootHistFile->Get(name.c_str())->Clone();
   tempHist->SetDirectory(0);
 
   rootHistFile->Close();
   delete rootHistFile;
 
   return tempHist;
 }
 
 TH1* PlotUtils::GetTH1FromRootFile(std::string file, std::string name) {
   if (name.empty()) {
     std::vector<std::string> tempfile = GeneralUtils::ParseToStr(file, ";");
     file = tempfile[0];
     name = tempfile[1];
   }
 
   TFile* rootHistFile = new TFile(file.c_str(), "READ");
   if (!rootHistFile || rootHistFile->IsZombie()) {
     THROW("Couldn't open root file: \"" << file << "\".");
   }
   TH1* tempHist = dynamic_cast<TH1*>(rootHistFile->Get(name.c_str())->Clone());
   if (!tempHist) {
     THROW("Couldn't retrieve: \"" << name << "\" from root file: \"" << file
                                   << "\".");
   }
   tempHist->SetDirectory(0);
 
   rootHistFile->Close();
   delete rootHistFile;
 
   return tempHist;
 }
 
 TGraph* PlotUtils::GetTGraphFromRootFile(std::string file, std::string name) {
   if (name.empty()) {
     std::vector<std::string> tempfile = GeneralUtils::ParseToStr(file, ";");
     file = tempfile[0];
     name = tempfile[1];
   }
 
   TDirectory* olddir = gDirectory;
 
   TFile* rootHistFile = new TFile(file.c_str(), "READ");
   if (!rootHistFile || rootHistFile->IsZombie()) {
     THROW("Couldn't open root file: \"" << file << "\".");
   }
   TDirectory* newdir = gDirectory;
 
   TGraph* temp = dynamic_cast<TGraph*>(rootHistFile->Get(name.c_str())->Clone());
   if (!temp) {
     THROW("Couldn't retrieve: \"" << name << "\" from root file: \"" << file
 	  << "\".");
   }
   newdir->Remove(temp);
   olddir->Append(temp);
   rootHistFile->Close();
   olddir->cd();
   return temp;
 }
 
 
 /// Returns a vector of named TH1*s found in a single input file.
 ///
 /// Expects a descriptor like: file.root[hist1|hist2|...]
 std::vector<TH1*> PlotUtils::GetTH1sFromRootFile(
     std::string const& descriptor) {
   std::vector<std::string> descriptors =
       GeneralUtils::ParseToStr(descriptor, ",");
 
   std::vector<TH1*> hists;
   for (size_t d_it = 0; d_it < descriptors.size(); ++d_it) {
     std::string& d = descriptors[d_it];
 
     std::vector<std::string> fname = GeneralUtils::ParseToStr(d, "[");
     if (!fname.size() || !fname[0].length()) {
       THROW("Couldn't find input file when attempting to parse : \""
             << d << "\". Expected input.root[hist1|hist2|...].");
     }
 
     if (fname[1][fname[1].length() - 1] == ']') {
       fname[1] = fname[1].substr(0, fname[1].length() - 1);
     }
     std::vector<std::string> histnames =
         GeneralUtils::ParseToStr(fname[1], "|");
     if (!histnames.size()) {
       THROW(
           "Couldn't find any histogram name specifiers when attempting to "
           "parse "
           ": \""
           << fname[1] << "\". Expected hist1|hist2|...");
     }
 
     TFile* rootHistFile = new TFile(fname[0].c_str(), "READ");
     if (!rootHistFile || rootHistFile->IsZombie()) {
       THROW("Couldn't open root file: \"" << fname[0] << "\".");
     }
 
     for (size_t i = 0; i < histnames.size(); ++i) {
       TH1* tempHist =
           dynamic_cast<TH1*>(rootHistFile->Get(histnames[i].c_str())->Clone());
       if (!tempHist) {
         THROW("Couldn't retrieve: \"" << histnames[i] << "\" from root file: \""
                                       << fname[0] << "\".");
       }
       tempHist->SetDirectory(0);
       hists.push_back(tempHist);
     }
     rootHistFile->Close();
   }
 
   return hists;
 }
 
 TH2D* PlotUtils::GetTH2DFromTextFile(std::string file) {
   /// Contents should be
   /// Low Edfe
 
   return NULL;
 }
 
 void PlotUtils::AddNeutModeArray(TH1D* hist1[], TH1D* hist2[], double scaling) {
   for (int i = 0; i < 60; i++) {
     if (!hist2[i]) continue;
     if (!hist1[i]) continue;
     hist1[i]->Add(hist2[i], scaling);
   }
   return;
 }
 
 void PlotUtils::ScaleToData(TH1D* data, TH1D* mc, TH1I* mask) {
   double scaleF = GetDataMCRatio(data, mc, mask);
   mc->Scale(scaleF);
 
   return;
 }
 
 void PlotUtils::MaskBins(TH1D* hist, TH1I* mask) {
   for (int i = 0; i < hist->GetNbinsX(); i++) {
     if (mask->GetBinContent(i + 1) <= 0.5) continue;
 
     hist->SetBinContent(i + 1, 0.0);
     hist->SetBinError(i + 1, 0.0);
 
     LOG(REC) << "MaskBins: Set " << hist->GetName() << " Bin " << i + 1
              << " to 0.0 +- 0.0" << std::endl;
   }
 
   return;
 }
 
 void PlotUtils::MaskBins(TH2D* hist, TH2I* mask) {
   for (int i = 0; i < hist->GetNbinsX(); i++) {
     for (int j = 0; j < hist->GetNbinsY(); j++) {
       if (mask->GetBinContent(i + 1, j + 1) <= 0.5) continue;
 
       hist->SetBinContent(i + 1, j + 1, 0.0);
       hist->SetBinError(i + 1, j + 1, 0.0);
 
       LOG(REC) << "MaskBins: Set " << hist->GetName() << " Bin " << i + 1 << " "
                << j + 1 << " to 0.0 +- 0.0" << std::endl;
     }
   }
   return;
 }
 
 double PlotUtils::GetDataMCRatio(TH1D* data, TH1D* mc, TH1I* mask) {
   double rat = 1.0;
 
   TH1D* newmc = (TH1D*)mc->Clone();
   TH1D* newdt = (TH1D*)data->Clone();
 
   if (mask) {
     MaskBins(newmc, mask);
     MaskBins(newdt, mask);
   }
 
   rat = newdt->Integral() / newmc->Integral();
 
   return rat;
 }
 
 TH2D* PlotUtils::GetCorrelationPlot(TH2D* cov, std::string name) {
   TH2D* cor = (TH2D*)cov->Clone();
   cor->Reset();
 
   for (int i = 0; i < cov->GetNbinsX(); i++) {
     for (int j = 0; j < cov->GetNbinsY(); j++) {
       if (cov->GetBinContent(i + 1, i + 1) != 0.0 and
           cov->GetBinContent(j + 1, j + 1) != 0.0)
         cor->SetBinContent(i + 1, j + 1,
                            cov->GetBinContent(i + 1, j + 1) /
                                (sqrt(cov->GetBinContent(i + 1, i + 1) *
                                      cov->GetBinContent(j + 1, j + 1))));
     }
   }
 
   if (!name.empty()) {
     cor->SetNameTitle(name.c_str(), (name + ";;correlation").c_str());
   }
 
   cor->SetMinimum(-1);
   cor->SetMaximum(1);
 
   return cor;
 }
 
 TH2D* PlotUtils::GetDecompPlot(TH2D* cov, std::string name) {
   TMatrixDSym* covarmat = new TMatrixDSym(cov->GetNbinsX());
 
   for (int i = 0; i < cov->GetNbinsX(); i++)
     for (int j = 0; j < cov->GetNbinsY(); j++)
       (*covarmat)(i, j) = cov->GetBinContent(i + 1, j + 1);
 
   TMatrixDSym* decompmat = StatUtils::GetDecomp(covarmat);
 
   TH2D* dec = (TH2D*)cov->Clone();
   for (int i = 0; i < cov->GetNbinsX(); i++)
     for (int j = 0; j < cov->GetNbinsY(); j++)
       dec->SetBinContent(i + 1, j + 1, (*decompmat)(i, j));
 
   delete covarmat;
   delete decompmat;
 
   dec->SetNameTitle(name.c_str(), (name + ";;;decomposition").c_str());
 
   return dec;
 }
 
 TH2D* PlotUtils::MergeIntoTH2D(TH1D* xhist, TH1D* yhist, std::string zname) {
   std::vector<double> xedges, yedges;
   for (int i = 0; i < xhist->GetNbinsX() + 2; i++) {
     xedges.push_back(xhist->GetXaxis()->GetBinLowEdge(i + 1));
   }
   for (int i = 0; i < yhist->GetNbinsX() + 2; i++) {
     yedges.push_back(yhist->GetXaxis()->GetBinLowEdge(i + 1));
   }
 
   int nbinsx = xhist->GetNbinsX();
   int nbinsy = yhist->GetNbinsX();
 
   std::string name =
       std::string(xhist->GetName()) + "_vs_" + std::string(yhist->GetName());
   std::string titles = ";" + std::string(xhist->GetXaxis()->GetTitle()) + ";" +
                        std::string(yhist->GetXaxis()->GetTitle()) + ";" + zname;
 
   TH2D* newplot = new TH2D(name.c_str(), (name + titles).c_str(), nbinsx,
                            &xedges[0], nbinsy, &yedges[0]);
 
   return newplot;
 }
 
 //***************************************************
 void PlotUtils::MatchEmptyBins(TH1D* data, TH1D* mc) {
   //**************************************************
 
   for (int i = 0; i < data->GetNbinsX(); i++) {
     if (data->GetBinContent(i + 1) == 0.0 or data->GetBinError(i + 1) == 0.0)
       mc->SetBinContent(i + 1, 0.0);
   }
 
   return;
 }
 
 //***************************************************
 void PlotUtils::MatchEmptyBins(TH2D* data, TH2D* mc) {
   //**************************************************
 
   for (int i = 0; i < data->GetNbinsX(); i++) {
     for (int j = 0; j < data->GetNbinsY(); j++) {
       if (data->GetBinContent(i + 1, j + 1) == 0.0 or
           data->GetBinError(i + 1, j + 1) == 0.0)
         mc->SetBinContent(i + 1, j + 1, 0.0);
     }
   }
 
   return;
 }
 
 //***************************************************
 TH1D* PlotUtils::GetProjectionX(TH2D* hist, TH2I* mask) {
   //***************************************************
 
   TH2D* maskedhist = StatUtils::ApplyHistogramMasking(hist, mask);
 
   TH1D* hist_X = maskedhist->ProjectionX();
 
   delete maskedhist;
   return hist_X;
 }
 
 //***************************************************
 TH1D* PlotUtils::GetProjectionY(TH2D* hist, TH2I* mask) {
   //***************************************************
 
   TH2D* maskedhist = StatUtils::ApplyHistogramMasking(hist, mask);
 
   TH1D* hist_Y = maskedhist->ProjectionY();
 
   delete maskedhist;
   return hist_Y;
 }