diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b088f9..6b75c51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,78 +1,79 @@ # Copyright 2018 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 . ################################################################################ cmake_minimum_required (VERSION 2.8 FATAL_ERROR) #Use the compilers found in the path find_program(CMAKE_C_COMPILER NAMES $ENV{CC} gcc PATHS ENV PATH NO_DEFAULT_PATH) find_program(CMAKE_CXX_COMPILER NAMES $ENV{CXX} g++ PATHS ENV PATH NO_DEFAULT_PATH) project(NUISANCE) include(ExternalProject) set (NUISANCE_VERSION_MAJOR 3) set (NUISANCE_VERSION_MINOR 0) set (NUISANCE_VERSION_REVISION 0) set (NUISANCE_VERSION_STRING "v${NUISANCE_VERSION_MAJOR}r${NUISANCE_VERSION_MINOR}") if(${NUISANCE_VERSION_REVISION} STRGREATER "0") set (NUISANCE_VERSION_STRING "${NUISANCE_VERSION_STRING}p${NUISANCE_VERSION_REVISION}") endif() #Set this to TRUE to enable build debugging messages set(BUILD_DEBUG_MSGS TRUE) include(${CMAKE_SOURCE_DIR}/cmake/cmessage.cmake) include(${CMAKE_SOURCE_DIR}/cmake/cacheVariables.cmake) include(${CMAKE_SOURCE_DIR}/cmake/parseConfigApp.cmake) include(${CMAKE_SOURCE_DIR}/cmake/StringAndListUtils.cmake) cmessage(STATUS "CMAKE_INSTALL_PREFIX: \"${CMAKE_INSTALL_PREFIX}\"") cmessage(STATUS "CMAKE_BUILD_TYPE: \"${CMAKE_BUILD_TYPE}\"") ################################################################################ # Check Dependencies ################################################################################ ################################## ROOT ###################################### include(${CMAKE_SOURCE_DIR}/cmake/ROOTSetup.cmake) ################################# InputHandler ################################# include(${CMAKE_SOURCE_DIR}/cmake/InputHandlerSetup.cmake) ################################# Pythia6/8 ################################### include(${CMAKE_SOURCE_DIR}/cmake/pythia6Setup.cmake) #Want this before fhiclcpp which will add the install directory include_directories(${CMAKE_SOURCE_DIR}/src) ################################## FHICLCPP #################################### include(${CMAKE_SOURCE_DIR}/cmake/fhiclcppSetup.cmake) ################################## COMPILER #################################### +include(${CMAKE_SOURCE_DIR}/cmake/gperfSetup.cmake) include(${CMAKE_SOURCE_DIR}/cmake/c++CompilerSetup.cmake) ################################################################################ add_subdirectory(src) add_subdirectory(scripts) add_subdirectory(config) add_subdirectory(data) diff --git a/cmake/gperfSetup.cmake b/cmake/gperfSetup.cmake new file mode 100644 index 0000000..3d54519 --- /dev/null +++ b/cmake/gperfSetup.cmake @@ -0,0 +1,60 @@ +# 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 . +################################################################################ + +if(DEFINED USE_GPERFTOOLS AND USE_GPERFTOOLS) + + ExternalProject_Add(libunwind + PREFIX "${CMAKE_BINARY_DIR}/Ext" + GIT_REPOSITORY "https://github.com/libunwind/libunwind.git" + GIT_TAG v1.3.1 + CONFIGURE_COMMAND ${CMAKE_BINARY_DIR}/Ext/src/libunwind/autogen.sh --prefix=${CMAKE_INSTALL_PREFIX} + UPDATE_DISCONNECTED 1 + UPDATE_COMMAND "" + BUILD_COMMAND make + INSTALL_COMMAND make install + ) + + ExternalProject_Add(gperftools + PREFIX "${CMAKE_BINARY_DIR}/Ext" + GIT_REPOSITORY "https://github.com/gperftools/gperftools.git" + GIT_TAG "gperftools-2.7" + CONFIGURE_COMMAND ./autogen.sh && ./configure --prefix=${CMAKE_INSTALL_PREFIX} CPPFLAGS=-I${CMAKE_INSTALL_PREFIX}/include LDFLAGS=-L${CMAKE_INSTALL_PREFIX}/lib + BUILD_IN_SOURCE 1 + UPDATE_DISCONNECTED 1 + UPDATE_COMMAND "" + BUILD_COMMAND make + INSTALL_COMMAND make install + ) + + add_dependencies(gperftools libunwind) + + LIST(APPEND EXTRA_CXX_FLAGS + -fno-builtin-malloc + -fno-builtin-calloc + -fno-builtin-realloc + -fno-builtin-free) + + + LIST(APPEND EXTRA_LINK_DIRS ${CMAKE_INSTALL_PREFIX}/lib) + + ##Want to prepend them + LIST(APPEND EXTRA_LIBS tcmalloc_and_profiler) + + cmessage(STATUS "Using google performance libraries") +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 63767ba..68b52bd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,18 +1,19 @@ add_subdirectory(config) add_subdirectory(event) add_subdirectory(exception) add_subdirectory(generator) add_subdirectory(input) add_subdirectory(parameters) add_subdirectory(persistency) add_subdirectory(plugins) add_subdirectory(samples) add_subdirectory(utility) add_subdirectory(variation) SET(INuADataComparisons_List ${INuADataComparisons_List} PARENT_SCOPE) SET(INuADataComparisons_FHiCL ${INuADataComparisons_FHiCL} PARENT_SCOPE) SET(GENERATOR_DEPENDENT_TARGETS ${GENERATOR_DEPENDENT_TARGETS} PARENT_SCOPE) +add_subdirectory(tests) add_subdirectory(app) diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index c84c5fe..34feffb 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -1,15 +1,15 @@ SET(APPS nuissamples nuiscomp nuisevsum nuisstudy) foreach(a ${APPS}) add_executable(${a} ${a}.cxx) - target_link_libraries(${a} -Wl,--no-as-needed nuis_event nuis_input nuis_utility_experimental nuis_utility nuis_config nuis_persistency nuis_plugins nuis_params nuis_variation) + target_link_libraries(${a} -Wl,--no-as-needed nuis_event nuis_input nuis_generator_utility nuis_utility_experimental nuis_utility nuis_config nuis_persistency nuis_plugins nuis_params nuis_variation) target_link_libraries(${a} ${GENERATOR_DEPENDENT_TARGETS} -Wl,--as-needed) target_link_libraries(${a} ${NUISANCE_LINK_DIRS}) target_link_libraries(${a} ${NUISANCE_DEPEND_LIBS}) if(NOT "${CMAKE_LINK_FLAGS}" STREQUAL "") set_target_properties(${a} PROPERTIES LINK_FLAGS ${CMAKE_LINK_FLAGS}) endif() install(TARGETS ${a} DESTINATION bin) endforeach() diff --git a/src/generator/input/GENIEInputHandler.cxx b/src/generator/input/GENIEInputHandler.cxx index cc5c146..1bfb67d 100644 --- a/src/generator/input/GENIEInputHandler.cxx +++ b/src/generator/input/GENIEInputHandler.cxx @@ -1,165 +1,215 @@ #include "generator/input/GENIEInputHandler.hxx" #include "generator/utility/GENIEUtility.hxx" #include "utility/PDGCodeUtility.hxx" #ifdef GENIE_V3_INTERFACE #include "Framework/EventGen/EventRecord.h" #include "Framework/GHEP/GHepParticle.h" #include "Framework/GHEP/GHepRecord.h" #else #include "EVGCore/EventRecord.h" #include "GHEP/GHepParticle.h" #include "GHEP/GHepRecord.h" #endif #include "fhiclcpp/ParameterSet.h" using namespace nuis; using namespace nuis::event; using namespace nuis::utility; using namespace nuis::genietools; GENIEInputHandler::GENIEInputHandler() : fInputTree(), fGenieNtpl(nullptr), fFileWeight(1) {} GENIEInputHandler::GENIEInputHandler(GENIEInputHandler &&other) : fInputTree(std::move(other.fInputTree)), fReaderEvent(std::move(other.fReaderEvent)), fGenieNtpl(nullptr), fFileWeight(1) {} +std::set GENIEInputHandler::GetSplineList() { + std::set splinenames; + size_t NEvents = 1000; // GetNEvents(); + size_t ShoutEvery = NEvents / 100; + std::cout << "[INFO]: Read " << 0 << "/" << NEvents << " GENIE events." + << std::flush; + for (size_t ev_it = 0; ev_it < NEvents; ++ev_it) { + if (fGenieNtpl) { + fGenieNtpl->Clear(); + } + fInputTree.tree->GetEntry(ev_it); + + if (ShoutEvery && !(ev_it % ShoutEvery)) { + std::cout << "\r[INFO]: Read " << ev_it << "/" << NEvents + << " GENIE events." << std::flush; + } + + genie::GHepRecord *GHep = + static_cast(fGenieNtpl->event); + if (!GHep) { + throw invalid_GENIE_event() << "[ERROR]: GENIE event " << ev_it + << " failed to contain a GHepRecord"; + } + splinenames.insert(GHep->Summary()->AsString()); + } + std::cout << "[INFO]: Having read GENIE events, found " << splinenames.size() + << " splines: " << std::endl; + for (auto const &sn : splinenames) { + std::cout << "\t" << sn << std::endl; + } + return splinenames; +} + void GENIEInputHandler::Initialize(fhicl::ParameterSet const &ps) { fInputTree = CheckGetTTree(ps.get("file"), "gtree"); fInputTree.tree->SetBranchAddress("gmcrec", &fGenieNtpl); fKeepIntermediates = ps.get("keep_intermediates", false); fKeepNuclearParticles = ps.get("keep_nuclear_particles", false); fhicl::ParameterSet XSecInfo = ps.get("xsec_info", {}); if (XSecInfo.has_key("weight")) { fFileWeight = XSecInfo.get("weight"); std::cout << "[INFO]: Average GENIE XSecWeight = " << fFileWeight << "" << std::endl; } else if (XSecInfo.has_key("flux") || XSecInfo.has_key("target") || - XSecInfo.has_key("spline_file")) { + XSecInfo.has_key("spline_file") || + XSecInfo.has_key("filter_splines_by_event_tree")) { std::cout << "[INFO]: Attempting to build GENIE file weight with input splines." << std::endl; - fFileWeight = genietools::GetFileWeight(XSecInfo) / double(GetNEvents()); + + if (XSecInfo.get("filter_splines_by_event_tree", false)) { + std::cout << "[INFO]: Ensuring we only read relevant splines... this " + "will take a while." + << std::endl; + fFileWeight = genietools::GetFileWeight(XSecInfo, GetSplineList()) / + double(GetNEvents()); + } else { + fFileWeight = genietools::GetFileWeight(XSecInfo) / double(GetNEvents()); + } std::cout << "[INFO]: Average GENIE XSecWeight = " << fFileWeight << "" << std::endl; } } -MinimalEvent const &GENIEInputHandler::GetMinimalEvent(ev_index_t idx) const { +void GENIEInputHandler::GetEntry(ev_index_t idx) const { if (idx >= GetNEvents()) { throw IInputHandler::invalid_entry() << "[ERROR]: Attempted to get entry " << idx << " from an InputHandler with only " << GetNEvents(); } + if (fGenieNtpl) { + fGenieNtpl->Clear(); + } fInputTree.tree->GetEntry(idx); +} + +MinimalEvent const &GENIEInputHandler::GetMinimalEvent(ev_index_t idx) const { + GetEntry(idx); genie::GHepRecord *GHep = static_cast(fGenieNtpl->event); if (!GHep) { throw invalid_GENIE_event() << "[ERROR]: GENIE event " << idx << " failed to contain a GHepRecord"; } fReaderEvent.mode = GetEventChannel(*GHep); TObjArrayIter iter(GHep); genie::GHepParticle *p; while ((p = (dynamic_cast((iter).Next())))) { if (!p) { continue; } Particle::Status_t state = GetParticleStatus(*p, fReaderEvent.mode); if (state != Particle::Status_t::kPrimaryInitialState) { continue; } if (!IsNeutralLepton(p->Pdg(), pdgcodes::kMatterAntimatter) && !IsChargedLepton(p->Pdg(), pdgcodes::kMatterAntimatter)) { continue; } fReaderEvent.probe_E = p->E() * 1.E3; fReaderEvent.probe_pdg = p->Pdg(); break; } fReaderEvent.XSecWeight = fFileWeight; if (fWeightCache.size() <= idx) { fWeightCache.push_back(fReaderEvent.XSecWeight); } return fReaderEvent; } FullEvent const &GENIEInputHandler::GetFullEvent(ev_index_t idx) const { (void)GetMinimalEvent(idx); fReaderEvent.ClearParticleStack(); genie::GHepRecord *GHep = static_cast(fGenieNtpl->event); unsigned int npart = GHep->GetEntries(); // Fill Particle Stack genie::GHepParticle *p = 0; TObjArrayIter iter(GHep); // Loop over all particles while ((p = (dynamic_cast((iter).Next())))) { if (!p) { continue; } // Get Status Particle::Status_t state = GetParticleStatus(*p, fReaderEvent.mode); if (!fKeepIntermediates && (state == Particle::Status_t::kIntermediate)) { continue; } if (!fKeepNuclearParticles && IsNuclearPDG(p->Pdg())) { continue; } Particle nuis_part; nuis_part.pdg = p->Pdg(); nuis_part.P4 = TLorentzVector(p->Px(), p->Py(), p->Pz(), p->E()) * 1E3; fReaderEvent.ParticleStack[static_cast(state)].particles.push_back( nuis_part); } return fReaderEvent; } double GENIEInputHandler::GetEventWeight(ev_index_t idx) const { if (idx > fWeightCache.size()) { throw weight_cache_miss() << "[ERROR]: Failed to get cached weight for event index: " << idx; } return fWeightCache[idx]; } double GENIEInputHandler::GetXSecScaleFactor( std::pair const &EnuRange) const { throw input_handler_feature_unimplemented() << "[ERROR]: Flux cuts not yet implemented for GENIE input handler."; } size_t GENIEInputHandler::GetNEvents() const { return fInputTree.tree->GetEntries(); } GeneratorManager::Generator_id_t GENIEInputHandler::GetGeneratorId() const { return GeneratorManager::Get().EnsureGeneratorRegistered("GENIE"); } DECLARE_PLUGIN(IInputHandler, GENIEInputHandler); diff --git a/src/generator/input/GENIEInputHandler.hxx b/src/generator/input/GENIEInputHandler.hxx index 312b6b7..a1f3456 100644 --- a/src/generator/input/GENIEInputHandler.hxx +++ b/src/generator/input/GENIEInputHandler.hxx @@ -1,69 +1,72 @@ // Copyright 2018 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 . *******************************************************************************/ #pragma once #include "event/FullEvent.hxx" #include "input/IInputHandler.hxx" #include "exception/exception.hxx" #include "utility/ROOTUtility.hxx" #ifdef GENIE_V3_INTERFACE #include "Framework/Ntuple/NtpMCEventRecord.h" #else #include "Ntuple/NtpMCEventRecord.h" #endif namespace fhicl { class ParameterSet; } #include +#include class GENIEInputHandler : public IInputHandler { mutable nuis::utility::TreeFile fInputTree; mutable nuis::event::FullEvent fReaderEvent; mutable std::vector fWeightCache; mutable genie::NtpMCEventRecord *fGenieNtpl; bool fKeepIntermediates; bool fKeepNuclearParticles; double fFileWeight; public: NEW_NUIS_EXCEPT(weight_cache_miss); GENIEInputHandler(); GENIEInputHandler(GENIEInputHandler const &) = delete; GENIEInputHandler(GENIEInputHandler &&); void Initialize(fhicl::ParameterSet const &); + void GetEntry(ev_index_t) const; nuis::event::MinimalEvent const &GetMinimalEvent(ev_index_t idx) const; nuis::event::FullEvent const &GetFullEvent(ev_index_t idx) const; double GetEventWeight(ev_index_t idx) const; size_t GetNEvents() const; + std::set GetSplineList(); double GetXSecScaleFactor(std::pair const &EnuRange) const; nuis::GeneratorManager::Generator_id_t GetGeneratorId() const; }; diff --git a/src/generator/input/NEUTInputHandler.cxx b/src/generator/input/NEUTInputHandler.cxx index 9fc688d..476b383 100644 --- a/src/generator/input/NEUTInputHandler.cxx +++ b/src/generator/input/NEUTInputHandler.cxx @@ -1,260 +1,264 @@ #include "generator/input/NEUTInputHandler.hxx" #include "persistency/ROOTOutput.hxx" #include "utility/HistogramUtility.hxx" #include "utility/InteractionChannelUtility.hxx" #include "utility/PDGCodeUtility.hxx" #include "generator/utility/NEUTUtility.hxx" #include "neutpart.h" #include "neutvect.h" #include "fhiclcpp/ParameterSet.h" using namespace nuis; using namespace nuis::event; using namespace nuis::utility; using namespace nuis::neuttools; NEUTInputHandler::NEUTInputHandler() : fInputTreeFile() {} NEUTInputHandler::NEUTInputHandler(NEUTInputHandler &&other) : fInputTreeFile(std::move(other.fInputTreeFile)), fReaderEvent(std::move(other.fReaderEvent)) {} void NEUTInputHandler::Initialize(fhicl::ParameterSet const &ps) { fInputTreeFile = CheckGetTTree(ps.get("file"), "neuttree"); fNeutVect = nullptr; fInputTreeFile.tree->SetBranchAddress("vectorbranch", &fNeutVect); fKeepIntermediates = ps.get("keep_intermediates", false); std::string flux_name = ps.get("flux_hist_name", "flux_numu"); std::string evtrt_name = ps.get("evtrt_hist_name", "evtrt_numu"); fXSecRescaleFactor = ps.get("xsec_rescale_factor",1); std::string override_flux_file = ps.get("override_flux_file", ""); if (override_flux_file.size()) { fFlux = GetHistogramFromROOTFile(override_flux_file, flux_name); RebuildEventRate(!ps.get("flux_hist_in_MeV", false)); } else { fFlux = GetHistogramFromROOTFile(fInputTreeFile.file, flux_name, false); } if (fFlux) { if (!fEvtrt) { fEvtrt = GetHistogramFromROOTFile(fInputTreeFile.file, evtrt_name); } fFileWeight = fEvtrt->Integral() * 1.0E-38 / (fFlux->Integral() * double(GetNEvents())); std::cout << "[INFO]: Average NEUT XSecWeight = " << fFileWeight << "" << std::endl; } else { std::cout << "[INFO]: Input NEUT file doesn't have flux information, assuming " "mono energetic and calculating average cross-section..." << std::endl; fFileWeight = GetMonoEXSecWeight() / double(GetNEvents()); std::cout << "[INFO]: Done (Average NEUT XSecWeight = " << fFileWeight << ")!" << std::endl; } fFileWeight *= fXSecRescaleFactor; } NEW_NUIS_EXCEPT(non_mono_energetic_input_file); double NEUTInputHandler::GetMonoEXSecWeight() { double xsec = 0; double count = 0; double E_first = std::numeric_limits::max(); size_t NEvents = GetNEvents(); size_t ShoutEvery = NEvents / 100; std::cout << "[INFO]: Read " << 0 << "/" << NEvents << " NEUT events." << std::flush; for (size_t nev_it = 0; nev_it < NEvents; ++nev_it) { if (ShoutEvery && !(nev_it % ShoutEvery)) { std::cout << "\r[INFO]: Read " << nev_it << "/" << NEvents << " NEUT events." << std::flush; } fInputTreeFile.tree->GetEntry(nev_it); xsec += fNeutVect->Totcrs; //Assume monoE. return xsec * 1E-38; count++; if (E_first == std::numeric_limits::max()) { NeutPart *part = fNeutVect->PartInfo(0); E_first = part->fP.E(); } else { NeutPart *part = fNeutVect->PartInfo(0); if (E_first != part->fP.E()) { throw non_mono_energetic_input_file() << "[ERROR]: When calculating NEUT xsec weight for a mono " "energetic beam, found different energies: " << E_first << " and " << part->fP.E() << ". Cannot continue with this input file."; } } } std::cout << "\r[INFO]: Read " << NEvents << "/" << NEvents << " NEUT events." << std::endl; return (xsec / count) * 1E-38; } void NEUTInputHandler::RebuildEventRate(bool FluxInGeV) { auto XSec = Clone(fFlux, true, "xsec"); auto Entry = Clone(fFlux, true, "entry"); std::cout << "[INFO]: Rebuilding total cross-section prediction..." << std::endl; size_t NEvents = GetNEvents(); size_t ShoutEvery = NEvents / 100; std::cout << "[INFO]: Read " << 0 << "/" << NEvents << " NEUT events." << std::flush; for (size_t nev_it = 0; nev_it < NEvents; ++nev_it) { if (ShoutEvery && !(nev_it % ShoutEvery)) { std::cout << "\r[INFO]: Read " << nev_it << "/" << NEvents << " NEUT events." << std::flush; } fInputTreeFile.tree->GetEntry(nev_it); NeutPart *part = fNeutVect->PartInfo(0); double E = part->fP.E() * (FluxInGeV ? 1E-3 : 1); XSec->Fill(E, fNeutVect->Totcrs); Entry->Fill(E); } std::cout << std::endl << "[INFO]: Done!" << std::endl; // Binned total xsec XSec->Divide(Entry.get()); fEvtrt = Clone(XSec, false, "evtrt"); // Event rate prediction fEvtrt->Multiply(fFlux.get()); } double NEUTInputHandler::GetXSecScaleFactor(std::pair const &) const { throw input_handler_feature_unimplemented() << "[ERROR]: Flux cuts not yet implemented for NEUT input handler."; } NeutVect *NEUTInputHandler::GetNeutEvent(ev_index_t idx) const { if (idx >= GetNEvents()) { throw IInputHandler::invalid_entry() << "[ERROR]: Attempted to get entry " << idx << " from an InputHandler with only " << GetNEvents(); } fInputTreeFile.tree->GetEntry(idx); return fNeutVect; } -MinimalEvent const &NEUTInputHandler::GetMinimalEvent(ev_index_t idx) const { +void NEUTInputHandler::GetEntry(ev_index_t idx) const { if (idx >= GetNEvents()) { throw IInputHandler::invalid_entry() << "[ERROR]: Attempted to get entry " << idx << " from an InputHandler with only " << GetNEvents(); } fInputTreeFile.tree->GetEntry(idx); +} + +MinimalEvent const &NEUTInputHandler::GetMinimalEvent(ev_index_t idx) const { + GetEntry(idx); fReaderEvent.mode = IntToChannel(fNeutVect->Mode); size_t NPart = fNeutVect->Npart(); for (size_t part_it = 0; part_it < NPart; part_it++) { NeutPart const &part = (*fNeutVect->PartInfo(part_it)); if ((part.fIsAlive == false) && (part.fStatus == -1) && IsNeutralLepton(part.fPID)) { fReaderEvent.probe_E = part.fP.T(); fReaderEvent.probe_pdg = part.fPID; break; } } fReaderEvent.XSecWeight = fFileWeight; if (fWeightCache.size() <= idx) { fWeightCache.push_back(fReaderEvent.XSecWeight); } fReaderEvent.fGenEvent = fNeutVect; return fReaderEvent; } FullEvent const &NEUTInputHandler::GetFullEvent(ev_index_t idx) const { (void)GetMinimalEvent(idx); fReaderEvent.ClearParticleStack(); if (fNeutVect->Ibound) { fReaderEvent.target_pdg = MakeNuclearPDG(fNeutVect->TargetA, fNeutVect->TargetZ); } else { fReaderEvent.target_pdg = MakeNuclearPDG(1, 1); } size_t NPart = fNeutVect->Npart(); size_t NPrimary = fNeutVect->Nprimary(); for (size_t part_it = 0; part_it < NPart; part_it++) { NeutPart const &part = (*fNeutVect->PartInfo(part_it)); Particle nuis_part; nuis_part.pdg = part.fPID; nuis_part.P4 = part.fP; Particle::Status_t state = GetNeutParticleStatus(part, fReaderEvent.mode); if (!fKeepIntermediates && (state == Particle::Status_t::kIntermediate)) { continue; } size_t state_int = static_cast(state); // Add status == 0 particles as pre-FSI particles until we find an // intermediate state particle if ((part_it < NPrimary) && (state != Particle::Status_t::kPrimaryInitialState)) { fReaderEvent .ParticleStack[static_cast( Particle::Status_t::kPrimaryFinalState)] .particles.push_back(nuis_part); } fReaderEvent.ParticleStack[state_int].particles.push_back(nuis_part); } return fReaderEvent; } double NEUTInputHandler::GetEventWeight(ev_index_t idx) const { if (idx > fWeightCache.size()) { throw weight_cache_miss() << "[ERROR]: Failed to get cached weight for event index: " << idx; } return fWeightCache[idx]; } size_t NEUTInputHandler::GetNEvents() const { return fInputTreeFile.tree->GetEntries(); } GeneratorManager::Generator_id_t NEUTInputHandler::GetGeneratorId() const { return GeneratorManager::Get().EnsureGeneratorRegistered("NEUT"); } DECLARE_PLUGIN(IInputHandler, NEUTInputHandler); diff --git a/src/generator/input/NEUTInputHandler.hxx b/src/generator/input/NEUTInputHandler.hxx index a2cc915..574e2fa 100644 --- a/src/generator/input/NEUTInputHandler.hxx +++ b/src/generator/input/NEUTInputHandler.hxx @@ -1,71 +1,72 @@ // Copyright 2018 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 . *******************************************************************************/ #pragma once #include "event/FullEvent.hxx" #include "input/IInputHandler.hxx" #include "utility/ROOTUtility.hxx" #include class NeutVect; class TH1; namespace fhicl { class ParameterSet; } class NEUTInputHandler : public IInputHandler { mutable nuis::utility::TreeFile fInputTreeFile; mutable nuis::event::FullEvent fReaderEvent; mutable NeutVect *fNeutVect; mutable std::vector fWeightCache; double fXSecRescaleFactor; std::unique_ptr fFlux; std::unique_ptr fEvtrt; double fFileWeight; bool fKeepIntermediates; double GetMonoEXSecWeight(); void RebuildEventRate(bool FluxInGeV=true); public: NEW_NUIS_EXCEPT(weight_cache_miss); NEUTInputHandler(); NEUTInputHandler(NEUTInputHandler const &) = delete; NEUTInputHandler(NEUTInputHandler &&); void Initialize(fhicl::ParameterSet const &); NeutVect *GetNeutEvent(ev_index_t) const; + void GetEntry(ev_index_t) const; nuis::event::MinimalEvent const &GetMinimalEvent(ev_index_t idx) const; nuis::event::FullEvent const &GetFullEvent(ev_index_t idx) const; double GetEventWeight(ev_index_t idx) const; size_t GetNEvents() const; double GetXSecScaleFactor(std::pair const &EnuRange) const; nuis::GeneratorManager::Generator_id_t GetGeneratorId() const; }; diff --git a/src/generator/input/NuWroInputHandler.cxx b/src/generator/input/NuWroInputHandler.cxx index 15e3814..ae0d48c 100644 --- a/src/generator/input/NuWroInputHandler.cxx +++ b/src/generator/input/NuWroInputHandler.cxx @@ -1,134 +1,139 @@ #include "generator/input/NuWroInputHandler.hxx" #include "generator/utility/NuWroUtility.hxx" #include "fhiclcpp/ParameterSet.h" #include "particle.h" using NuWroParticle = ::particle; using namespace nuis; using namespace nuis::event; using namespace nuis::utility; using namespace nuis::nuwrotools; NuWroInputHandler::NuWroInputHandler() : fInputTree(), fTreeEvent(nullptr) {} NuWroInputHandler::NuWroInputHandler(NuWroInputHandler &&other) : fInputTree(std::move(other.fInputTree)), fReaderEvent(std::move(other.fReaderEvent)), fTreeEvent(other.fTreeEvent) {} void NuWroInputHandler::Initialize(fhicl::ParameterSet const &ps) { fInputTree = CheckGetTTree(ps.get("file"), "treeout"); fTreeEvent = nullptr; fInputTree.tree->SetBranchAddress("e", &fTreeEvent); fKeepIntermediates = ps.get("keep_intermediates", false); - if(GetNEvents()){ + if (GetNEvents()) { fInputTree.tree->GetEntry(0); - std::cout << "[INFO]: Average NuWro XSec weight: " << (fTreeEvent->weight / double(GetNEvents())) << std::endl; + std::cout << "[INFO]: Average NuWro XSec weight: " + << (fTreeEvent->weight / double(GetNEvents())) << std::endl; } } -MinimalEvent const &NuWroInputHandler::GetMinimalEvent(ev_index_t idx) const { + +void NuWroInputHandler::GetEntry(ev_index_t idx) const { if (idx >= GetNEvents()) { throw IInputHandler::invalid_entry() << "[ERROR]: Attempted to get entry " << idx << " from an InputHandler with only " << GetNEvents(); } fInputTree.tree->GetEntry(idx); +} + +MinimalEvent const &NuWroInputHandler::GetMinimalEvent(ev_index_t idx) const { fReaderEvent.mode = NuWroEventChannel(*fTreeEvent); fReaderEvent.probe_E = fTreeEvent->in[0].E(); fReaderEvent.probe_pdg = fTreeEvent->in[0].pdg; fReaderEvent.XSecWeight = fTreeEvent->weight / double(GetNEvents()); if (fWeightCache.size() <= idx) { fWeightCache.push_back(fReaderEvent.XSecWeight); } return fReaderEvent; } FullEvent const &NuWroInputHandler::GetFullEvent(ev_index_t idx) const { (void)GetMinimalEvent(idx); fReaderEvent.ClearParticleStack(); for (size_t p_it = 0; p_it < fTreeEvent->in.size(); ++p_it) { NuWroParticle &part = fTreeEvent->in[p_it]; Particle nuis_part; nuis_part.pdg = part.pdg; nuis_part.P4 = TLorentzVector(part[1], part[2], part[3], part[0]); fReaderEvent .ParticleStack[static_cast( Particle::Status_t::kPrimaryInitialState)] .particles.push_back(nuis_part); } for (size_t p_it = 0; p_it < fKeepIntermediates && fTreeEvent->out.size(); ++p_it) { NuWroParticle &part = fTreeEvent->out[p_it]; Particle nuis_part; nuis_part.pdg = part.pdg; nuis_part.P4 = TLorentzVector(part[1], part[2], part[3], part[0]); fReaderEvent .ParticleStack[static_cast( Particle::Status_t::kPrimaryFinalState)] .particles.push_back(nuis_part); } for (size_t p_it = 0; (p_it < fTreeEvent->post.size()); ++p_it) { NuWroParticle &part = fTreeEvent->post[p_it]; Particle nuis_part; nuis_part.pdg = part.pdg; nuis_part.P4 = TLorentzVector(part[1], part[2], part[3], part[0]); fReaderEvent .ParticleStack[static_cast(Particle::Status_t::kNuclearLeaving)] .particles.push_back(nuis_part); } fReaderEvent.fGenEvent = fTreeEvent; return fReaderEvent; } NuWroEvent const &NuWroInputHandler::GetNuWroEvent(ev_index_t idx) const { (void)GetMinimalEvent(idx); return *fTreeEvent; } double NuWroInputHandler::GetEventWeight(ev_index_t idx) const { if (idx > fWeightCache.size()) { throw weight_cache_miss() << "[ERROR]: Failed to get cached weight for event index: " << idx; } return fWeightCache[idx]; } double NuWroInputHandler::GetXSecScaleFactor( std::pair const &EnuRange) const { throw input_handler_feature_unimplemented() << "[ERROR]: Flux cuts not yet implemented for NuWro input handler."; } size_t NuWroInputHandler::GetNEvents() const { return fInputTree.tree->GetEntries(); } GeneratorManager::Generator_id_t NuWroInputHandler::GetGeneratorId() const { return GeneratorManager::Get().EnsureGeneratorRegistered("NuWro"); } DECLARE_PLUGIN(IInputHandler, NuWroInputHandler); diff --git a/src/generator/input/NuWroInputHandler.hxx b/src/generator/input/NuWroInputHandler.hxx index ec36b0c..143a39c 100644 --- a/src/generator/input/NuWroInputHandler.hxx +++ b/src/generator/input/NuWroInputHandler.hxx @@ -1,66 +1,67 @@ // Copyright 2018 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 . *******************************************************************************/ #pragma once #include "event/FullEvent.hxx" #include "input/IInputHandler.hxx" #include "exception/exception.hxx" #include "utility/ROOTUtility.hxx" #include "event1.h" using NuWroEvent = ::event; #include namespace fhicl { class ParameterSet; } class NuWroInputHandler : public IInputHandler { mutable nuis::utility::TreeFile fInputTree; mutable nuis::event::FullEvent fReaderEvent; mutable std::vector fWeightCache; mutable NuWroEvent *fTreeEvent; bool fKeepIntermediates; public: NEW_NUIS_EXCEPT(weight_cache_miss); NuWroInputHandler(); NuWroInputHandler(NuWroInputHandler const &) = delete; NuWroInputHandler(NuWroInputHandler &&); void Initialize(fhicl::ParameterSet const &); + void GetEntry(ev_index_t) const; nuis::event::MinimalEvent const &GetMinimalEvent(ev_index_t idx) const; nuis::event::FullEvent const &GetFullEvent(ev_index_t idx) const; NuWroEvent const &GetNuWroEvent(ev_index_t idx) const; double GetEventWeight(ev_index_t idx) const; size_t GetNEvents() const; double GetXSecScaleFactor(std::pair const &EnuRange) const; nuis::GeneratorManager::Generator_id_t GetGeneratorId() const; }; diff --git a/src/generator/utility/GENIEUtility.cxx b/src/generator/utility/GENIEUtility.cxx index b3be697..6011309 100644 --- a/src/generator/utility/GENIEUtility.cxx +++ b/src/generator/utility/GENIEUtility.cxx @@ -1,465 +1,479 @@ // Copyright 2018 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 . *******************************************************************************/ #include "generator/utility/GENIEUtility.hxx" #include "generator/utility/GENIESplineReader.hxx" #include "utility/HistogramUtility.hxx" -#include "utility/StringUtility.hxx" - #include "utility/InteractionChannelUtility.hxx" #include "utility/PDGCodeUtility.hxx" +#include "utility/ROOTUtility.hxx" +#include "utility/StringUtility.hxx" #ifdef GENIE_V3_INTERFACE #include "Framework/GHEP/GHepParticle.h" #include "Framework/GHEP/GHepRecord.h" #include "Framework/GHEP/GHepUtils.h" #include "Framework/ParticleData/PDGCodes.h" #else #include "GHEP/GHepParticle.h" #include "GHEP/GHepRecord.h" #include "GHEP/GHepUtils.h" #include "PDG/PDGCodes.h" #endif #include "fhiclcpp/ParameterSet.h" #include "string_parsers/from_string.hxx" #include "TGraph.h" namespace nuis { using namespace event; namespace genietools { -static std::map SplineCache; - -TGraph dum; - -TGraph const &GetGENIESpline(std::string const &SplineFile, - std::string const &SplineIdentifier) { - if (SplineCache.find(SplineFile + SplineIdentifier) != SplineCache.end()) { - return SplineCache.find(SplineFile + SplineIdentifier)->second; - } - return dum; -} - struct NFSParticleCount { size_t NProton; size_t NNeutron; size_t NPip; size_t NPi0; size_t NPim; size_t NOther; }; NFSParticleCount CountPreFSIParticles(genie::GHepRecord const &ev) { // This code in this method is adapted from the GENIE source code found in // GHep/GHepUtils.cxx This method therefore carries the GENIE copyright // licence as copied below: // /// Copyright (c) 2003-2017, GENIE Neutrino MC Generator Collaboration /// For the full text of the license visit http://copyright.genie-mc.org /// or see $GENIE/LICENSE // genie::Target const &tgt = ev.Summary()->InitState().Tgt(); if (!tgt.HitNucIsSet()) { throw invalid_GENIE_event() << "[ERROR]: Failed to get hit nucleon kinematics as it was not " "included in this GHep event. This is a fatal error."; } genie::GHepParticle *FSLep = ev.FinalStatePrimaryLepton(); genie::GHepParticle *ISLep = ev.Probe(); if (!FSLep || !ISLep) { throw invalid_GENIE_event() << "[ERROR]: Failed to find IS and FS lepton in event: " << ev.Summary()->AsString(); } size_t NPi0 = 0, NPip = 0, NPim = 0, NProton = 0, NNeutron = 0, NOther = 0; bool nuclear_target = tgt.IsNucleus(); TIter event_iter(&ev); genie::GHepParticle *p = 0; while ((p = dynamic_cast(event_iter.Next()))) { genie::GHepStatus_t ghep_ist = (genie::GHepStatus_t)p->Status(); int ghep_pdgc = p->Pdg(); int ghep_fm = p->FirstMother(); int ghep_fmpdgc = (ghep_fm == -1) ? 0 : ev.Particle(ghep_fm)->Pdg(); // For nuclear targets use hadrons marked as 'hadron in the nucleus' // which are the ones passed in the intranuclear rescattering // For free nucleon targets use particles marked as 'final state' // but make an exception for decayed pi0's,eta's (count them and not their // daughters) bool decayed = (ghep_ist == genie::kIStDecayedState && (ghep_pdgc == genie::kPdgPi0 || ghep_pdgc == genie::kPdgEta)); bool parent_included = (ghep_fmpdgc == genie::kPdgPi0 || ghep_fmpdgc == genie::kPdgEta); bool count_it = (nuclear_target && ghep_ist == genie::kIStHadronInTheNucleus) || (!nuclear_target && decayed) || (!nuclear_target && ghep_ist == genie::kIStStableFinalState && !parent_included); if (!count_it) { continue; } if (ghep_pdgc == genie::kPdgPiP) { NPip++; } else if (ghep_pdgc == genie::kPdgPiM) { NPim++; } else if (ghep_pdgc == genie::kPdgPi0) { NPi0++; } else if (ghep_pdgc == genie::kPdgProton) { NProton++; } else if (ghep_pdgc == genie::kPdgNeutron) { NNeutron++; } else if (!utility::IsNeutralLepton( ghep_pdgc, utility::pdgcodes::kMatterAntimatter) && !utility::IsChargedLepton( ghep_pdgc, utility::pdgcodes::kMatterAntimatter)) { NOther++; } } return NFSParticleCount{NProton, NNeutron, NPip, NPi0, NPim, NOther}; } Channel_t GetEventChannel(genie::GHepRecord const &gev) { // Electron Scattering if (gev.Summary()->ProcInfo().IsEM()) { if (gev.Summary()->InitState().ProbePdg() == utility::pdgcodes::kElectron) { if (gev.Summary()->ProcInfo().IsQuasiElastic()) { NFSParticleCount fsparts = CountPreFSIParticles(gev); if (fsparts.NProton) { return Channel_t::kNCELP; } else { return Channel_t::kNCELN; } } else if (gev.Summary()->ProcInfo().IsMEC()) { return Channel_t::kNC2p2h; } else if (gev.Summary()->ProcInfo().IsResonant()) { NFSParticleCount fsparts = CountPreFSIParticles(gev); if (fsparts.NOther || ((fsparts.NPip + fsparts.NPi0 + fsparts.NPim) > 1)) { return Channel_t::kNCTransitionMPi; } else if (fsparts.NPip) { return Channel_t::kNCSPP_NPip; } else if (fsparts.NPi0) { return fsparts.NProton ? Channel_t::kNCSPP_PPi0 : Channel_t::kNCSPP_NPi0; } else if (fsparts.NPim) { return Channel_t::kNCSPP_PPim; } return Channel_t::kNCTransitionMPi; } else if (gev.Summary()->ProcInfo().IsDeepInelastic()) { return Channel_t::kNCDIS; } else { std::cout << "Unknown GENIE Electron Scattering Mode!" << std::endl << "ScatteringTypeId = " << gev.Summary()->ProcInfo().ScatteringTypeId() << " " << "InteractionTypeId = " << gev.Summary()->ProcInfo().InteractionTypeId() << std::endl << genie::ScatteringType::AsString( gev.Summary()->ProcInfo().ScatteringTypeId()) << " " << genie::InteractionType::AsString( gev.Summary()->ProcInfo().InteractionTypeId()) << " " << gev.Summary()->ProcInfo().IsMEC() << std::endl; return Channel_t::kUndefined; } } // Weak CC } else if (gev.Summary()->ProcInfo().IsWeakCC()) { // CC MEC if (gev.Summary()->ProcInfo().IsMEC()) { if (utility::IsNeutralLepton(gev.Summary()->InitState().ProbePdg(), utility::pdgcodes::kMatter)) { return Channel_t::kCC2p2h; } else if (utility::IsNeutralLepton(gev.Summary()->InitState().ProbePdg(), utility::pdgcodes::kAntimatter)) { return Channel_t::kCC2p2h_nub; } // CC OTHER } else { return FromNEUTCode(genie::utils::ghep::NeutReactionCode(&gev)); } // Weak NC } else if (gev.Summary()->ProcInfo().IsWeakNC()) { // NC MEC if (gev.Summary()->ProcInfo().IsMEC()) { if (utility::IsNeutralLepton(gev.Summary()->InitState().ProbePdg(), utility::pdgcodes::kMatter)) { return Channel_t::kNC2p2h; } else if (utility::IsNeutralLepton(gev.Summary()->InitState().ProbePdg(), utility::pdgcodes::kAntimatter)) { return Channel_t::kNC2p2h_nub; } // NC OTHER } else { return FromNEUTCode(genie::utils::ghep::NeutReactionCode(&gev)); } } return Channel_t::kUndefined; } Particle::Status_t GetParticleStatus(genie::GHepParticle const &p, Channel_t chan) { /* kIStUndefined = -1, kIStInitialState = 0, / generator-level initial state / kIStStableFinalState = 1, / generator-level final state: particles to be tracked by detector-level MC / kIStIntermediateState = 2, kIStDecayedState = 3, kIStCorrelatedNucleon = 10, kIStNucleonTarget = 11, kIStDISPreFragmHadronicState = 12, kIStPreDecayResonantState = 13, kIStHadronInTheNucleus = 14, / hadrons inside the nucleus: marked for hadron transport modules to act on / kIStFinalStateNuclearRemnant = 15, / low energy nuclear fragments entering the record collectively as a 'hadronic blob' pseudo-particle / kIStNucleonClusterTarget = 16, // for composite nucleons before phase space decay */ Particle::Status_t state = Particle::Status_t::kUnknown; switch (p.Status()) { case genie::kIStNucleonTarget: case genie::kIStInitialState: case genie::kIStCorrelatedNucleon: case genie::kIStNucleonClusterTarget: { state = Particle::Status_t::kPrimaryInitialState; break; } case genie::kIStStableFinalState: { state = Particle::Status_t::kNuclearLeaving; break; } case genie::kIStHadronInTheNucleus: { state = utility::Is2p2h(chan) ? Particle::Status_t::kPrimaryInitialState : Particle::Status_t::kIntermediate; break; } case genie::kIStPreDecayResonantState: case genie::kIStDISPreFragmHadronicState: case genie::kIStIntermediateState: { state = Particle::Status_t::kIntermediate; break; } case genie::kIStFinalStateNuclearRemnant: case genie::kIStUndefined: case genie::kIStDecayedState: default: { state = Particle::Status_t::kUnknown; } } if (utility::IsNuclearPDG(p.Pdg())) { if (state == Particle::Status_t::kPrimaryInitialState) { state = Particle::Status_t::kPrimaryInitialState; } else if (state == Particle::Status_t::kNuclearLeaving) { state = Particle::Status_t::kPrimaryFinalState; } } return state; } struct TargetSplineBlob { double MolecularWeight; size_t NNucleons; std::string search_term; TGraph TotSpline; }; NEW_NUIS_EXCEPT(Invalid_target_specifier); -double GetFileWeight(fhicl::ParameterSet const &xsecinfo) { +double GetFileWeight(fhicl::ParameterSet const &xsecinfo, + std::set const &spline_list) { double mec_scale = xsecinfo.get("mec_scale", 1); double EMin = xsecinfo.get("EMin", 0); double EMax = xsecinfo.get("EMax", 10); size_t NKnots = xsecinfo.get("NKnots", 100); std::vector TargetSplines; int probe = xsecinfo.get("nu_pdg"); for (std::string const &target : xsecinfo.get>("target")) { std::vector splits = nuis::utility::split(target, ";"); if (splits.size() != 1 && splits.size() != 2) { throw Invalid_target_specifier() << "Expected to find 100ZZZAAA0;, e.g. " "1000060120;1, " "but found: \"" << target << "\""; } std::stringstream ss; ss << ".*nu:" << probe << ";tgt:" << splits[0] << ".*"; size_t nuc_pdg = fhicl::string_parsers::str2T(splits[0]); double molwght = splits.size() == 2 ? fhicl::string_parsers::str2T(splits[1]) : 1; TargetSplines.push_back( {molwght, (nuc_pdg % 1000) / 10, ss.str(), TGraph()}); std::cout << "[INFO]:\tGetting splines that match: \"" << ss.str() << "\" with A = " << TargetSplines.back().NNucleons << " and multiplied by " << molwght / double(TargetSplines.back().NNucleons) << std::endl; } size_t NTotNucleons = 0; std::vector spline_patterns; for (auto const &spb : TargetSplines) { spline_patterns.push_back(spb.search_term); NTotNucleons += spb.MolecularWeight * spb.NNucleons; } double WeightToPerNucleon = 1.0 / double(NTotNucleons); // Read the spline file std::cout << "[INFO]: Reading input file: " << xsecinfo.get("spline_file") << ", this may take a while..." << std::endl; GENIESplineGetter spg(spline_patterns); spg.ParseFile(xsecinfo.get("spline_file").c_str()); std::vector> all_splines = spg.GetTGraphs(); double step = (EMax - EMin) / double(NKnots); // Sum each targets-worth of interaction splines together, weighting for // molecular fraction and possibly fixing the MEC spline oddity for (size_t ts_it = 0; ts_it < TargetSplines.size(); ++ts_it) { TargetSplines[ts_it].TotSpline = TGraph(NKnots); - for (Int_t p_it = 0; p_it < NKnots; ++p_it) { + for (size_t p_it = 0; p_it < NKnots; ++p_it) { TargetSplines[ts_it].TotSpline.SetPoint(p_it, EMin + p_it * step, 0); } double target_weight = (TargetSplines[ts_it].MolecularWeight / double(TargetSplines[ts_it].NNucleons)); for (size_t c_it = 0; c_it < all_splines[ts_it].size(); ++c_it) { double weight = target_weight; if (std::string(all_splines[ts_it][c_it].GetName()).find("MEC") != std::string::npos) { if (mec_scale != 1) { std::cout << "[INFO]: Weighting MEC splines by " << mec_scale << std::endl; weight *= mec_scale; } } - for (Int_t p_it = 0; p_it < NKnots; ++p_it) { + for (size_t p_it = 0; p_it < NKnots; ++p_it) { double E, XSec; TargetSplines[ts_it].TotSpline.GetPoint(p_it, E, XSec); // Copied from GENIE/Convents/Units.h static const double gigaelectronvolt = 1.; static const double GeV = gigaelectronvolt; static const double meter = 5.07e+15 / GeV; static const double centimeter = 0.01 * meter; static const double centimeter2 = centimeter * centimeter; XSec += all_splines[ts_it][c_it].Eval(E) * weight / centimeter2; TargetSplines[ts_it].TotSpline.SetPoint(p_it, E, XSec); } } } // Sum all the correctly weighted per-target splines TGraph MasterSpline(NKnots); - for (Int_t p_it = 0; p_it < NKnots; ++p_it) { + for (size_t p_it = 0; p_it < NKnots; ++p_it) { MasterSpline.SetPoint(p_it, EMin + p_it * step, 0); } for (size_t c_it = 0; c_it < TargetSplines.size(); ++c_it) { - for (Int_t p_it = 0; p_it < NKnots; ++p_it) { + for (size_t p_it = 0; p_it < NKnots; ++p_it) { double E, XSec; MasterSpline.GetPoint(p_it, E, XSec); XSec += TargetSplines[c_it].TotSpline.Eval(E) * WeightToPerNucleon; MasterSpline.SetPoint(p_it, E, XSec); } } + nuis::utility::TFile_ptr outfile(nullptr, [](TFile *) {}); + if (xsecinfo.has_key("spline_output_file")) { + outfile = nuis::utility::CheckOpenTFile( + xsecinfo.get("spline_output_file"), "RECREATE"); + + for (auto &sp : TargetSplines) { + std::string spname = nuis::utility::SanitizeROOTObjectName( + sp.search_term.substr(2, sp.search_term.length() - 4)); + std::cout << "[INFO]: Dumping spline: " << spname << std::endl; + nuis::utility::WriteToTFile(outfile, &sp.TotSpline, spname.c_str()); + } + nuis::utility::WriteToTFile(outfile, &MasterSpline, "TotalXSec"); + } + fhicl::ParameterSet fluxps = xsecinfo.get("flux"); // If MonoE if (fluxps.has_key("energy_GeV")) { double monoE = fluxps.get("energy_GeV"); return MasterSpline.Eval(monoE); } else { // Use the master spline to get flux*xsec (which the events are thrown // according to) and return the flux-averaged total xsec which is used for // weighting std::unique_ptr Flux = nuis::utility::GetHistogram(fluxps.get("histogram")); + + if (outfile) { + std::unique_ptr Fluxcp = nuis::utility::Clone(Flux); + nuis::utility::WriteToTFile(outfile, Fluxcp.get(), "Flux"); + } + bool per_width = fluxps.get("is_divided_by_bin_width", true); double FluxIntegral = Flux->Integral(per_width ? "width" : ""); for (int bi_it = 0; bi_it < Flux->GetXaxis()->GetNbins(); ++bi_it) { double bc = Flux->GetBinContent(bi_it + 1); double low_e = Flux->GetXaxis()->GetBinLowEdge(bi_it + 1); double up_e = Flux->GetXaxis()->GetBinUpEdge(bi_it + 1); size_t NIntSteps = 100; double step = (up_e - low_e) / double(NIntSteps); double avg_xsec = 0; for (size_t i = 0; i < NIntSteps; ++i) { double e = low_e + (double(i) + 0.5) * step; avg_xsec += MasterSpline.Eval(e); } avg_xsec /= double(NIntSteps); Flux->SetBinContent(bi_it + 1, bc * avg_xsec); } + if (outfile) { + std::unique_ptr Fluxcp = nuis::utility::Clone(Flux); + nuis::utility::WriteToTFile(outfile, Fluxcp.get(), "EvRate"); + } + double EvRateIntegral = Flux->Integral(per_width ? "width" : ""); return EvRateIntegral / FluxIntegral; } } } // namespace genietools } // namespace nuis diff --git a/src/generator/utility/GENIEUtility.hxx b/src/generator/utility/GENIEUtility.hxx index 3bc447a..bb25aef 100644 --- a/src/generator/utility/GENIEUtility.hxx +++ b/src/generator/utility/GENIEUtility.hxx @@ -1,53 +1,53 @@ // Copyright 2018 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 . *******************************************************************************/ #pragma once #include "event/Particle.hxx" #include "event/types.hxx" +#include + class TGraph; namespace genie { class GHepRecord; class GHepParticle; } // namespace genie namespace fhicl { class ParameterSet; } namespace nuis { namespace genietools { NEW_NUIS_EXCEPT(invalid_GENIE_event); -TGraph const &GetGENIESpline(std::string const &SplineFile, - std::string const &SplineIdentifier); - event::Channel_t GetEventChannel(genie::GHepRecord const &); event::Particle::Status_t GetParticleStatus(genie::GHepParticle const &p, event::Channel_t chan); -double GetFileWeight(fhicl::ParameterSet const &xsecinfo); +double GetFileWeight(fhicl::ParameterSet const &xsecinfo, + std::set const &spline_list = {}); } // namespace genietools } // namespace nuis diff --git a/src/input/IInputHandler.hxx b/src/input/IInputHandler.hxx index fcb467e..205ea65 100644 --- a/src/input/IInputHandler.hxx +++ b/src/input/IInputHandler.hxx @@ -1,122 +1,123 @@ // Copyright 2018 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 . *******************************************************************************/ #pragma once #include "plugins/traits.hxx" #include "exception/exception.hxx" #include "generator/GeneratorManager.hxx" #include #include namespace fhicl { class ParameterSet; } namespace nuis { namespace event { class MinimalEvent; class FullEvent; } // namespace event } // namespace nuis class IInputHandler { public: struct FullEvent_const_iterator : public std::iterator< std::input_iterator_tag, nuis::event::FullEvent const, size_t, nuis::event::FullEvent const *, nuis::event::FullEvent const &> { FullEvent_const_iterator(size_t _idx, IInputHandler const *_ih) { idx = _idx; ih = _ih; } FullEvent_const_iterator(FullEvent_const_iterator const &other) { idx = other.idx; ih = other.ih; } FullEvent_const_iterator operator=(FullEvent_const_iterator const &other) { idx = other.idx; ih = other.ih; return (*this); } bool operator==(FullEvent_const_iterator const &other) { return (idx == other.idx); } bool operator!=(FullEvent_const_iterator const &other) { return !(*this == other); } nuis::event::FullEvent const &operator*() { return ih->GetFullEvent(idx); } nuis::event::FullEvent const *operator->() { return &ih->GetFullEvent(idx); } FullEvent_const_iterator operator++() { idx++; return *this; } FullEvent_const_iterator operator++(int) { FullEvent_const_iterator tmp(*this); idx++; return tmp; } private: size_t idx; IInputHandler const *ih; }; NEW_NUIS_EXCEPT(invalid_input_file); NEW_NUIS_EXCEPT(invalid_entry); NEW_NUIS_EXCEPT(input_handler_feature_unimplemented); typedef size_t ev_index_t; virtual void Initialize(fhicl::ParameterSet const &) = 0; + virtual void GetEntry(ev_index_t) const = 0; virtual nuis::event::MinimalEvent const & GetMinimalEvent(ev_index_t idx) const = 0; virtual nuis::event::FullEvent const &GetFullEvent(ev_index_t idx) const = 0; virtual void RecalculateEventWeights(){}; virtual double GetEventWeight(ev_index_t) const { return 1; }; /// Allows samples that implement flux cuts to request an appropriate virtual double GetXSecScaleFactor( std::pair const &EnuRange = std::pair{ std::numeric_limits::max(), std::numeric_limits::max()}) const = 0; virtual size_t GetNEvents() const = 0; FullEvent_const_iterator begin() const { return FullEvent_const_iterator(0, this); } FullEvent_const_iterator end() const { return FullEvent_const_iterator(GetNEvents(), this); } virtual ~IInputHandler() {} virtual nuis::GeneratorManager::Generator_id_t GetGeneratorId() const = 0; }; DECLARE_PLUGIN_INTERFACE(IInputHandler); diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt new file mode 100644 index 0000000..c0f8bcb --- /dev/null +++ b/src/tests/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(memcheck) diff --git a/src/tests/memcheck/CMakeLists.txt b/src/tests/memcheck/CMakeLists.txt new file mode 100644 index 0000000..c3fb4e8 --- /dev/null +++ b/src/tests/memcheck/CMakeLists.txt @@ -0,0 +1,30 @@ +SET(TESTS InputHandlerCheck) + +foreach(a ${TESTS}) + add_executable(${a} ${a}.cxx) + target_link_libraries(${a} -Wl,--no-as-needed nuis_event nuis_input nuis_utility_experimental nuis_utility nuis_config nuis_persistency nuis_plugins nuis_params nuis_variation InputHandlers) + target_link_libraries(${a} ${GENERATOR_DEPENDENT_TARGETS} -Wl,--as-needed) + target_link_libraries(${a} ${NUISANCE_LINK_DIRS}) + target_link_libraries(${a} ${NUISANCE_DEPEND_LIBS}) + + if(NOT "${CMAKE_LINK_FLAGS}" STREQUAL "") + set_target_properties(${a} PROPERTIES LINK_FLAGS ${CMAKE_LINK_FLAGS}) + endif() + + if(USE_GENIE) + target_compile_options(${a} PUBLIC ${GENIE_CXX_FLAGS}) + include_directories(${GENIE_INCLUDE_DIRS}) + endif() + + if(USE_NEUT) + target_compile_options(${a} PUBLIC ${NEUT_CXX_FLAGS}) + include_directories(${NEUT_INCLUDE_DIRS}) + endif() + + if(USE_NUWRO) + target_compile_options(${a} PUBLIC ${NUWRO_CXX_FLAGS}) + include_directories(${NUWRO_INCLUDE_DIRS}) + endif() + + install(TARGETS ${a} DESTINATION test) +endforeach() diff --git a/src/tests/memcheck/InputHandlerCheck.cxx b/src/tests/memcheck/InputHandlerCheck.cxx new file mode 100644 index 0000000..9a795ad --- /dev/null +++ b/src/tests/memcheck/InputHandlerCheck.cxx @@ -0,0 +1,156 @@ +#include "config/GlobalConfiguration.hxx" + +#ifdef USE_GENIE +#include "generator/input/GENIEInputHandler.hxx" +#endif +#ifdef USE_NEUT +#include "generator/input/NEUTInputHandler.hxx" +#endif +#include "input/InputManager.hxx" + +#include "event/MinimalEvent.hxx" + +#include "exception/exception.hxx" + +#include "utility/StringUtility.hxx" + +#include "fhiclcpp/make_ParameterSet.h" +#include "string_parsers/from_string.hxx" + +#include + +NEW_NUIS_EXCEPT(invalid_cli_arguments); + +void SayUsage(char const *argv[]) { + std::cout + << "[USAGE]: " << argv[0] + << "\n" + "\t-c : FHiCL file containing study " + "configuration. \n" + "\t-s : FHiCL key of a single sample " + "to run from the -c argument. \n" + "\t-n : Number of events toload. \n" +#ifdef USE_GENIE + "\t--genie : Just use GENIEInputHandler directly " +#endif +#ifdef USE_NEUT + "\t--neut : Just use NEUTInputHandler directly " +#endif + "\t-G : Just use GetEntry directly " + "rather than the GetMinimalEvent interface." + << std::endl; +} + +std::string fhicl_file = ""; +std::string named_sample = ""; +size_t NTries = 0; +bool GetEntry = false; + +enum EGen { + kManager, +#ifdef USE_NEUT + kNEUT, +#endif +#ifdef USE_GENIE + kGENIE, +#endif +}; +EGen WhichGen = kManager; + +void handleOpts(int argc, char const *argv[]) { + int opt = 1; + while (opt < argc) { + if ((std::string(argv[opt]) == "-?") || + (std::string(argv[opt]) == "--help")) { + SayUsage(argv); + exit(0); + } else if (std::string(argv[opt]) == "-c") { + fhicl_file = argv[++opt]; + } else if (std::string(argv[opt]) == "-s") { + named_sample = argv[++opt]; + } else if (std::string(argv[opt]) == "-n") { + NTries = fhicl::string_parsers::str2T(argv[++opt]); + } else if (std::string(argv[opt]) == "-G") { + GetEntry = true; + } +#ifdef USE_GENIE + else if (std::string(argv[opt]) == "--genie") { + WhichGen = kGENIE; + } +#endif +#ifdef USE_NEUT + else if (std::string(argv[opt]) == "--neut") { + WhichGen = kNEUT; + } +#endif + else { + std::cout << "[ERROR]: Unknown option: " << argv[opt] << std::endl; + SayUsage(argv); + exit(1); + } + opt++; + } +} + +int main(int argc, char const *argv[]) { + nuis::config::EnsureConfigurationRead("nuis.global.config.fcl"); + nuis::config::EnsureConfigurationRead("nuis.datacomparisons.fcl"); + + handleOpts(argc, argv); + + if (!fhicl_file.size()) { + SayUsage(argv); + throw invalid_cli_arguments(); + } + + nuis::config::EnsureConfigurationRead(fhicl_file); + + fhicl::ParameterSet inps = + nuis::config::GetDocument().get(named_sample); + IInputHandler const *IH; + + switch (WhichGen) { + case kManager: { + auto id = nuis::input::InputManager::Get().EnsureInputLoaded(inps); + IH = &nuis::input::InputManager::Get().GetInputHandler(id); + break; + } +#ifdef USE_NEUT + case kNEUT: { + IInputHandler *IIH = new NEUTInputHandler(); + IIH->Initialize(inps); + IH = IIH; + break; + } +#endif +#ifdef USE_GENIE + case kGENIE: { + IInputHandler *IIH = new GENIEInputHandler(); + IIH->Initialize(inps); + IH = IIH; + break; + } +#endif + default: { + std::cout << "[ERROR]: Invalid input handler type." << std::endl; + return 1; + } + } + + size_t ShoutEvery = NTries / 100; + + std::cout << "[INFO]: Read " << 0 << "/" << NTries << " GENIE events." + << std::flush; + for (size_t t_it = 0; t_it < NTries; ++t_it) { + if (ShoutEvery && !(t_it % ShoutEvery)) { + std::cout << "\r[INFO]: Read " << t_it << "/" << NTries + << " GENIE events." << std::flush; + } + if (GetEntry) { + IH->GetEntry(0); + } else { + IH->GetMinimalEvent(0); + } + } + std::cout << std::endl; +} diff --git a/src/utility/ROOTUtility.hxx b/src/utility/ROOTUtility.hxx index 75b0d47..2099789 100644 --- a/src/utility/ROOTUtility.hxx +++ b/src/utility/ROOTUtility.hxx @@ -1,164 +1,181 @@ // Copyright 2018 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 . *******************************************************************************/ #ifndef UTILITY_ROOTUTILITY_HXX_SEEN #define UTILITY_ROOTUTILITY_HXX_SEEN #include "exception/exception.hxx" #include "TFile.h" #include "TTree.h" #include #include #include #include namespace nuis { namespace utility { NEW_NUIS_EXCEPT(failed_to_open_TFile); NEW_NUIS_EXCEPT(failed_to_get_TTree); +NEW_NUIS_EXCEPT(WriteToTFile_nullptr); inline void CloseTFile(TFile *f = nullptr) { if (f) { std::cout << "[INFO]: Shutting TFile: " << f->GetName() << ", " << f << std::endl; f->Close(); } delete f; } using TFile_ptr = std::unique_ptr; inline TFile_ptr make_unique_TFile(TFile *f) { return TFile_ptr(f, &CloseTFile); } inline TFile_ptr CheckOpenTFile(std::string const &fname, char const *opts = "") { TDirectory *ogDir = gDirectory; TFile *inpF = new TFile(fname.c_str(), opts); if (!inpF || !inpF->IsOpen()) { throw failed_to_open_TFile() << "[ERROR]: Couldn't open input file: " << std::quoted(fname); } if (ogDir) { ogDir->cd(); } return make_unique_TFile(inpF); } struct TreeFile { TFile_ptr file; TTree *tree; bool file_owned; TreeFile() : file(make_unique_TFile(nullptr)), tree(nullptr), file_owned(false) {} TreeFile(TreeFile const &other) = delete; TreeFile &operator=(TreeFile &&other) { file = std::move(other.file); tree = other.tree; file_owned = other.file_owned; other.file = nullptr; other.tree = nullptr; other.file_owned = false; return *this; } TreeFile(TreeFile &&other) : file(std::move(other.file)), tree(other.tree), file_owned(other.file_owned) { other.file = nullptr; other.tree = nullptr; other.file_owned = false; } TTree *operator->() { return tree; } ~TreeFile() { if (!file_owned) { file.release(); } } }; inline TreeFile CheckGetTTree(TFile *file, std::string const &tname) { TreeFile tf; tf.file = make_unique_TFile(file); tf.tree = dynamic_cast(tf.file->Get(tname.c_str())); tf.file_owned = false; if (!tf.tree) { throw failed_to_get_TTree() << "[ERROR]: Failed to get TTree named: " << std::quoted(tname) << " from TFile: " << std::quoted(file->GetName()); } std::cout << "[INFO]: Opened TFile: " << file->GetName() << ", " << file << std::endl; return tf; } inline TreeFile CheckGetTTree(std::string const &fname, std::string const &tname, char const *opts = "") { TreeFile tf = CheckGetTTree(CheckOpenTFile(fname, opts).release(), tname); tf.file_owned = true; return tf; } inline TreeFile MakeNewTTree(std::string const &fname, std::string const &tname, char const *opts = "") { TreeFile tf; tf.file = CheckOpenTFile(fname, opts); tf.tree = new TTree(tname.c_str(), ""); tf.tree->SetDirectory(tf.file.get()); tf.file_owned = true; return tf; } inline TreeFile AddNewTTreeToFile(TFile *f, std::string const &tname, std::string const &dirname = "") { TreeFile tf; // This is pretty dumb... tf.file = make_unique_TFile(f); tf.tree = new TTree(tname.c_str(), ""); if (dirname.size()) { TDirectory *dir = tf.file->GetDirectory(dirname.c_str()); if (!dir) { dir = tf.file->mkdir(dirname.c_str()); } tf.tree->SetDirectory(dir); } else { tf.tree->SetDirectory(tf.file.get()); } tf.file_owned = false; return tf; } inline std::string SanitizeROOTObjectName(std::string name) { return name; } +inline void WriteToTFile(TFile_ptr &tf, TObject *object, + std::string const &object_name) { + if (!object) { + throw WriteToTFile_nullptr(); + } + + TDirectory *ogdir = gDirectory; + + tf->cd(); + object->Write(object_name.c_str(), TObject::kOverwrite); + + if (ogdir) { + ogdir->cd(); + } +} + } // namespace utility } // namespace nuis #endif