diff --git a/README.md b/README.md index 2d48c3cb9..a106d4366 100644 --- a/README.md +++ b/README.md @@ -77,3 +77,4 @@ source util/clang-format-all.sh * [Static analyzer using Clang-tidy](config/clang_tidy/README.md) * [CMake build system for R3BRoot](doc/cmake_usage.md) +* [How to use an unmerged pull request](doc/git_usage.md#fetch-the-update-from-an-unmerged-pull-request-pr) diff --git a/doc/git_usage.md b/doc/git_usage.md new file mode 100644 index 000000000..ff91eb622 --- /dev/null +++ b/doc/git_usage.md @@ -0,0 +1,187 @@ +## Fetch the update from an unmerged pull request (PR) + +More often than not, people need to use new features from a pull request that is not yet merged to the dev branch. In this case, the new features can still be added to your local repository with following steps: + +### Step 1: Identify the remote and branch name + +Go to the [R3BRoot pull request](https://github.com/R3BRootGroup/R3BRoot/pulls) webpage and find the pull request that has the new features you need. For example: + +![git_pr](pics/git_pr_example.png) + +In the example above, you could see the pull request is made from `YanzhaoW:edwin_filesource_update`. Here the user who made the PR has the account name "YanzhaoW". The branch, which is used to create the PR, is called "edwin_filesource_update". His remote repository can be checked by clicking this `YanzhaoW:edwin_filesource_update` and you will be redirected to the webpage of his remote repository. As for the example above, the remote url can be check by clicking the green button and choose the `HTTPS` tab: + + + +In this case, the remote url is `https://github.com/YanzhaoW/R3BRoot.git`. + +### Step 2: Add the remote + +First, go to your local repository and check all your existing avaliable remote urls: + +```bash +git remote -v +``` + +the output could be: + +```text +origin git@github.com:YanzhaoW/R3BRoot.git (fetch) +origin git@github.com:YanzhaoW/R3BRoot.git (push) +pulrich git@github.com:P-Ulrich/R3BRoot_Fork.git (fetch) +pulrich git@github.com:P-Ulrich/R3BRoot_Fork.git (push) +slonzen https://github.com/SimonL2718/R3BRoot.git (fetch) +slonzen https://github.com/SimonL2718/R3BRoot.git (push) +upstream https://github.com/R3BRootGroup/R3BRoot.git (fetch) +upstream https://github.com/R3BRootGroup/R3BRoot.git (push) + +``` + +Here each remote url is attached to an unique name, called "remote name". One special url, namely `https://github.com/R3BRootGroup/R3BRoot.git`, represents the git repository of R3BRoot, which everyone pushes the updates to. Thus, when you need to update your dev branch, please use the remote name corresponding to this remote url. In the case above, the remote name is "upstream". + +If the remote url from the step 1 already exists, go to step 3. If you can't find the remote url from the step 1, please add it with: + +```bash +git remote add [remote name] [remote url] +``` + +For example + +```bash +git remote add yanzhao https://github.com/YanzhaoW/R3BRoot.git +``` + +You can use a different remote name for the new remote url. But please make sure it's different from all existing remote names. Once this is done, check the remotes again with `git remote -v` to make sure the new remote is added correclty. + +### Step 3: Update the dev branch + +Once the new remote name is added, first make sure you are in a clean git status: + +```bash +git status +``` + +you should expect an message with "nothing to commit, working tree clean". If not, either commit the changes or reset to last commit (ATTENTION: if you use reset, all the uncommitted changes would be lost): + +```bash +git reset --hard HEAD +``` + +After git status is clean, switch to dev branch and update it from the upstream + +```bash +git checkout dev +git pull --rebase upstream dev +``` + +Here the name "upstream" is the remote name that points to the remote url `https://github.com/R3BRootGroup/R3BRoot`. Change "upstream" to the corresponding name if you have a different situation. + +### Step 4: Fetch the update from the remote + +After dev branch is updated, now you need to fetch the update from the pull request. + +```bash +git fetch [remote name] [branch name] +``` + +Here the `[remote name]` is the name you used/found in step 2 and `[branch name]` is the branch name you identified in step 1. + +### Step 5: Checkout + +After the update is fetched, check the new branch with: + +```bash +git checkout [banch name] +``` + +Here, again, `[branch name]` is the branch name you identified in step 1. + +### Step 6: Recompile the program + +Recompile the program with: + +```bash +cmake --build ./build -- -j${number_of_threads} +source build/config.sh +``` + +### How to apply the changes on a new branch + +First, make sure you are in the branch that contains the changes and git status is clean. Then to apply your changes on another branch, use: + +```bash +git rebase [another branch] +``` + +It's likely that you encounter some "conflicts" that must be resolved before moving forward. If this happens, please refer to [Resolving merge conflicts after a Git rebase](https://docs.github.com/en/get-started/using-git/resolving-merge-conflicts-after-a-git-rebase) for the instruction. + +### How to pull the latest version of the pull request branch + +To pull the latest version, use + +```bash +git pull --rebase [remote name] [branch name] +``` + +Note that this may fail if the person who made the PR `force push`ed the update to his remote. In such case, first go to the dev branch and delete the remote branch: + +```bash +git checkout dev +git branch -D remote_branch_name +``` + +then start it over from step 4. + +## How to make your local git repository in a clean state + +Whenever you need to pull the updates from the dev branch or other people's branch, your git repository must be in a **clean state**: + +```bash +git status +``` + +if your state is clean, you should get a message "nothing to commit, working tree clean". If not, use one of the following methods. + +### Method 1: commit to your own branch + +#### step 1: Create new branch if necessary + +First make sure you are not in the dev or master branch (which can be checked by `git branch`). If so, create a new branch for your changes: + +```bash +git checkout -b [branch name] +``` +Here `[branch name]` is can any name. Once on the new branch, commit all the changes to the new branch: + +```bash +git add -A +git commit -m "any message you want to write for the branch" +``` + +After this is done, go back to the dev branch: + +```bash +git checkout dev +``` + +### Method 2: Reset back to the latest commit + +If you don't need any uncommitted changes, you could reset it back to the latest head of the current branch: + +```bash +git reset --hard HEAD +``` +Be aware that this will erase any uncommitted change permanently. + +### Method 3: Stash the change + +You could first put all the changes into a temporary stash with + +```bash +git stash +``` + +After you completed all the actions, to get your changes back: + +```bash +git stash pop +``` diff --git a/doc/pics/git_green_button.png b/doc/pics/git_green_button.png new file mode 100644 index 000000000..2fe7938c8 Binary files /dev/null and b/doc/pics/git_green_button.png differ diff --git a/doc/pics/git_pr_example.png b/doc/pics/git_pr_example.png new file mode 100644 index 000000000..2f90915eb Binary files /dev/null and b/doc/pics/git_pr_example.png differ diff --git a/neuland/executables/neulandAna.cxx b/neuland/executables/neulandAna.cxx index 513cfcebe..f488115f8 100644 --- a/neuland/executables/neulandAna.cxx +++ b/neuland/executables/neulandAna.cxx @@ -1,4 +1,3 @@ -#include "FairFileSource.h" #include "FairParRootFileIo.h" #include "FairRootFileSink.h" #include "FairRunAna.h" @@ -12,7 +11,6 @@ #include "R3BNeulandDigitizer.h" #include "R3BNeulandHitMon.h" #include "R3BProgramOptions.h" -#include "TRandom3.h" #include "TStopwatch.h" #include #include @@ -42,8 +40,10 @@ auto main(int argc, const char** argv) -> int programOptions.Create_Option("paddle", R"(set the paddle name. e.g. "neuland")", "neuland"); auto channelName = programOptions.Create_Option("channel", R"(set the channel name. e.g. "tamex")", "tacquila"); - auto simuFileName = - programOptions.Create_Option("simuFile", "set the filename of simulation input", "simu.root"); + auto simuFileName = programOptions.Create_Option( + "simuFile", "set the filename of simulation input generated by R3BRoot", "simu.root"); + auto simuTreeFileName = + programOptions.Create_Option("simuTreeFile", "set the filename of simulation tree-only input", ""); auto paraFileName = programOptions.Create_Option("paraFile", "set the filename of parameter sink", "para.root"); auto paraFileName2 = @@ -52,6 +52,7 @@ auto main(int argc, const char** argv) -> int programOptions.Create_Option("digiFile", "set the filename of digitization output", "digi.root"); auto logLevel = programOptions.Create_Option("logLevel,v", "set log level of fairlog", "error"); auto eventNum = programOptions.Create_Option("eventNum,n", "set total event number", 0); + auto run_id = programOptions.Create_Option("run-id", "set the run ID (Only needed if reading only trees)", -1); auto hitLevelPar = programOptions.Create_Option("hitLevelPar", "set the name of hit level parameter if needed.", ""); @@ -108,7 +109,18 @@ auto main(int argc, const char** argv) -> int FairLogger::GetLogger()->SetLogScreenLevel(logLevel->value().c_str()); auto run = std::make_unique(); - auto filesource = std::make_unique(simuFileName->value().c_str()); + auto fairroot_input_files = R3B::GetFilesFromRegex(simuFileName->value()); + auto tree_input_files = R3B::GetFilesFromRegex(simuTreeFileName->value()); + auto filesource = std::make_unique(); + if (run_id->value() >= 0) + { + filesource->SetInitRunID(run_id->value()); + R3BLOG(info, fmt::format("Filesource2: Set to run id {}", run_id->value())); + } + + filesource->AddFile(std::move(tree_input_files), true); + filesource->AddFile(std::move(fairroot_input_files), false); + auto filesink = std::make_unique(digiFileName->value().c_str()); run->SetSource(filesource.release()); run->SetSink(filesink.release()); diff --git a/r3bbase/CMakeLists.txt b/r3bbase/CMakeLists.txt index c4e2f0d6b..19275fc4e 100644 --- a/r3bbase/CMakeLists.txt +++ b/r3bbase/CMakeLists.txt @@ -68,7 +68,7 @@ add_library_with_dictionary( if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9) message(STATUS "Linking -lstdc++fs due to the old version of gcc") - target_link_libraries(R3BBase PRIVATE -lstdc++fs) + target_link_libraries(R3BBase PUBLIC -lstdc++fs) endif() if("${FairRoot_VERSION}" VERSION_LESS 19.0.0) diff --git a/r3bbase/R3BFileSource2.cxx b/r3bbase/R3BFileSource2.cxx index cbc430ae9..b9172cf92 100644 --- a/r3bbase/R3BFileSource2.cxx +++ b/r3bbase/R3BFileSource2.cxx @@ -12,6 +12,7 @@ ******************************************************************************/ #include "R3BFileSource2.h" + #include "R3BException.h" #include "R3BLogger.h" #include @@ -221,16 +222,16 @@ void R3BEventProgressPrinter::Print(uint64_t event_num, double speed_per_ms) std::cout << std::flush; } -auto R3BInputRootFiles::AddFileName(std::string fileName) -> std::optional +auto R3BInputRootFiles::AddFileName(std::string fileName, bool is_tree_file) -> std::optional { auto const msg = fmt::format("Adding {} to file source\n", fileName); R3BLOG(info, msg); if (fileNames_.empty()) { - Intitialize(fileName); + Intitialize(fileName, is_tree_file); register_branch_name(); } - if (!ValidateFile(fileName)) + if (!ValidateFile(fileName, is_tree_file)) { return fileName; } @@ -289,11 +290,11 @@ auto R3BInputRootFiles::ExtractMainFolder(TFile* rootFile) -> std::optional bool +auto R3BInputRootFiles::ValidateFile(const std::string& filename, bool is_tree_file) -> bool { auto rootFile = R3B::make_rootfile(filename.c_str()); - if (is_tree_file_) + if (is_tree_file) { if (!is_friend_) { @@ -334,11 +335,11 @@ auto R3BInputRootFiles::ExtractRunId(TFile* rootFile) -> std::optional return runID; } -void R3BInputRootFiles::Intitialize(std::string_view filename) +void R3BInputRootFiles::Intitialize(std::string_view filename, bool is_tree_file) { auto file = R3B::make_rootfile(filename.data()); - if (is_tree_file_) + if (is_tree_file) { branchList_ = GetBranchListFromTree(file.get(), treeName_); return; @@ -424,9 +425,9 @@ R3BFileSource2::R3BFileSource2() { } -void R3BFileSource2::AddFile(std::string fileName) +void R3BFileSource2::AddFile(std::string file_name, bool is_tree_file) { - if (auto const res = inputDataFiles_.AddFileName(std::move(fileName)); res.has_value()) + if (auto const res = inputDataFiles_.AddFileName(std::move(file_name), is_tree_file); res.has_value()) { if (not dataFileNames_.empty()) { @@ -438,16 +439,32 @@ void R3BFileSource2::AddFile(std::string fileName) } else { - R3BLOG(error, fmt::format("Failed to add the first root file {:?}", fileName)); + R3BLOG(error, fmt::format("Failed to add the first root file {:?}", file_name)); } } - dataFileNames_.emplace_back(fileName); + dataFileNames_.emplace_back(file_name); +} + +void R3BFileSource2::AddFile(std::vector file_names, bool is_tree_file) +{ + for (auto& file_name : file_names) + { + AddFile(std::move(file_name), is_tree_file); + } +} + +void R3BFileSource2::AddFriend(std::vector file_names, bool is_tree_file) +{ + for (auto& file_name : file_names) + { + AddFriend(std::move(file_name), is_tree_file); + } } -void R3BFileSource2::AddFriend(std::string_view fileName) +void R3BFileSource2::AddFriend(std::string file_name, bool is_tree_file) { // - auto rootfile = R3B::make_rootfile(fileName.data()); + auto rootfile = R3B::make_rootfile(file_name.c_str()); auto friendGroup = std::find_if(inputFriendFiles_.begin(), inputFriendFiles_.end(), [&rootfile](const auto& friends) @@ -460,7 +477,7 @@ void R3BFileSource2::AddFriend(std::string_view fileName) friendGroup = --inputFriendFiles_.end(); friendGroup->SetTitle(fmt::format("FriendTree_{}", inputFriendFiles_.size())); } - auto res = friendGroup->AddFileName(std::string{ fileName }); + auto res = friendGroup->AddFileName(file_name, is_tree_file); if (res.has_value()) { R3BLOG(error, @@ -471,12 +488,17 @@ void R3BFileSource2::AddFriend(std::string_view fileName) else { // TODO: really need it? - friendFileNames_.emplace_back(fileName); + friendFileNames_.emplace_back(std::move(file_name)); } } Bool_t R3BFileSource2::Init() { + if (inputDataFiles_.is_empty()) + { + throw R3B::logic_error{ "No input file available!" }; + } + inputDataFiles_.RegisterTo(FairRootManager::Instance()); for (auto& friendGroup : inputFriendFiles_) @@ -509,7 +531,7 @@ void R3BFileSource2::FillEventHeader(FairEventHeader* evtHeader) if (init_runID != GetRunId()) { R3BLOG( - error, + warn, fmt::format("runID {} being set is different from the runID {} in the data file!", GetRunId(), init_runID)); } SetRunId(init_runID); // NOLINT diff --git a/r3bbase/R3BFileSource2.h b/r3bbase/R3BFileSource2.h index 7ef4518d1..37cce9a34 100644 --- a/r3bbase/R3BFileSource2.h +++ b/r3bbase/R3BFileSource2.h @@ -48,9 +48,10 @@ class R3BInputRootFiles public: using Strings = std::vector; R3BInputRootFiles() = default; - auto AddFileName(std::string name) -> std::optional; + auto AddFileName(std::string name, bool is_tree_file = false) -> std::optional; void SetInputFileChain(TChain* chain); void RegisterTo(FairRootManager*); + [[nodiscard]] auto is_empty() const -> bool { return fileNames_.empty(); } [[nodiscard]] auto is_friend() const -> bool { return is_friend_; } void Make_as_friend() { is_friend_ = true; } @@ -69,7 +70,6 @@ class R3BInputRootFiles void SetTreeName(std::string_view treeName) { treeName_ = treeName; } void SetTitle(std::string_view title) { title_ = title; } void SetFileHeaderName(std::string_view fileHeader) { fileHeader_ = fileHeader; } - void SetEnableTreeFile(bool is_tree_file) { is_tree_file_ = is_tree_file; } void SetRunID(uint run_id) { initial_RunID_ = run_id; } // rule of five: @@ -81,7 +81,6 @@ class R3BInputRootFiles private: bool is_friend_ = false; - bool is_tree_file_ = false; uint initial_RunID_ = 0; // TODO: title of each file group seems not necessary. Consider to remove it in the future. std::string title_; @@ -95,8 +94,8 @@ class R3BInputRootFiles std::vector validMainFolders_; TChain* rootChain_ = nullptr; - void Intitialize(std::string_view filename); - auto ValidateFile(const std::string& filename) -> bool; + void Intitialize(std::string_view filename, bool is_tree_file = false); + auto ValidateFile(const std::string& filename, bool is_tree_file = false) -> bool; static auto ExtractMainFolder(TFile*) -> std::optional; auto ExtractRunId(TFile* rootFile) -> std::optional; void register_branch_name(); @@ -110,8 +109,10 @@ class R3BFileSource2 : public FairFileSourceBase R3BFileSource2(std::vector fileNames, std::string_view title); explicit R3BFileSource2(std::vector fileNames); - void AddFile(std::string); - void AddFriend(std::string_view); + void AddFile(std::string file_name, bool is_tree_file = false); + void AddFile(std::vector file_names, bool is_tree_file = false); + void AddFriend(std::string, bool is_tree_file = false); + void AddFriend(std::vector file_names, bool is_tree_file = false); [[nodiscard]] auto GetEventEnd() const { return event_end_; } @@ -119,7 +120,6 @@ class R3BFileSource2 : public FairFileSourceBase void SetFileHeaderName(std::string_view fileHeaderName) { inputDataFiles_.SetFileHeaderName(fileHeaderName); } // Set event print refresh rate in Hz void SetEventPrintRefreshRate(float rate) { event_progress_.SetRefreshRate_Hz(rate); } - void SetEnableTreeFile(bool is_tree_file) { inputDataFiles_.SetEnableTreeFile(is_tree_file); } void SetInitRunID(int run_id) { inputDataFiles_.SetRunID(run_id); diff --git a/r3bbase/R3BShared.h b/r3bbase/R3BShared.h index 61077522b..bb4ab0e77 100644 --- a/r3bbase/R3BShared.h +++ b/r3bbase/R3BShared.h @@ -193,6 +193,10 @@ namespace R3B inline auto GetFilesFromRegex(std::string_view filename_regex) -> std::vector { + if (filename_regex.empty()) + { + return {}; + } auto regex_path = fs::path{ filename_regex }; auto parent_folder = GetParentDir(filename_regex); const auto regex_string = regex_path.filename().string(); diff --git a/r3bbase/README.md b/r3bbase/README.md index accbb07fe..acfe6546f 100644 --- a/r3bbase/README.md +++ b/r3bbase/README.md @@ -103,9 +103,8 @@ To add the source files which only contain root trees: auto file_source = std::make_unique(); file_source->SetInitRunID(999); // set the run iD -file_source->SetEnableTreeFile(true); -file_source->AddFile("filename.root"); +file_source->AddFile("filename.root", true); ``` Please make sure that the run ID set to file_source is consistent with the run ID from the parameter file.