diff --git a/README.md b/README.md index d4b5263..aae3e82 100644 --- a/README.md +++ b/README.md @@ -35,5 +35,37 @@ ANALYZER UTILITIES 1. __mkvariables.py__ reads a Root file and creates the file __variables.txt__ containing a description of (by default) the first tree it finds. -2. __mkanalyzer.py__ reads __variables.txt__ and creates the skeleton of an C++ +2. __mkanalyzer.py__ reads __variables.txt__ and creates the skeleton of an C++ and Python analyzer program for the Root tree. + +## 코드 구조 쉽게 이해하기 (Korean Guide) + +### 핵심 파일별 역할 +- **`bin/mkanalyzer.py`**: `variables.txt`를 읽어 C++/Python 분석기, `eventBuffer` 헤더, 링크 정의, Makefile, README까지 한 번에 생성합니다. 템플릿 문자열 안에 실제 코드 조각을 모아두고, 사용자가 지정한 출력 디렉터리에 필요한 파일을 모두 써 줍니다. +- **`bin/mklist.py`**: 입력 루트 파일에서 사용 가능한 트리와 브랜치를 훑어 보고, 어떤 변수를 `variables.txt`에 담을지 미리 확인할 수 있는 간단한 나열 도구입니다. +- **`bin/mkvariables.py`**: 지정한 ntuple을 열어 브랜치 정보를 추출한 뒤, `mkanalyzer.py`가 읽을 `variables.txt`를 자동으로 만들어 줍니다. +- **`include/pdg.h` · `src/pdg.cc`**: PDG ID를 사람이 읽을 이름으로 바꿔 주거나, Monte Carlo 입자 계보를 출력하는 유틸리티 함수 모음입니다. 분석기에서 입자 정보를 해석할 때 바로 쓸 수 있게 독립 모듈로 제공됩니다. +- **`include/treestream.h` · `src/treestream.cc`**: `itreestream`/`otreestream` 클래스를 정의하여 ROOT 트리를 C++ 객체처럼 순회하거나 새 트리를 저장할 수 있는 핵심 I/O 계층입니다. `eventBuffer`가 실제 데이터를 불러오거나 쓰는 기반이 됩니다. +- **`tnm/tnm.h` · `tnm/tnm.cc`**: 분석기 실행에 필요한 공용 유틸리티(명령줄 파싱, 출력 파일 관리, 자주 쓰는 수학 함수 등)를 모았습니다. `mkanalyzer.py`가 만들어 주는 분석기 본문에서 바로 include 하도록 설계되어 있습니다. + +### `mkanalyzer.py`가 뼈대 코드를 엮는 방법 +1. `variables.txt`를 파싱해 각 브랜치의 타입·길이·카운터 정보를 수집합니다. +2. 위 정보를 `eventBuffer` 템플릿(`TEMPLATE_H`, `TEMPLATE_CC`)에 채워 넣어, `treestream.h`의 스트림 클래스와 연동되는 버퍼 클래스를 생성합니다. +3. 생성되는 분석기 C++ 파일은 `tnm/tnm.h`를 include 하여 `commandLine`, `outputFile`, `fileNames` 등 공용 함수를 재사용하고, 앞서 생성된 `eventBuffer.h`를 통해 트리 데이터를 읽습니다. +4. Python 템플릿 역시 ROOT 파이썬 바인딩에서 `tnm` 함수와 `eventBuffer` 클래스를 불러와 동일한 흐름을 따르도록 구성되어 있습니다. +5. Makefile 템플릿은 `treestream.cc`, `pdg.cc` 등의 라이브러리를 링크하고, 필요하면 ROOT dictionary를 만들도록 규칙을 포함합니다. 설치 후에는 `include/`와 `src/`의 코드가 그대로 재사용됩니다. + +### 기존 코드와 이전 제안의 차이 +- 원본 `mkanalyzer.py`는 브랜치 선택 토글을 `std::map`으로 구현하고, 이벤트 루프는 최소한의 로그만 제공합니다. +- 이전 제안에서는 이 부분을 `std::unordered_map`과 추가 디버그 인자로 확장하려 했으나 구조 자체는 크게 바뀌지 않았습니다. +- 현재 저장소에는 원본 흐름을 복원하고, 향후에 직접 개선할 수 있도록 **한국어 주석**으로 개선 포인트(예: `std::unordered_map`으로 교체, 디버그 로그 추가, dictionary 규칙 끄기)를 표시해 두었습니다. + +### PhysicsTools/TheNtupleMaker 의존성 정리 +- `src/treestream.cc`, `src/pdg.cc`, `tnm/tnm.h` 등은 `#include "PhysicsTools/TheNtupleMaker/interface/..."`를 먼저 시도한 뒤, 같은 파일을 로컬 경로에서 다시 include 합니다. 이는 CMSSW 안에서 사용할 때 기존 모듈과 충돌하지 않도록 하기 위한 **호환성 장치**입니다. +- 이 저장소만으로도 빌드가 가능하도록 로컬 헤더가 바로 이어서 include 되므로, CMSSW 환경이 아니라면 추가 의존성은 없습니다. +- 만약 해당 경로를 완전히 없애고 싶다면, 위 파일들의 `#ifdef PROJECT_NAME` 블록을 정리하고, Makefile/컴파일 옵션에서 `-Iinclude` 만 남겨도 됩니다. README와 `bin/mkanalyzer.py`의 주석에 dictionary 규칙을 해제하는 방법도 함께 안내되어 있습니다. + +### 향후 수정 포인트 안내 +- `bin/mkanalyzer.py`의 템플릿 안에 `// NOTE(KR): ...` 또는 `# NOTE(KR): ...` 형태의 주석을 추가했습니다. `std::map` 대신 `std::unordered_map`으로 바꾸거나, 디버그 로그/진행률 출력, dictionary 생성 비활성화 등을 적용하고 싶을 때 해당 위치를 찾아 수정하면 됩니다. +- Python 템플릿에도 같은 위치에 주석이 있으니, C++과 Python 분석기를 동시에 유지하려면 두 곳을 함께 손보면 됩니다. +- 필요한 변경을 직접 시도하면서 README를 참고하면, NanoAOD뿐 아니라 miniAOD 등 다른 ntuple 구조에도 맞게 뼈대를 확장하기 수월해집니다. diff --git a/bin/mkanalyzer.py b/bin/mkanalyzer.py index 6333964..9dfe2b8 100755 --- a/bin/mkanalyzer.py +++ b/bin/mkanalyzer.py @@ -220,6 +220,8 @@ def getauthor(): //-------------------------------------------------------------------------- // A read-only buffer eventBuffer() : input(0), output(0), choose(std::map()) {} + // NOTE(KR): 여기서 choose 자료구조를 std::unordered_map 등으로 + // 바꿔 메모리/탐색 효율을 개선할 수 있습니다. eventBuffer(itreestream& stream, std::string varlist="") : input(&stream), output(0), @@ -254,7 +256,10 @@ def getauthor(): sin >> key; if ( sin ) { - std::map::iterator it; + // NOTE(KR): 접두사 비교 로직을 더 직관적으로 바꾸고 싶다면 + // 여기서 range-based for 문과 std::string_view 등을 + // 도입해도 됩니다. + std::map::iterator it; for(it = choose.begin(); it != choose.end(); it++) { if ( it->first.length() > key.length() ) @@ -297,8 +302,9 @@ def getauthor(): input->read(entry); // clear indexmap + // NOTE(KR): range-based for 문과 구조적 바인딩을 쓰면 더 간결하게 비울 수 있습니다. for(std::map >::iterator - item=indexmap.begin(); + item=indexmap.begin(); item != indexmap.end(); ++item) item->second.clear(); @@ -379,6 +385,8 @@ def getauthor(): // Get command line arguments commandLine cl(argc, argv); + // NOTE(KR): cl 구조체에 debug 플래그를 추가하고 싶다면 + // tnm/tnm.h, tnm/tnm.cc를 함께 수정해야 합니다. // Get names of ntuple files to be processed vector filenames = fileNames(cl.filelist); @@ -398,6 +406,8 @@ def getauthor(): int nevents = ev.size(); cout << "number of events: " << nevents << endl; + // NOTE(KR): 디버그 모드에서 처리 상황을 보고하려면 여기에서 + // 주기적으로 로그를 출력하도록 루프를 확장하세요. // Create output file for histograms; see notes in header outputFile of(cl.outputfilename); @@ -415,7 +425,8 @@ def getauthor(): { // read an event into event buffer ev.read(entry); - + // NOTE(KR): entry 인덱스를 이용해 진행률/디버그 로그를 남기는 + // 코드를 추가하기 좋은 위치입니다. } ev.close(); @@ -445,6 +456,8 @@ def getauthor(): def main(): cl = ROOT.commandLine() + # NOTE(KR): commandLine 클래스에 debug 속성을 추가했다면 + # 여기에서 cl.debug 값을 읽어와 로그에 활용하세요. # Get names of ntuple files to be processed filenames = ROOT.fileNames(cl.filelist) @@ -479,6 +492,8 @@ def main(): # ------------------------------------------------------------------------ for entry in range(nevents): ev.read(entry) + # NOTE(KR): Python 분석기에서도 진행률 바 혹은 조건부 로그를 + # 출력하려면 이 위치에서 print나 logging을 호출하면 됩니다. ev.close() of.close() @@ -639,6 +654,7 @@ def main(): \t@echo "---> Generating dictionary `basename $@`" \t$(AT)$(CINT) -f $@ -c -I. -Iinclude -I$(ROOTSYS)/include $+ \t$(AT)mv $(srcdir)/*.pcm $(libdir) +\t# NOTE(KR): dictionary가 필요 없다면 위 규칙과 sharedlib 의존성을 주석 처리하세요. # Define clean up rules clean :