Skip to content
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

feat: bindings for vector action functions #330

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 15 additions & 11 deletions doc/gen/mainpage.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,16 @@ In summary, the general way to use an Iguana algorithm is as follows; see exampl
- Tip: you may use `iguana::AlgorithmSequence` to help run a _sequence_ of algorithms
2. Check each algorithm configuration, and [adjust it if you prefer](#secConfiguring)
3. Start each algorithm, which "locks in" its configuration:
- call `Start(banklist)` if you use [**the HIPO API**](https://github.com/gavalian/hipo) and [Common Functions](#secCommon)
- call `Start()` otherwise, _i.e._, if you use [Action Functions](#secAction)
- call iguana::Algorithm::Start(hipo::banklist&) if you use [**the HIPO API**](https://github.com/gavalian/hipo) and [Common Functions](#secCommon)
- call iguana::Algorithm::Start() otherwise, _i.e._, if you use [Action Functions](#secAction)
4. In the event loop, run the algorithm:
- call `Run(...)` if you use Common Functions
- call iguana::Algorithm::Run(hipo::banklist&) const if you use Common Functions
- call the Action Function(s) otherwise
5. Proceed with your analysis
- if you called `Run(...)`, the banks will be filtered, transformed, and/or created
- if you called iguana::Algorithm::Run(hipo::banklist&) const, the banks will be filtered, transformed, and/or created
- if you called action functions, you will need to handle their output yourself
- in either case, see [guidance on how to run algorithms](#secRunning) for more details
6. After your event loop, stop each algorithm by calling `Stop()`
6. After your event loop, stop each algorithm by calling iguana::Algorithm::Stop()

Please let the maintainers know if your use case is not covered in any examples or if you need any help.

Expand Down Expand Up @@ -84,13 +84,13 @@ All algorithms have the following **Common Functions**, which may be used in ana

| Common Functions ||
| --- | --- |
| `iguana::Algorithm::Start` | To be called before event processing |
| `iguana::Algorithm::Run` | To be called for every event |
| `iguana::Algorithm::Stop` | To be called after event processing |
| iguana::Algorithm::Start(hipo::banklist&) | To be called before event processing |
| iguana::Algorithm::Run(hipo::banklist&) const | To be called for every event |
| iguana::Algorithm::Stop() | To be called after event processing |

The algorithms are implemented in C++ classes which inherit from the base class `iguana::Algorithm`; these three class methods are overridden in each algorithm.

The `iguana::Algorithm::Run` function should be called on every event; the general consequence, that is, how the user should handle the algorithm's results, depends on the
The iguana::Algorithm::Run(hipo::banklist&) const function should be called on every event; the general consequence, that is, how the user should handle the algorithm's results, depends on the
algorithm type:

<table>
Expand Down Expand Up @@ -119,12 +119,12 @@ typically change the particle momentum components.
<tr> <td>**Creator**</td> <td>
Creator-type algorithms will simply create a new `hipo::bank` object, appending
it to the end of the input `hipo::banklist`. An initial version is created upon calling
`iguana::Algorithm::Start`, so that you may begin to reference it; it is helpful to
iguana::Algorithm::Start(hipo::banklist&), so that you may begin to reference it; it is helpful to
use `hipo::getBanklistIndex` (see [the examples for details](#secExample)).
</td> </tr>
</table>

Internally, `iguana::Algorithm::Run` calls Action Functions, which are described in the next section.
Internally, iguana::Algorithm::Run(hipo::banklist&) const calls Action Functions, which are described in the next section.

<br>
@anchor secAction
Expand All @@ -137,6 +137,10 @@ documentation for details, or browse the full list:

- [List of all Action Functions](#action)

@note To start an algorithm in order to use action functions, you may `Start` it without a bank list, that is, call
iguana::Algorithm::Start() instead of iguana::Algorithm::Start(hipo::banklist&). Stopping the algorithm is the same
regardless of whether you use action functions or not: call iguana::Algorithm::Stop().

Action function parameters are supposed to be _simple_: numbers or lists of numbers, preferably obtainable _directly_
from HIPO bank rows. The return type of an action function depends on the algorithm type:

Expand Down
81 changes: 67 additions & 14 deletions examples/iguana_ex_fortran_01_action_functions.f
Original file line number Diff line number Diff line change
Expand Up @@ -33,34 +33,48 @@ program iguana_ex_fortran_01_action_functions
c HIPO and bank variables
integer counter ! event counter
integer(c_int) reader_status ! hipo event loop vars
integer(c_int) nrows, nrows_c ! number of rows
integer(c_int) nr ! unused
integer N_MAX ! max number of rows we can read
parameter (N_MAX=50)

c REC::Particle columns
integer(c_int) nrows_p ! number of rows
integer(c_int) pindex(N_MAX)
integer(c_int) pid(N_MAX)
real(c_float) px(N_MAX), py(N_MAX), pz(N_MAX)
real(c_float) vz(N_MAX)
integer(c_int) stat(N_MAX)
integer(c_int) sector(N_MAX)

c RUN::config columns
integer(c_int) nrows_c ! number of rows
real(c_float) torus(N_MAX)
integer(c_int) runnum(N_MAX)

c REC::Track, REC::Calorimeter, REC::Scintillator columns
integer(c_int) nrows_trk, nrows_cal, nrows_sci
integer(c_int) sector_trk(N_MAX) ! sectors from REC::Track
integer(c_int) pindex_trk(N_MAX) ! pindices from REC::Track
integer(c_int) sector_cal(N_MAX) ! from REC::Calorimeter
integer(c_int) pindex_cal(N_MAX)
integer(c_int) sector_sci(N_MAX) ! from REC::Scintillator
integer(c_int) pindex_sci(N_MAX)

c iguana algorithm outputs
logical(c_bool) accept(N_MAX) ! filter
real(c_double) qx, qy, qz, qE ! q vector
real(c_double) Q2, x, y, W, nu ! inclusive kinematics
real(c_double) beamPz, targetM ! beam and target
integer(c_int) key_vz_filter ! key for Z-vertex filter
integer(c_int) key_inc_kin ! key for inclusive kinematics
integer(c_int) sector(N_MAX) ! sectors
integer(c_int) nrows_sec ! size of `sector`

c iguana algorithm indices
integer(c_int) algo_eb_filter, algo_vz_filter,
& algo_inc_kin, algo_mom_cor
& algo_inc_kin, algo_sec_finder, algo_mom_cor

c misc.
integer i
integer i, j
real p, p_ele
integer i_ele
logical found_ele
Expand Down Expand Up @@ -138,6 +152,9 @@ program iguana_ex_fortran_01_action_functions
& algo_inc_kin,
& 'physics::InclusiveKinematics'//c_null_char)
call iguana_algo_create(
& algo_sec_finder,
& 'clas12::SectorFinder'//c_null_char)
call iguana_algo_create(
& algo_mom_cor,
& 'clas12::MomentumCorrection'//c_null_char)

Expand All @@ -153,6 +170,8 @@ program iguana_ex_fortran_01_action_functions
call iguana_algo_set_log_level(
& algo_inc_kin, 'debug'//c_null_char)
call iguana_algo_set_log_level(
& algo_sec_finder, 'debug'//c_null_char)
call iguana_algo_set_log_level(
& algo_mom_cor, 'debug'//c_null_char)

c configure algorithms with a configuration file
Expand All @@ -175,8 +194,13 @@ program iguana_ex_fortran_01_action_functions

c read banks
call hipo_file_next(reader_status)
call hipo_read_bank('REC::Particle', nrows)
c get number of rows
call hipo_read_bank('REC::Particle', nrows_p)
call hipo_read_bank('RUN::config', nrows_c)
call hipo_read_bank('REC::Track', nrows_trk)
call hipo_read_bank('REC::Calorimeter', nrows_cal)
call hipo_read_bank('REC::Scintillator', nrows_sci)
c get bank elements
call hipo_read_int('REC::Particle', 'pid', nr, pid, N_MAX)
call hipo_read_float('REC::Particle', 'px', nr, px, N_MAX)
call hipo_read_float('REC::Particle', 'py', nr, py, N_MAX)
Expand All @@ -185,6 +209,22 @@ program iguana_ex_fortran_01_action_functions
call hipo_read_int('REC::Particle', 'status', nr, stat, N_MAX)
call hipo_read_float('RUN::config', 'torus', nr, torus, N_MAX)
call hipo_read_int('RUN::config', 'run', nr, runnum, N_MAX)
call hipo_read_int('REC::Track', 'sector', nr,
& sector_trk, N_MAX)
call hipo_read_int('REC::Track', 'pindex', nr,
& pindex_trk, N_MAX)
call hipo_read_int('REC::Calorimeter', 'sector', nr,
& sector_cal, N_MAX)
call hipo_read_int('REC::Calorimeter', 'pindex', nr,
& pindex_cal, N_MAX)
call hipo_read_int('REC::Scintillator', 'sector', nr,
& sector_sci, N_MAX)
call hipo_read_int('REC::Scintillator', 'pindex', nr,
& pindex_sci, N_MAX)
c simple list of pindices in REC::Particle
do i=1, nrows_p
pindex(i) = i
enddo

c before using the Z-vertext filter, we must "prepare" the
c algorithm's configuration for this event; the resulting
Expand All @@ -203,7 +243,7 @@ program iguana_ex_fortran_01_action_functions
c `REC::Particle::pid == 11 or -211` (simple example algorithm)
c - the AND with the z-vertex filter is the final filter, `accept`
print *, '===> filter particles with iguana:'
do i=1, nrows
do i=1, nrows_p
accept(i) = .true.
call iguana_clas12_eventbuilderfilter_filter(
& algo_eb_filter, pid(i), accept(i))
Expand All @@ -215,20 +255,33 @@ program iguana_ex_fortran_01_action_functions
enddo

c get sector number
c FIXME: we have the algorithm `iguana::clas12::SectorFinder`,
c but it is not yet compatible with Fortran bindings; until
c then, assume the sector number is 1
do i=1, nrows
sector(i) = 1 ! FIXME
enddo
print *, '>>> debug'
write(*,*) ' sector_trk', (sector_trk(j),j=1,nrows_trk)
write(*,*) ' pindex_trk', (pindex_trk(j),j=1,nrows_trk)
write(*,*) ' sector_cal', (sector_cal(j),j=1,nrows_cal)
write(*,*) ' pindex_cal', (pindex_cal(j),j=1,nrows_cal)
write(*,*) ' sector_sci', (sector_sci(j),j=1,nrows_sci)
write(*,*) ' pindex_sci', (pindex_sci(j),j=1,nrows_sci)
print *, '<<<'
call iguana_clas12_sectorfinder_getstandardsectors(
& algo_sec_finder,
& sector_trk, nrows_trk, pindex_trk, nrows_trk,
& sector_cal, nrows_cal, pindex_cal, nrows_cal,
& sector_sci, nrows_sci, pindex_sci, nrows_sci,
& pindex, nrows_p,
& sector, nrows_sec)
print *, '>>> debug'
write(*,*) ' nrows_sec: ', nrows_sec
write(*,*) ' sector', (sector(j),j=1,nrows_sec)
print *, '<<<'

c momentum corrections
if(nrows_c.lt.1) then
print *, '===> no RUN::config bank; cannot ',
& 'apply momentum corrections'
else
print *, '===> momentum corrections:'
do i=1, nrows
do i=1, nrows_p
if(accept(i)) then
print *, ' i = ', i
print *, ' before: p = (', px(i), py(i), pz(i), ')'
Expand All @@ -246,7 +299,7 @@ program iguana_ex_fortran_01_action_functions
p_ele = 0
found_ele = .false.
print *, '===> finding electron...'
do i=1, nrows
do i=1, nrows_p
if(accept(i)) then
print *, ' i = ', i, ' status = ', stat(i)
if(pid(i).eq.11 .and. stat(i).lt.0) then
Expand Down
15 changes: 14 additions & 1 deletion src/chameleon/chameleon
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require_relative 'src/bind_c.rb'
@args.out_dir = ''
@args.out_prefix = ''
@args.verbose = false
@args.debug = false
@args.quiet = false

# parse arguments
Expand All @@ -26,13 +27,15 @@ OptionParser.new do |o|
o.on('-p', '--prefix [PREFIX]', 'if specified, each generated filename will start with [PREFIX]') {|a| @args.out_prefix = a}
o.separator ''
o.on('-v', '--verbose', 'print more output') {|a| @args.verbose = true}
o.on('-d', '--debug', 'enable debugging printouts in the bindings') {|a| @args.debug = true}
o.on('-q', '--quiet', 'print no output (unless --verbose)') {|a| @args.quiet = true}
o.on_tail('-h', '--help', 'show this message') do
puts o
exit
end
end.parse! ARGV
VERBOSE = @args.verbose
VERBOSE = @args.verbose
DEBUG = @args.debug
ACTION_YAML = @args.action_yaml

# start main generator
Expand Down Expand Up @@ -61,6 +64,16 @@ out_files = {
:c_bindings => Bind_c.new(File.join(out_dir, out_name('bind.cc')), algo_name),
}

# require all action function names to be unique for this algorithm
# FIXME: this would not need to be enforced if we generate proper function overloads
# in C, e.g., by using `_Generic`; on the other hand, banning action function
# overloads may give more user stability...
action_function_names = @main.get_spec(main_spec, 'actions').map{ |a| a['name'] }
unless action_function_names.uniq == action_function_names
duplicates = action_function_names.select{ |f| action_function_names.count(f) > 1 }
raise "algorithm '#{algo_name}' has overloaded action functions [#{duplicates.join ', '}]; all action function names must be unique"
end

# parse action functions
@main.get_spec(main_spec, 'actions').each do |action_spec|
out_files[:c_bindings].bind action_spec
Expand Down
Loading
Loading