11"""Tracking algorithm."""
2- from dataclasses import dataclass , field
2+ # from dataclasses import dataclass, field
33from typing import List , Tuple
44
55import numpy as np
6+ from numba import float64 , njit
67
78from .calibration import Calibration
89from .constants import (
3435}
3536
3637
37- @dataclass
38- class Foundpix :
39- """A Foundpix object holds the parameters for a found pixel."""
38+ # @dataclass
39+ # class Foundpix:
40+ # """A Foundpix object holds the parameters for a found pixel."""
4041
41- ftnr : int = TR_UNUSED
42- freq : int = 0
43- whichcam : List [int ] = field (default_factory = list )
42+ # ftnr: int = TR_UNUSED
43+ # freq: int = 0
44+ # whichcam: List[int] = field(default_factory=list)
4445
45- def __post_init__ (self ):
46- self .whichcam = [0 ] * TR_MAX_CAMS
46+ # def __post_init__(self):
47+ # self.whichcam = [0] * TR_MAX_CAMS
4748
4849
49- def reset_foundpix_array (arr : List [Foundpix ], arr_len : int , num_cams : int ) -> None :
50+ Foundpix_dtype = np .dtype ([
51+ ('ftnr' , np .int32 ),
52+ ('freq' , np .int32 ),
53+ ('whichcam' , np .int32 , (TR_MAX_CAMS ,))
54+ ])
55+
56+ # Create an instance of the recarray
57+ # foundpix = np.recarray((1,), dtype=Foundpix_dtype)
58+
59+ # Initialize the recarray with the values from the class
60+ # foundpix['ftnr'] = TR_UNUSED
61+ # foundpix['freq'] = 0
62+ # foundpix['whichcam'] = [0] * TR_MAX_CAMS
63+
64+
65+ # def reset_foundpix_array(arr: List[Foundpix], arr_len: int, num_cams: int) -> None:
66+ # @njit(cache=True, fastmath=True, nogil=True, parallel=True)
67+ def reset_foundpix_array (arr : np .ndarray , arr_len : int , num_cams : int ) -> None :
5068 """Set default values for foundpix objects in an array.
5169
5270 Arguments:
5371 ---------
54- arr -- the array to reset
72+ arr -- the array to reset, dtype = Foundpix_dtype
5573 arr_len -- array length
5674 num_cams -- number of places in the whichcam member of foundpix.
5775 """
5876 for i in range (arr_len ):
59- # Set default values for each foundpix object in the array
60- arr [i ].ftnr = TR_UNUSED
61- arr [i ].freq = 0
62-
63- # Set default values for each whichcam member of the foundpix object
64- for cam in range (num_cams ):
65- if len (arr [i ].whichcam ) < num_cams :
66- arr [i ].whichcam .append (0 )
67- else :
68- arr [i ].whichcam [cam ] = 0
77+ arr [i ]["ftnr" ] = TR_UNUSED
78+ arr [i ]["freq" ] = 0
79+ for j in range (num_cams ):
80+ # Set default values for unused foundpix objects
81+ arr [i ]["whichcam" ][j ] = 0
6982
7083 return None
7184
72-
73- def copy_foundpix_array (
74- dest : List [Foundpix ], src : List [Foundpix ], arr_len : int , num_cams : int
75- ) -> None :
76- """copy_foundpix_array() copies foundpix objects from one array to another.
77-
78- Arguments:
79- ---------
80- dest -- dest receives the copied array
81- src -- src is the array to copy
82- arr_len -- array length
83- num_cams -- number of places in the whichcam member of foundpix.
84- """
85+ def copy_foundpix_array (dest : np .ndarray , src : np .ndarray , arr_len : int , num_cams : int ) -> None :
86+ """Copy the relevant part of foundpix array."""
8587 for i in range (arr_len ):
8688 # Copy values from source foundpix object to destination foundpix object
8789 dest [i ].ftnr = src [i ].ftnr
@@ -91,6 +93,7 @@ def copy_foundpix_array(
9193 for cam in range (num_cams ):
9294 dest [i ].whichcam [cam ] = src [i ].whichcam [cam ]
9395
96+ return None
9497
9598def register_closest_neighbs (
9699 targets : List [Target ],
@@ -102,7 +105,7 @@ def register_closest_neighbs(
102105 dr : float ,
103106 du : float ,
104107 dd : float ,
105- reg : List [ Foundpix ] ,
108+ reg : np . ndarray ,
106109 cpar : ControlPar ,
107110) -> List [int ]:
108111 """Register_closest_neighbs() finds candidates for continuing a particle's.
@@ -141,7 +144,7 @@ def register_closest_neighbs(
141144
142145 return all_cands
143146
144-
147+ @ njit ( float64 [:]( float64 [:], float64 [:]), cache = True , fastmath = True , nogil = True , parallel = True )
145148def search_volume_center_moving (
146149 prev_pos : np .ndarray , curr_pos : np .ndarray
147150) -> np .ndarray :
@@ -509,7 +512,7 @@ def searchquader(
509512 return xr , xl , yd , yu
510513
511514
512- def sort_candidates_by_freq (foundpix : List [ Foundpix ] , num_cams : int ) -> int :
515+ def sort_candidates_by_freq (foundpix : np . ndarray , num_cams : int ) -> int :
513516 """Sort candidates by frequency."""
514517 different = 0
515518
@@ -601,10 +604,13 @@ def point_to_pixel(point: np.ndarray, cal: Calibration, cpar: ControlPar) -> np.
601604
602605def sorted_candidates_in_volume (
603606 center : np .ndarray , center_proj : np .ndarray , frm : Frame , run : TrackingRun
604- ) -> List [ Foundpix ] :
607+ ) -> np . ndarray :
605608 """Find candidates for continuing a particle's path in the search volume."""
606- points = [Foundpix () for _ in range (frm .num_cams * MAX_CANDS )]
607- # reset_foundpix_array(points, frm.num_cams * MAX_CANDS, frm.num_cams)
609+ # points = [Foundpix() for _ in range(frm.num_cams * MAX_CANDS)]
610+ points = np .array (
611+ [(TR_UNUSED , 0 , [0 ]* TR_MAX_CAMS )]* (frm .num_cams * MAX_CANDS ),
612+ dtype = Foundpix_dtype ).view (np .recarray )
613+ reset_foundpix_array (points , frm .num_cams * MAX_CANDS , frm .num_cams )
608614
609615 # Search limits in image space
610616 right , left , down , up = searchquader (center , run .tpar , run .cpar , run .cal )
@@ -628,9 +634,11 @@ def sorted_candidates_in_volume(
628634 # fill and sort candidate struct
629635 num_cands = sort_candidates_by_freq (points , frm .num_cams )
630636 if num_cands > 0 :
631- points = points [:num_cands ] + [Foundpix (ftnr = TR_UNUSED )]
637+ points = points [:num_cands + 1 ]
638+ # points[-1] = np.ndarray((1,), dtype = Foundpix_dtype)
639+ # points[-1].ftnr = TR_UNUSED
632640 else :
633- points = [ Foundpix ( ftnr = TR_UNUSED )]
641+ points = np . array ([( TR_UNUSED , 0 , [ 0 ] * TR_MAX_CAMS )], dtype = Foundpix_dtype ). view ( np . recarray )
634642
635643 return points
636644
@@ -856,7 +864,8 @@ def trackcorr_c_loop(run_info, step):
856864
857865 # calculate search cuboid and reproject it to the image space
858866 w = sorted_candidates_in_volume (X [2 ], v1 , fb .buf [2 ], run_info )
859- if not w : # empty
867+ # if not w # empty
868+ if w .shape [0 ] == 1 : # empty means at least one row
860869 continue
861870
862871 # Continue to find candidates for the candidates.
@@ -886,7 +895,7 @@ def trackcorr_c_loop(run_info, step):
886895
887896 # end of search in pix
888897 wn = sorted_candidates_in_volume (X [5 ], v1 , fb .buf [3 ], run_info )
889- if len ( wn ) > 0 : # not empty
898+ if wn . shape [ 0 ] > 1 : # not empty means two rows at least.
890899 count3 += 1
891900 kk = 0
892901 while wn [kk ].ftnr != TR_UNUSED and len (fb .buf [3 ].path_info ) > wn [kk ].ftnr :
0 commit comments