CMS 3D CMS Logo

/data/doxygen/doxygen-1.7.3/gen/CMSSW_4_2_8/src/PhysicsTools/MVAComputer/src/MVAComputer.cc

Go to the documentation of this file.
00001 #include <iostream>
00002 #include <sstream>
00003 #include <fstream>
00004 #include <algorithm>
00005 #include <iterator>
00006 #include <cstddef>
00007 #include <cstring>
00008 #include <vector>
00009 #include <set>
00010 
00011 // ROOT version magic to support TMVA interface changes in newer ROOT   
00012 #include <RVersion.h>
00013 
00014 #include <TBufferFile.h>
00015 #include <TClass.h>
00016 
00017 #include "FWCore/Utilities/interface/Exception.h"
00018 
00019 #include "PhysicsTools/MVAComputer/interface/zstream.h"
00020 
00021 #include "PhysicsTools/MVAComputer/interface/MVAComputer.h"
00022 #include "PhysicsTools/MVAComputer/interface/VarProcessor.h"
00023 #include "PhysicsTools/MVAComputer/interface/Calibration.h"
00024 #include "PhysicsTools/MVAComputer/interface/Variable.h"
00025 #include "PhysicsTools/MVAComputer/interface/AtomicId.h"
00026 
00027 // #define DEBUG_EVAL
00028 
00029 #ifdef DEBUG_EVAL
00030 #       include <Reflex/Tools.h>
00031 #endif
00032 
00033 #define STANDALONE_HEADER "MVAComputer calibration\n"
00034 
00035 namespace PhysicsTools {
00036 
00037 MVAComputer::MVAComputer(const Calibration::MVAComputer *calib) :
00038         nVars(0), output(0)
00039 {
00040         setup(calib);
00041 }
00042 
00043 MVAComputer::MVAComputer(Calibration::MVAComputer *calib, bool owned) :
00044         nVars(0), output(0)
00045 {
00046         if (owned)
00047                 this->owned.reset(calib);
00048         setup(calib);
00049 }
00050 
00051 MVAComputer::MVAComputer(const char *filename) :
00052         nVars(0), output(0), owned(readCalibration(filename))
00053 {
00054         setup(owned.get());
00055 }
00056 
00057 MVAComputer::MVAComputer(std::istream &is) :
00058         nVars(0), output(0), owned(readCalibration(is))
00059 {
00060         setup(owned.get());
00061 }
00062 
00063 void MVAComputer::setup(const Calibration::MVAComputer *calib)
00064 {
00065         nVars = calib->inputSet.size();
00066         output = calib->output;
00067 
00068         std::vector<Variable::Flags> flags(nVars, Variable::FLAG_ALL);
00069         const TrainMVAComputerCalibration *trainCalib =
00070                 dynamic_cast<const TrainMVAComputerCalibration*>(calib);
00071         if (trainCalib)
00072                 trainCalib->initFlags(flags);
00073 
00074         VarProcessor::ConfigCtx config(flags);
00075         std::vector<Calibration::VarProcessor*> processors =
00076                                                         calib->getProcessors();
00077 
00078         for(std::vector<Calibration::VarProcessor*>::const_iterator iter =
00079                                                         processors.begin();
00080             iter != processors.end(); ++iter) {
00081                 std::string name = (*iter)->getInstanceName();
00082                 VarProcessor *processor =
00083                         VarProcessor::create(name.c_str(), *iter, this);
00084                 if (!processor)
00085                         throw cms::Exception("UnknownProcessor")
00086                                 << name << " could not be instantiated."
00087                                 << std::endl;
00088 
00089                 VarProcessor::ConfigCtx::iterator::difference_type pos =
00090                                                 config.end() - config.begin();
00091                 processor->configure(config);
00092                 unsigned int nOutput = (config.end() - config.begin()) - pos;
00093                 if (!nOutput)
00094                         throw cms::Exception("InvalidProcessor")
00095                                 << name << " rejected input variable "
00096                                 "configuration" << std::endl;
00097 
00098                 varProcessors.push_back(Processor(processor, nOutput));
00099         }
00100 
00101         for(VarProcessor::ConfigCtx::iterator iter = config.begin() + nVars;
00102             iter != config.end(); iter++) {
00103                 VarProcessor::Config *origin = &config[iter->origin];
00104                 if (iter->origin >= nVars)
00105                         iter->origin = origin->origin;
00106 
00107                 if (iter->mask & Variable::FLAG_MULTIPLE) {
00108                         iter->mask = (Variable::Flags)(iter->mask &
00109                                                        origin->mask);
00110                         config[iter->origin].origin++;
00111                 }
00112         }
00113 
00114         nVars = config.size();
00115 
00116         if (output >= nVars)
00117                         // FIXME || config[output].mask != Variable::FLAG_NONE)
00118                 throw cms::Exception("InvalidOutput")
00119                         << "Output variable at index " << output
00120                         << " invalid." << std::endl;
00121 
00122         std::set<InputVar> variables;
00123         unsigned int i = 0;
00124         for(std::vector<Calibration::Variable>::const_iterator iter =
00125                         calib->inputSet.begin(); iter != calib->inputSet.end();
00126             ++iter, i++) {
00127                 InputVar var;
00128                 var.var = Variable(iter->name, config[i].mask);
00129                 var.index = i;
00130                 variables.insert(var);
00131         }
00132 
00133         inputVariables.resize(i);
00134         std::copy(variables.begin(), variables.end(),
00135                   inputVariables.begin());
00136 
00137         for(unsigned int j = 0; j < i; j++)
00138                 inputVariables[j].multiplicity = config[j].origin;
00139 }
00140 
00141 MVAComputer::~MVAComputer()
00142 {
00143 }
00144 
00145 unsigned int MVAComputer::getVariableId(AtomicId name) const
00146 {
00147         std::vector<InputVar>::const_iterator pos =
00148                 std::lower_bound(inputVariables.begin(), inputVariables.end(),
00149                                  name);
00150 
00151         if (pos == inputVariables.end() || pos->var.getName() != name)
00152                 throw cms::Exception("InvalidVariable")
00153                         << "Input variable " << (const char*)name
00154                         << " not found."  << std::endl;
00155 
00156         return pos->index;
00157 }
00158 
00159 template<class T>
00160 void MVAComputer::evalInternal(T &ctx) const
00161 {
00162         double *output = ctx.values() + ctx.n();
00163         int *outConf = ctx.conf() + inputVariables.size();
00164 
00165 #ifdef DEBUG_EVAL
00166         std::cout << "Input" << std::endl;
00167         double *v = ctx.values();
00168         for(int *o = ctx.conf(); o < outConf; o++) {
00169                 std::cout << "\tVar " << (o - ctx.conf()) << std::endl;
00170                 for(int i = o[0]; i < o[1]; i++)
00171                         std::cout << "\t\t" << *v++ << std::endl;
00172         }
00173 #endif
00174         std::vector<Processor>::const_iterator iter = varProcessors.begin();
00175         while(iter != varProcessors.end()) {
00176                 std::vector<Processor>::const_iterator loop = iter;
00177                 int *loopOutConf = outConf;
00178                 int *loopStart = 0;
00179                 double *loopOutput = output;
00180 
00181                 VarProcessor::LoopStatus status = VarProcessor::kNext;
00182                 unsigned int offset = 0;
00183                 while(status != VarProcessor::kStop) {
00184                         std::vector<Processor>::const_iterator next = iter + 1;
00185                         unsigned int nextOutput = (next != varProcessors.end())
00186                                                   ? next->nOutput : 0;
00187 
00188 #ifdef DEBUG_EVAL
00189                         std::cout << ROOT::Reflex::Tools::Demangle(
00190                                 typeid(*iter->processor)) << std::endl;
00191 #endif
00192                         if (status != VarProcessor::kSkip)
00193                                 ctx.eval(&*iter->processor, outConf, output,
00194                                          loopStart ? loopStart : loopOutConf,
00195                                          offset, iter->nOutput);
00196 
00197 #ifdef DEBUG_EVAL
00198                         for(unsigned int i = 0; i < iter->nOutput;
00199                             i++, outConf++) {
00200                                 std::cout << "\tVar " << (outConf - ctx.conf())
00201                                           << std::endl;
00202                                 for(int j = outConf[0]; j < outConf[1]; j++)
00203                                         std::cout << "\t\t" << *output++
00204                                                   << std::endl;
00205                         }
00206 #else
00207                         int orig = *outConf;
00208                         outConf += iter->nOutput;
00209                         output += *outConf - orig;
00210 #endif
00211 
00212                         status = loop->processor->loop(output, outConf,
00213                                                        nextOutput, offset);
00214 
00215                         if (status == VarProcessor::kReset) {
00216                                 outConf = loopOutConf;
00217                                 output = loopOutput;
00218                                 loopStart = 0;
00219                                 offset = 0;
00220                                 iter = loop;
00221                         } else {
00222                                 if (loop == iter)
00223                                         loopStart = outConf;
00224                                 iter = next;
00225                         }
00226                 }
00227         }
00228 }
00229 
00230 Calibration::MVAComputer *MVAComputer::readCalibration(const char *filename)
00231 {
00232         std::ifstream file(filename);
00233         return readCalibration(file);
00234 }
00235 
00236 Calibration::MVAComputer *MVAComputer::readCalibration(std::istream &is)
00237 {
00238         if (!is.good())
00239                 throw cms::Exception("InvalidFileState")
00240                         << "Stream passed to MVAComputer::readCalibration "
00241                            "has an invalid state." << std::endl;
00242 
00243         char header[sizeof STANDALONE_HEADER - 1] = { 0, };
00244         if (is.readsome(header, sizeof header) != sizeof header ||
00245             std::memcmp(header, STANDALONE_HEADER, sizeof header) != 0)
00246                 throw cms::Exception("InvalidFileFormat")
00247                         << "Stream passed to MVAComputer::readCalibration "
00248                            "is not a valid calibration file." << std::endl;
00249 
00250         TClass *rootClass =
00251                 TClass::GetClass("PhysicsTools::Calibration::MVAComputer");
00252         if (!rootClass)
00253                 throw cms::Exception("DictionaryMissing")
00254                         << "CondFormats dictionary for "
00255                            "PhysicsTools::Calibration::MVAComputer missing"
00256                         << std::endl;
00257 
00258         ext::izstream izs(&is);
00259         std::ostringstream ss;
00260         ss << izs.rdbuf();
00261         std::string buf = ss.str();
00262 
00263         TBufferFile buffer(TBuffer::kRead, buf.size(), const_cast<void*>(
00264                         static_cast<const void*>(buf.c_str())), kFALSE);
00265         buffer.InitMap();
00266 
00267         std::auto_ptr<Calibration::MVAComputer> calib(
00268                                         new Calibration::MVAComputer());
00269         buffer.StreamObject(static_cast<void*>(calib.get()), rootClass);
00270 
00271         return calib.release();
00272 }
00273 
00274 void MVAComputer::writeCalibration(const char *filename,
00275                                    const Calibration::MVAComputer *calib)
00276 {
00277         std::ofstream file(filename);
00278         writeCalibration(file, calib);
00279 }
00280 
00281 void MVAComputer::writeCalibration(std::ostream &os,
00282                                    const Calibration::MVAComputer *calib)
00283 {
00284         if (!os.good())
00285                 throw cms::Exception("InvalidFileState")
00286                         << "Stream passed to MVAComputer::writeCalibration "
00287                            "has an invalid state." << std::endl;
00288 
00289         os << STANDALONE_HEADER;
00290 
00291         TClass *rootClass =
00292                 TClass::GetClass("PhysicsTools::Calibration::MVAComputer");
00293         if (!rootClass)
00294                 throw cms::Exception("DictionaryMissing")
00295                         << "CondFormats dictionary for "
00296                            "PhysicsTools::Calibration::MVAComputer missing"
00297                         << std::endl;
00298 
00299         TBufferFile buffer(TBuffer::kWrite);
00300         buffer.StreamObject(const_cast<void*>(static_cast<const void*>(calib)),
00301                             rootClass);
00302 
00303         ext::ozstream ozs(&os);
00304         ozs.write(buffer.Buffer(), buffer.Length());
00305         ozs.flush();
00306 }
00307 
00308 // instantiate use cases fo MVAComputer::evalInternal
00309 
00310 void MVAComputer::DerivContext::eval(
00311                 const VarProcessor *proc, int *outConf, double *output,
00312                 int *loop, unsigned int offset, unsigned int out) const
00313 {
00314         proc->deriv(values(), conf(), output, outConf,
00315                     loop, offset, n(), out, deriv_);
00316 }
00317 
00318 double MVAComputer::DerivContext::output(unsigned int output,
00319                                          std::vector<double> &derivs) const
00320 {
00321         derivs.clear();
00322         derivs.reserve(n_);
00323 
00324         int pos = conf_[output];
00325         if (pos >= (int)n_)
00326                 std::copy(&deriv_.front() + n_ * (pos - n_),
00327                           &deriv_.front() + n_ * (pos - n_ + 1),
00328                           std::back_inserter(derivs));
00329         else {
00330                 derivs.resize(n_);
00331                 derivs[pos] = 1.;
00332         }
00333 
00334         return values_[pos];
00335 }
00336 
00337 template void MVAComputer::evalInternal(EvalContext &ctx) const;
00338 template void MVAComputer::evalInternal(DerivContext &ctx) const;
00339 
00340 } // namespace PhysicsTools