diff --git a/.gitignore b/.gitignore index df5fd5ce..2567bd0a 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,6 @@ build*/ dist*/ Python/*.egg-info __pycache__ + +# untracked directory +untracked*/ diff --git a/Cpp/Library/CMakeLists.txt b/Cpp/Library/CMakeLists.txt index c99c80ca..44f4a7b3 100644 --- a/Cpp/Library/CMakeLists.txt +++ b/Cpp/Library/CMakeLists.txt @@ -34,6 +34,7 @@ set( NYMPH_HEADERFILES ${DATA_DIR}/DataPresent.hh ${DATA_DIR}/SignalData.hh ${DATA_DIR}/SlotData.hh + ${DATA_DIR}/CutStatus.hh ${CONT_DIR}/ControlAccess.hh ${CONT_DIR}/Controller.hh @@ -48,6 +49,7 @@ set( NYMPH_SOURCEFILES ${DATA_DIR}/Data.cc ${DATA_DIR}/DataFrame.cc + ${DATA_DIR}/CutStatus.cc ${PROC_DIR}/PrimaryProcessor.cc ${PROC_DIR}/Processor.cc diff --git a/Cpp/Library/Data/CutStatus.cc b/Cpp/Library/Data/CutStatus.cc new file mode 100644 index 00000000..54aad68a --- /dev/null +++ b/Cpp/Library/Data/CutStatus.cc @@ -0,0 +1,72 @@ +/* + * CutStatus.cc + * + * Created on: Aug 24, 2012 + * Author: nsoblath + */ + +#include "CutStatus.hh" +#include "logger.hh" + +namespace Nymph +{ + LOGGER(cutlog, "Cut"); + + CutStatus::CutStatus() + { + } + + CutStatus::CutStatus(const CutStatus& orig) + { + fCutResults = orig.fCutResults; + } + + CutStatus::~CutStatus() + {} + + CutStatus& CutStatus::operator=(const CutStatus& rhs) + { + //delete[] fCutResults; + fCutResults = rhs.fCutResults; + return *this; + } + + void CutStatus::AssignCutResult(const std::string& cutName, bool state) + { + LDEBUG(cutlog, "Assigning cut result <" << cutName << "> with state <" << state << ">"); + if( fCutResults.find(cutName) != fCutResults.end()) + { + throw Exception() << "Cut with name: " << cutName << " has already been assigned"; + } + fCutResults.insert(make_pair(cutName,state)); + LDEBUG(cutlog, "Cut result size is now: " << fCutResults.size() ); + return; + } + + std::vector< std::string > CutStatus::CutResultsPresent() const + { + std::vector< std::string > cutsPresent; + for (auto cutIt = fCutResults.cbegin(); cutIt != fCutResults.cend(); ++cutIt) + { + if (! cutIt->first.empty()) + { + cutsPresent.push_back(cutIt->first); + } + } + return cutsPresent; + } + + std::ostream& operator<<(std::ostream& out, const CutStatus& status) + { + out << "Cut summary: " << '\n'; + std::vector< std::string > cuts = status.CutResultsPresent(); + for (auto cutIt = cuts.cbegin(); cutIt != cuts.cend(); ++cutIt) + { + out << *cutIt << "; "; + } + out << '\n'; + return out; + } + + +} /* namespace Nymph */ diff --git a/Cpp/Library/Data/CutStatus.hh b/Cpp/Library/Data/CutStatus.hh new file mode 100644 index 00000000..d105b9b6 --- /dev/null +++ b/Cpp/Library/Data/CutStatus.hh @@ -0,0 +1,184 @@ +/* + * CutStatus.hh + * + * Created on: Sept 19, 2014 + * Author: nsoblath + */ + +#ifndef CUTSTATUS_HH_ +#define CUTSTATUS_HH_ + +#include +#include +#include + +#include "Exception.hh" + + +namespace Nymph +{ + /*! + @class CutStatus + @author N. S. Oblath + + @brief Provides easy access to cut result information. + + @details + The cut results are stored as a map with cut name as key, with value of bool of whether the cut is applied or not. + + CutStatus is typically used as a member variable of DataFrame. + + You can check if the data has been cut with the IsCut functions. + - IsCut() returns true if any cut results are true; + + When specifying a cut, bools set to true specify cuts that are applied. + + With CutStatus you can interact with individual cut results in the following ways: + - Check whether any cut results are set to true with IsCut(), + - Get the number of cut results with size(), + - Get the number of cut results with value true with NumCuts(), + - Get a reference to the cut results with CutResults(), + - Add cut results to a dataframe with AssignCutResult(), + - Remove a cut result with RemoveCutResult(), + - Check to see if a particular cut result is present using HasCutResult(), + - Get the value of a cut result with GetCutState(), + - Set the value of a cut result with SetCutState(), + - Get a vector of cut names for cuts with value==True with CutResultsPresent(), and + - Output a text summary of applied cuts with the << operator, + + */ + + class CutStatus + { + public: + typedef std::map< std::string, bool > CutResults_t; + typedef CutResults_t::iterator CutResultsIt; + typedef CutResults_t::const_iterator CutResultsCIt; + + public: + CutStatus(); + CutStatus(const CutStatus& orig); + ~CutStatus(); + + CutStatus& operator=(const CutStatus& rhs); + + /// Returns the size of the cut results map + size_t size() const; + + /// Returns a reference to the cut results map + std::map< std::string, bool > CutResults() const; + + /// Adds a new cut result with the specified name; throws Exception if a cut with that name already exists + void AssignCutResult(const std::string& cutName, bool state=false); + + /// Removes the cut by erasing the name and setting the state to false + void RemoveCutResult(const std::string& cutName); + + CutResultsIt FindCutResult(const std::string& cutName); + CutResultsCIt FindCutResultC(const std::string& cutName) const; + + CutResultsIt CutResultsEnd(); + CutResultsCIt CutResultsEndC() const; + + /// Returns whether or not the specified cut is present + bool HasCutResult(const std::string& cutName) const; + + /// Returns the state of the named cut; throws Exception if it doesn't exist + bool GetCutState(const std::string& cutName) const; + + /// Sets the state of the specified cut; throws Exception if it doesn't exist + void SetCutState(const std::string& cutName, bool state); + + /// Returns a string with the names of the cuts that are present in bitset order + std::vector< std::string > CutResultsPresent() const; + + private: + friend std::ostream& operator<<(std::ostream& out, const CutStatus& status); + + CutResults_t fCutResults; + + public: + bool IsCut() const; + bool IsCut(const std::string& mask) const; + int NumCuts() const; + + }; + + std::ostream& operator<<(std::ostream& out, const CutStatus& status); + + inline std::map< std::string, bool > CutStatus::CutResults() const // get a const of the map + { + return fCutResults; + } + + inline CutStatus::CutResultsIt CutStatus::FindCutResult( const std::string& cutName ) + { + return fCutResults.find(cutName); + } + + inline CutStatus::CutResultsCIt CutStatus::FindCutResultC( const std::string& cutName ) const + { + return fCutResults.find(cutName); + } + + inline CutStatus::CutResultsIt CutStatus::CutResultsEnd() + { + return fCutResults.end(); + } + + inline CutStatus::CutResultsCIt CutStatus::CutResultsEndC() const + { + return fCutResults.cend(); + } + + inline bool CutStatus::HasCutResult( const std::string& cutName ) const + { + return fCutResults.count(cutName); + } + + inline bool CutStatus::GetCutState( const std::string& cutName ) const + { + if (fCutResults.find(cutName) != fCutResults.end()) + { + return fCutResults.at(cutName); + } + throw Exception() << "Unable to find cut <" << cutName << ">"; + } + + inline void CutStatus::SetCutState(const std::string& cutName, bool state) + { + if (fCutResults.find(cutName) != fCutResults.end()) + { + fCutResults[cutName] = state; + return; + } + throw Exception() << "Unable to find cut <" << cutName << ">"; + } + + inline void CutStatus::RemoveCutResult(const std::string& cutName) + { + if (fCutResults.find(cutName) != fCutResults.end()) + { + fCutResults.erase(cutName); + } + return; + } + inline size_t CutStatus::size() const + { + return fCutResults.size(); + } + + inline bool CutStatus::IsCut() const + { + int stateSum = boost::accumulate(fCutResults | boost::adaptors::map_values, 0); + return stateSum > 0; + } + + inline int CutStatus::NumCuts() const + { + int stateSum = boost::accumulate(fCutResults | boost::adaptors::map_values, 0); + return stateSum; + } +} /* namespace Nymph */ + +#endif /* CUTSTATUS_HH_ */ diff --git a/Cpp/Library/Data/DataFrame.cc b/Cpp/Library/Data/DataFrame.cc index 12240592..e1cfadc6 100644 --- a/Cpp/Library/Data/DataFrame.cc +++ b/Cpp/Library/Data/DataFrame.cc @@ -10,7 +10,8 @@ namespace Nymph { DataFrame::DataFrame() : - fDataObjects() + fDataObjects(), + fCuts() {} DataFrame::~DataFrame() diff --git a/Cpp/Library/Data/DataFrame.hh b/Cpp/Library/Data/DataFrame.hh index 4e8d4631..c20895d9 100644 --- a/Cpp/Library/Data/DataFrame.hh +++ b/Cpp/Library/Data/DataFrame.hh @@ -10,6 +10,7 @@ #define NYMPH_DATAFRAME_HH_ #include "Data.hh" +#include "CutStatus.hh" #include "Exception.hh" #include "MemberVariable.hh" @@ -40,10 +41,12 @@ namespace Nymph @author N. S. Oblath - @brief Container for Data objects used during data processing + @brief Container for Data objects and their cut information used during data processing @details Individual Data objects are held in an unordered map, indexed by type. + A CutStatus object contains cut information in an ordered map, with keys of cut name. + The CutStatus describes the latest/most processed data object in the dataframe, and is updated as new data objects are added with more cuts. */ class DataFrame @@ -95,6 +98,9 @@ namespace Nymph // typedef used to avoid problems with the comma in the MEMVAR macro typedef std::unordered_map< std::type_index, std::unique_ptr > DataMap; MEMVAR_REF( DataMap, DataObjects ); + + // CutStatus object for storing cut information + CutStatus fCuts; }; diff --git a/Cpp/Library/Data/README_future_work.txt b/Cpp/Library/Data/README_future_work.txt new file mode 100644 index 00000000..3b9ea7fe --- /dev/null +++ b/Cpp/Library/Data/README_future_work.txt @@ -0,0 +1,11 @@ +This branch reworked CutStatus into an ordered map. CutResult is replaced with a map definition within CutStatus. CutStatus is stored as a member object in DataFrame. +Potential improvements: +- Replace the bool values of the CutStatus map with pair of (bool, string) so a description can be added. +- May need to restore CutResult.hh, and move the map definition there. Could be needed in future Cut.hh + +Further Cut work to be done: +- CutFilter.hh and ApplyCut.hh should be updated next. +-- See Nymph/Cpp/Library_v1/Data/KTCutFilter.hh +-- and Nymph/Cpp/Library_v1/Data/KTApplyCut.hh +- Cut.hh may also need updating + diff --git a/Testing/CMakeLists.txt b/Testing/CMakeLists.txt index e883ad9e..b167b43e 100644 --- a/Testing/CMakeLists.txt +++ b/Testing/CMakeLists.txt @@ -42,6 +42,8 @@ set( testing_SOURCES ${CPP_DIR}/TestSingleRunController.cc ${CPP_DIR}/TestSlotData.cc ${CPP_DIR}/UseCatch.cc + # Ben adding tests + ${CPP_DIR}/TestCut.cc ) set( lib_dependencies diff --git a/Testing/Cpp/TestCut.cc b/Testing/Cpp/TestCut.cc new file mode 100644 index 00000000..923bf7e6 --- /dev/null +++ b/Testing/Cpp/TestCut.cc @@ -0,0 +1,67 @@ +/* + * TestCut.cc + * + * Created on: Jan 6, 2024 + * Author: btfoust + */ + +#include "CutStatus.hh" + +#include "catch.hpp" + +TEST_CASE( "cut_present", "[cut]" ) +{ + using namespace Nymph; + //using namespace NymphTesting; + + CutStatus testCutStatus; + testCutStatus.AssignCutResult("fTestCut", 1); + + // check fTestCut applied + REQUIRE ( testCutStatus.size() == 1 ); + //REQUIRE( testCutStatus.FindCutResult("fTestCut") == 0 ); // This returns position of cut in map, not state + // check fTestCut state + REQUIRE( testCutStatus.GetCutState("fTestCut") == 1 ); + + // check default is to assign cut status FALSE + testCutStatus.AssignCutResult("fNotCut"); + REQUIRE ( testCutStatus.size() == 2 ); + REQUIRE ( testCutStatus.GetCutState("fNotCut") == 0 ); + + // Test Readout + UNSCOPED_INFO ( testCutStatus ); + //CHECK ( false ); // Force readout even if no fails + + // Check IsCut() + REQUIRE ( testCutStatus.IsCut() == true ); + + // Check Num Cuts (size but only for cuts that are true) + REQUIRE ( testCutStatus.NumCuts() == 1 ); + + // Change Cut State + testCutStatus.SetCutState("fTestCut",0); + REQUIRE ( testCutStatus.GetCutState("fTestCut") == 0); + + // Check throw if set/check state for non-existant cut + REQUIRE_THROWS ( testCutStatus.SetCutState("fMissingCut",1) ); + REQUIRE_THROWS ( testCutStatus.GetCutState("fMissingCut") ); + + // Check initialize from other cut status + CutStatus testCutStatus2(testCutStatus); + REQUIRE ( testCutStatus2.size() == 2 ); + REQUIRE ( testCutStatus2.GetCutState("fTestCut") == 0); + + // Check assignment operator + testCutStatus2.SetCutState("fNotCut",1); + testCutStatus2 = testCutStatus; + REQUIRE ( testCutStatus2.GetCutState("fNotCut") == 0); + + // Remove cuts + testCutStatus.RemoveCutResult("fTestCut"); + testCutStatus.RemoveCutResult("fNotCut"); + REQUIRE ( testCutStatus.size() == 0 ); + testCutStatus2.RemoveCutResult("fTestCut"); + testCutStatus2.RemoveCutResult("fNotCut"); + REQUIRE ( testCutStatus2.size() == 0 ); + +} diff --git a/Testing/Cpp/TestDataFrame.cc b/Testing/Cpp/TestDataFrame.cc index 100ca626..1d8ad6c7 100644 --- a/Testing/Cpp/TestDataFrame.cc +++ b/Testing/Cpp/TestDataFrame.cc @@ -24,6 +24,10 @@ TEST_CASE( "data_frame", "[data]" ) REQUIRE_FALSE( frame.Has< TestData1 >() ); REQUIRE_FALSE( frame.Has< TestData2 >() ); + // check Cut Status functioning + frame.fCuts.AssignCutResult("fTestCut", 1); + REQUIRE ( frame.fCuts.GetCutState("fTestCut") == 1); + // create a data object with Get() TestData1& data1 = frame.Get< TestData1 >(); REQUIRE( frame.Has< TestData1 >() );