@ -28,17 +28,20 @@ logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(mess
logger = logging . getLogger ( " recompute_svd " )
logger = logging . getLogger ( " recompute_svd " )
def quarter_bounds ( window_id : str ) - > Tuple [ str , str ] :
def year_bounds ( window_id : str ) - > Tuple [ str , str ] :
# window_id like '2026-Q1'
""" Return (start_date, end_date) for an annual window_id like ' 2024 ' .
year , q = window_id . split ( " -Q " )
y = int ( year )
Quarterly window IDs ( containing ' -Q ' ) are not supported — this script
qn = int ( q )
only processes annual windows .
starts = { 1 : ( 1 , 1 ) , 2 : ( 4 , 1 ) , 3 : ( 7 , 1 ) , 4 : ( 10 , 1 ) }
"""
ends = { 1 : ( 3 , 31 ) , 2 : ( 6 , 30 ) , 3 : ( 9 , 30 ) , 4 : ( 12 , 31 ) }
if " -Q " in window_id :
s_m , s_d = starts [ qn ]
raise ValueError (
e_m , e_d = ends [ qn ]
f " Quarterly window ' { window_id } ' is not supported. "
start = date ( y , s_m , s_d ) . isoformat ( )
" Only annual windows should be recomputed. "
end = date ( y , e_m , e_d ) . isoformat ( )
)
y = int ( window_id )
start = date ( y , 1 , 1 ) . isoformat ( )
end = date ( y , 12 , 31 ) . isoformat ( )
return start , end
return start , end
@ -76,12 +79,14 @@ def main(argv: List[str] | None = None) -> int:
db = MotionDatabase ( dst )
db = MotionDatabase ( dst )
# find windows from original DB via trajectory helper
# find windows from original DB via trajectory helper
window_ids = traj . _load_window_ids ( src )
all_window_ids = traj . _load_window_ids ( src )
# Only process annual windows — quarterly windows are excluded from all PCA/SVD computation
window_ids = [ w for w in all_window_ids if " -Q " not in w ]
if not window_ids :
if not window_ids :
logger . error ( " No windows found in source DB %s " , src )
logger . error ( " No annual windows found in source DB %s " , src )
return 3
return 3
logger . info ( " Will recompute SVD for windows: %s " , window_ids )
logger . info ( " Will recompute SVD for annual windows: %s " , window_ids )
# clear existing svd_vectors rows for these windows in dst DB
# clear existing svd_vectors rows for these windows in dst DB
import duckdb
import duckdb
@ -100,7 +105,7 @@ def main(argv: List[str] | None = None) -> int:
# Run SVD per window
# Run SVD per window
for wid in window_ids :
for wid in window_ids :
start , end = quarte r_bounds( wid )
start , end = yea r_bounds( wid )
logger . info ( " Running SVD for %s ( %s -> %s ) k= %d " , wid , start , end , args . k )
logger . info ( " Running SVD for %s ( %s -> %s ) k= %d " , wid , start , end , args . k )
res = run_svd_for_window (
res = run_svd_for_window (
db = db , window_id = wid , start_date = start , end_date = end , k = args . k
db = db , window_id = wid , start_date = start , end_date = end , k = args . k