-
Notifications
You must be signed in to change notification settings - Fork 4
basic template for hpge post processing #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from 30 commits
Commits
Show all changes
91 commits
Select commit
Hold shift + click to select a range
578de78
basic template for hpge post processing
tdixon97 a6d3d12
style: pre-commit fixes
pre-commit-ci[bot] 05b42e6
pc fixes
tdixon97 3dfbf23
style improvements
tdixon97 0bd5d6f
fix merge
tdixon97 8b1fd87
basic functionality for time-windowing
tdixon97 223a7d0
detectors file to config
tdixon97 5ded4c9
[fix] sort by time
tdixon97 4261348
[wip] adding functions for DL calculations
tdixon97 2f888fb
[wip] adding functions for DL calc and __init__ for hpge subpackage
tdixon97 ddea2d5
style: pre-commit fixes
pre-commit-ci[bot] ca94f10
Update __init__.py
tdixon97 adb1f6e
style: pre-commit fixes
pre-commit-ci[bot] 534882c
Update src/reboost/hpge/processors.py
tdixon97 3d5a535
Update src/reboost/hpge/hit.py
tdixon97 39c587c
style: pre-commit fixes
pre-commit-ci[bot] 78e130a
[wip] starting functionality for DLs
tdixon97 592bdfc
Merge branch 'main' of github.com:tdixon97/reboost into main
tdixon97 a2e2599
style: pre-commit fixes
pre-commit-ci[bot] 16550ae
fix some parts of the docs
tdixon97 4c4f603
style: pre-commit fixes
pre-commit-ci[bot] f8778cc
generate proccesing chain from config file
tdixon97 0e7aaf5
bit of clean up / improved docs
tdixon97 5a9595b
[tests] add test for the windowing
tdixon97 63ca42b
style: pre-commit fixes
pre-commit-ci[bot] d65ffad
[tests] adding more tests
tdixon97 bfe9782
style: pre-commit fixes
pre-commit-ci[bot] 670f5df
[tests] test merging arrays
tdixon97 4747230
Merge branch 'main' of github.com:tdixon97/reboost into main
tdixon97 cdc8767
style: pre-commit fixes
pre-commit-ci[bot] 8e8de77
update to be able to read json or yaml
tdixon97 6cf37d6
fix merge
tdixon97 3dcc0f6
processor for distance to surface
tdixon97 0d22b95
[docs] improved documentation
tdixon97 83be05d
add hpges and pyg4ometry to the dependencies
tdixon97 a2e8d4a
add pyg4ometry
tdixon97 58e6f36
[docs] add legendtestdata to deps
tdixon97 8ec0df6
[tests] test on the whole of build_hit (IO)
tdixon97 ee048fa
precommit
tdixon97 410bb22
remove dependency
tdixon97 a4140bf
[tests] fix the test data
tdixon97 b615949
add the option to just read n evtid starting at a particular index.
tdixon97 42390b8
trying to fix tests
tdixon97 40329f5
style: pre-commit fixes
pre-commit-ci[bot] 432bd70
add awkward to dependencies
tdixon97 8616562
Merge branch 'main' of github.com:tdixon97/reboost into main
tdixon97 dea22dd
update main.yaml
tdixon97 6237681
improving documentation
tdixon97 1370087
change FileInfo into class (cleaner)
tdixon97 54663e0
[docs] improve documentation and start working on locals option
tdixon97 097b9e6
add option to specify local objects in config
tdixon97 133da5e
ak.min to np.min for 1D array
tdixon97 9f0a9ba
style: pre-commit fixes
pre-commit-ci[bot] f075594
style fixes
tdixon97 9f70f59
Merge branch 'main' of github.com:tdixon97/reboost into main
tdixon97 cd16454
ak -> np to fix CI failures
tdixon97 a28d1a4
style: pre-commit fixes
pre-commit-ci[bot] b9bc3a4
[docs] adding a basic tutorial
tdixon97 28115f1
Merge branch 'main' of github.com:tdixon97/reboost into main
tdixon97 50017cc
style: pre-commit fixes
pre-commit-ci[bot] e301bd7
[docs] fix spelling
tdixon97 7293579
Merge branch 'main' of github.com:tdixon97/reboost into main
tdixon97 03e6088
[docs] fix
tdixon97 90112a2
[docs] remove nbspinx
tdixon97 e4feb8f
[docs] update conf.p
tdixon97 66c63fc
Update pyproject.toml
tdixon97 22c4b78
[docs] fix tutorial
tdixon97 c2bc963
[docs] fix
tdixon97 387ac50
[docs] more format fixes
tdixon97 e78e90e
clean up build hit
tdixon97 9530b65
first version of building tcm
tdixon97 78116a4
remove timing debug (cleanup)
tdixon97 0abd90f
[evt] first version of build_tcm code
tdixon97 d9509bc
[docs] small fix
tdixon97 abd9450
pre-commit
tdixon97 01cc000
[docs] fix build-hit docsring
tdixon97 f0d13cb
change evtid to _evtid and global_evtid to _global_evtid since its no…
tdixon97 f594231
additions to documentation
tdixon97 9509c2a
[docs] switch tutorials from rst to ipynb (easier to mantain)
tdixon97 df7e6d9
change to notebook for docs
tdixon97 ae1cea5
[docs] switch back to rst (dont want to run the notebooks)
tdixon97 ecd90e7
[evt] adding build_tcm functionality
tdixon97 d6b6d27
[docs] documentation for event tier
tdixon97 235aefb
[docs] documentation for event tier
tdixon97 c61ef07
[docs] remove nbsphinx
tdixon97 2d8c634
[docs] fix
tdixon97 0a97068
style: pre-commit fixes
pre-commit-ci[bot] 5790828
[docs] ipython --> python
tdixon97 6383880
Merge branch 'main' of github.com:tdixon97/reboost into main
tdixon97 b779c4d
[docs] small fixes
tdixon97 e608760
Update .pre-commit-config.yaml
tdixon97 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from reboost import optical | ||
| from reboost import hpge, optical | ||
| from reboost._version import version as __version__ | ||
|
|
||
| __all__ = ["__version__", "optical"] | ||
| __all__ = ["__version__", "optical", "hpge"] |
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| from __future__ import annotations | ||
|
|
||
| import argparse | ||
| import logging | ||
| from pathlib import Path | ||
|
|
||
| import colorlog | ||
| import yaml | ||
|
|
||
|
|
||
| def hpge_cli() -> None: | ||
| parser = argparse.ArgumentParser( | ||
| prog="reboost-hpge", | ||
| description="%(prog)s command line interface", | ||
| ) | ||
|
|
||
| parser.add_argument( | ||
| "--verbose", | ||
| "-v", | ||
| action="store_true", | ||
| help="""Increase the program verbosity""", | ||
| ) | ||
|
|
||
| parser.add_argument( | ||
| "--bufsize", | ||
| action="store", | ||
| type=int, | ||
| default=int(5e6), | ||
| help="""Row count for input table buffering (only used if applicable). default: %(default)e""", | ||
| ) | ||
|
|
||
| # step 1: hit tier | ||
| subparsers = parser.add_subparsers(dest="command", required=True) | ||
| hit_parser = subparsers.add_parser("hit", help="build hit file from remage raw file") | ||
|
|
||
| hit_parser.add_argument( | ||
| "--proc_chain", | ||
| help="YAML file that contains the processing chain", | ||
| required=True, | ||
| ) | ||
| hit_parser.add_argument( | ||
| "--pars", | ||
| help="YAML file that contains the pars", | ||
| required=True, | ||
| ) | ||
| hit_parser.add_argument( | ||
| "--gdml", | ||
| help="GDML file used for Geant4", | ||
| required=False, | ||
| ) | ||
| hit_parser.add_argument( | ||
| "--macro", | ||
| help="Gean4 macro file used to generate raw tier", | ||
| required=False, | ||
| ) | ||
|
|
||
| hit_parser.add_argument("--infield", help="input LH5 field", required=False, default="hit") | ||
| hit_parser.add_argument( | ||
| "--outfield", help="output LH5 field name", required=False, default="hit" | ||
| ) | ||
|
|
||
| hit_parser.add_argument("input", help="input hit LH5 file", metavar="INPUT_HIT") | ||
| hit_parser.add_argument("output", help="output evt LH5 file", metavar="OUTPUT_EVT") | ||
|
|
||
| args = parser.parse_args() | ||
|
|
||
| handler = colorlog.StreamHandler() | ||
| handler.setFormatter( | ||
| colorlog.ColoredFormatter("%(log_color)s%(name)s [%(levelname)s] %(message)s") | ||
| ) | ||
| logger = logging.getLogger("reboost.hpge") | ||
| logger.addHandler(handler) | ||
| if args.verbose: | ||
| logger.setLevel(logging.DEBUG) | ||
| else: | ||
| logger.setLevel(logging.INFO) | ||
|
|
||
| if args.command == "hit": | ||
| # is the import here a good idea? | ||
| logger.info("...running raw->hit tier") | ||
| from reboost.hpge.hit import build_hit | ||
|
|
||
| with Path.open(Path(args.pars)) as config_f: | ||
| pars = yaml.safe_load(config_f) | ||
|
|
||
| with Path.open(Path(args.proc_chain)) as config_f: | ||
| proc_config = yaml.safe_load(config_f) | ||
|
|
||
| # check the processing chain | ||
| for req_field in ["channels", "outputs", "step_group", "operations"]: | ||
| if req_field not in proc_config: | ||
| msg = f"error proc chain config must contain the field {req_field}" | ||
| raise ValueError(msg) | ||
|
|
||
| build_hit( | ||
| args.output, | ||
| args.input, | ||
| out_field=args.outfield, | ||
| in_field=args.infield, | ||
| proc_config=proc_config, | ||
| pars=pars, | ||
| buffer=args.bufsize, | ||
| gdml=args.gdml, | ||
| macro=args.macro, | ||
| ) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,259 @@ | ||
| from __future__ import annotations | ||
|
|
||
| import logging | ||
|
|
||
| import numpy as np | ||
| from lgdo import Array, ArrayOfEqualSizedArrays, LH5Iterator, Table, VectorOfVectors, lh5 | ||
|
|
||
| from . import utils | ||
|
|
||
| log = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| def step_group(data: Table, group_config: dict) -> Table: | ||
| """Performs a grouping of geant4 steps to build the `hit` table. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| data | ||
| `stp` table from remage. | ||
| group_config | ||
| dict with the configuration describing the step grouping. | ||
| For example | ||
|
|
||
| .. code-block:: json | ||
|
|
||
| { | ||
| "description": "group steps by time and evtid.", | ||
| "expression": "reboost.hpge.processors.group_by_time(stp,window=10)" | ||
| } | ||
|
|
||
| this will then evaluate the function chosen by `expression` resulting in a new Table. | ||
|
|
||
| """ | ||
|
|
||
| # group to create hit table | ||
|
|
||
| group_func, globs = utils.get_function_string( | ||
| group_config["expression"], | ||
| ) | ||
| locs = {"stp": data} | ||
|
|
||
| msg = f"running step grouping with {group_func} and globals {globs.keys()} and locals {locs.keys()}" | ||
| log.debug(msg) | ||
| return eval(group_func, globs, locs) | ||
|
|
||
|
|
||
| def eval_expression( | ||
| table: Table, info: dict, pars: dict | ||
| ) -> Array | ArrayOfEqualSizedArrays | VectorOfVectors: | ||
| """Evaluate an expression returning an LGDO object. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| table | ||
| hit table, with columns possibly used in the operations. | ||
| info | ||
| `dict` containing the information on the expression. Must contain `mode` and `expressions` keys | ||
| For example: | ||
|
|
||
| .. code-block:: json | ||
|
|
||
| { | ||
| "mode": "eval", | ||
| "expression":"ak.sum(hit.edep,axis=-1)" | ||
| } | ||
|
|
||
| variables preceded by `hit` will be taken from the supplied table. Mode can be either `eval`, | ||
| in which case a simple expression is based (only involving numpy, awkward or inbuilt python functions), | ||
| or `function` in which case an arbitrary function is passed (for example defined in processors). | ||
|
|
||
| pars | ||
| dict of parameters, can contain any fields passed to the expression prefixed by `pars.`. | ||
|
|
||
|
|
||
| Returns | ||
| ------- | ||
| a new column for the hit table either :class:`Array`, :class:`ArrayOfEqualSizedArrays` or :class:`VectorOfVectors`. | ||
| """ | ||
|
|
||
| pars_tuple = utils.dict2tuple(pars) | ||
| local_dict = {"pars": pars_tuple} | ||
|
|
||
| if info["mode"] == "eval": | ||
| # replace hit. | ||
| expr = info["expression"].replace("hit.", "") | ||
|
|
||
| msg = f"evaluating table with command {expr} and local_dict {local_dict.keys()}" | ||
| log.debug(msg) | ||
|
|
||
| col = table.eval(expr, local_dict) | ||
|
|
||
| elif info["mode"] == "function": | ||
| proc_func, globs = utils.get_function_string(info["expression"]) | ||
|
|
||
| # add hit table to locals | ||
| local_dict = {"hit": table} | local_dict | ||
|
|
||
| msg = f"evaluating table with command {info['expression']} and local_dict {local_dict.keys()} and global dict {globs.keys()}" | ||
| log.debug(msg) | ||
| col = eval(proc_func, globs, local_dict) | ||
|
|
||
| else: | ||
| msg = "mode is not recognised." | ||
| raise ValueError(msg) | ||
| return col | ||
|
|
||
|
|
||
| def build_hit( | ||
| file_out: str, | ||
| file_in: str, | ||
| out_field: str, | ||
| in_field: str, | ||
| proc_config: dict, | ||
| pars: dict, | ||
| buffer: int = 1000000, | ||
| gdml: str | None = None, | ||
| macro: str | None = None, | ||
| ) -> None: | ||
| """ | ||
| Read incrementally the files compute something and then write output | ||
|
|
||
| Parameters | ||
| ---------- | ||
| file_out | ||
| output file path | ||
| file_in | ||
| input_file_path | ||
| out_field | ||
| lh5 group name for output | ||
| in_field | ||
| lh5 group name for input | ||
| proc_config | ||
| the configuration file for the processing. Must contain the fields `channels`, `outputs`, `step_group` and operations`. | ||
| For example: | ||
|
|
||
| .. code-block:: json | ||
|
|
||
| { | ||
| "channels": [ | ||
| "det000", | ||
| "det001", | ||
| "det002", | ||
| "det003" | ||
| ], | ||
| "outputs": [ | ||
| "t0", | ||
| "truth_energy_sum", | ||
| "smeared_energy_sum", | ||
| "evtid" | ||
| ], | ||
| "step_group": { | ||
| "description": "group steps by time and evtid.", | ||
| "expression": "reboost.hpge.processors.group_by_time(stp,window=10)" | ||
| }, | ||
| "operations": { | ||
| "t0": { | ||
| "description": "first time in the hit.", | ||
| "mode": "eval", | ||
| "expression": "ak.fill_none(ak.firsts(hit.time,axis=-1),np.nan)" | ||
| }, | ||
| "truth_energy_sum": { | ||
| "description": "truth summed energy in the hit.", | ||
| "mode": "eval", | ||
| "expression": "ak.sum(hit.edep,axis=-1)" | ||
| }, | ||
| "smeared_energy_sum": { | ||
| "description": "summed energy after convolution with energy response.", | ||
| "mode": "function", | ||
| "expression": "reboost.hpge.processors.smear_energies(hit.truth_energy_sum,reso=pars.reso)" | ||
| } | ||
|
|
||
| } | ||
| } | ||
|
|
||
| pars | ||
| a dictionary of parameters, must have a field per channel consisting of a `dict` of parameters. For example: | ||
|
|
||
| .. code-block:: json | ||
|
|
||
| { | ||
| "det000": { | ||
| "reso": 1, | ||
| "fccd": 0.1 | ||
| } | ||
| } | ||
|
|
||
| buffer | ||
| length of buffer | ||
| gdml | ||
| path to the input gdml file. | ||
| macro | ||
| path to the macro file. | ||
|
|
||
| Note | ||
| ---- | ||
| The operations can depend on the outputs of previous steps, so operations order is important. | ||
| """ | ||
| if gdml is not None: | ||
| pass | ||
|
|
||
| if macro is not None: | ||
| pass | ||
|
|
||
| for ch_idx, d in enumerate(proc_config["channels"]): | ||
| msg = f"...running hit tier for {d}" | ||
| log.info(msg) | ||
| delete_input = bool(ch_idx == 0) | ||
|
|
||
| msg = f"...begin processing with {file_in} to {file_out}" | ||
| log.info(msg) | ||
|
|
||
| entries = LH5Iterator(file_in, f"{in_field}/{d}", buffer_len=buffer)._get_file_cumentries(0) | ||
|
|
||
| # number of blocks is ceil of entries/buffer, | ||
| # shift by 1 since idx starts at 0 | ||
| # this is maybe too high if buffer exactly divides idx | ||
| max_idx = int(np.ceil(entries / buffer)) - 1 | ||
| buffer_rows = None | ||
|
|
||
| for idx, (lh5_obj, _, _) in enumerate( | ||
| LH5Iterator(file_in, f"{in_field}/{d}", buffer_len=buffer) | ||
| ): | ||
| msg = f"... processed {idx} files out of {max_idx}" | ||
| log.debug(msg) | ||
|
|
||
| # convert to awkward | ||
| ak_obj = lh5_obj.view_as("ak") | ||
|
|
||
| # handle the buffers | ||
| obj, buffer_rows, mode = utils._merge_arrays( | ||
| ak_obj, buffer_rows, idx=idx, max_idx=max_idx, delete_input=delete_input | ||
| ) | ||
|
|
||
| # convert back to a table, should work | ||
| data = Table(obj) | ||
|
|
||
| # group steps into hits | ||
| grouped = step_group(data, proc_config["step_group"]) | ||
|
|
||
| # processors | ||
| for name, info in proc_config["operations"].items(): | ||
| msg = f"adding column {name}" | ||
| log.debug(msg) | ||
|
|
||
| col = eval_expression(grouped, info, pars) | ||
| grouped.add_field(name, col) | ||
|
|
||
| # remove unwanted columns | ||
| log.debug("removing unwanted columns") | ||
|
|
||
| existing_cols = list(grouped.keys()) | ||
| for col in existing_cols: | ||
| if col not in proc_config["outputs"]: | ||
| grouped.remove_column(col, delete=True) | ||
|
|
||
| # write lh5 file | ||
| msg = f"...finished processing and save file with wo_mode {mode}" | ||
| log.debug(msg) | ||
| lh5.write(grouped, f"{out_field}/{d}", file_out, wo_mode=mode) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.