@@ -615,6 +615,88 @@ def get_router_process_identifier(procinfo):
615615 )
616616 )
617617
618+ # Pre-flight validation: check that required FHiCL configuration parameters
619+ # are present before attempting bookkeeping substitutions. Bookkeeping
620+ # uses re.sub to update these parameters in-place; if a required parameter
621+ # is absent re.sub silently does nothing, leaving the process with
622+ # incorrect or missing configuration.
623+
624+ for procinfo in self .procinfos :
625+
626+ if "RoutingManager" in procinfo .name :
627+ continue
628+
629+ fhicl_with_leading_newline = "\n " + procinfo .fhicl_used
630+
631+ # EventBuilders must have expected_fragments_per_event so that
632+ # bookkeeping can set the correct per-subsystem fragment count.
633+ if "EventBuilder" in procinfo .name :
634+ if not re .search (
635+ r"\n[^#\n]*expected_fragments_per_event\s*:" ,
636+ fhicl_with_leading_newline ,
637+ ):
638+ raise Exception (
639+ make_paragraph (
640+ "Required FHiCL parameter 'expected_fragments_per_event' was not "
641+ "found in the configuration for %s (%s). DAQInterface sets this "
642+ "parameter during bookkeeping - please add "
643+ "'expected_fragments_per_event: 0' (or any placeholder value) to "
644+ "the FHiCL document."
645+ % (procinfo .label , procinfo .name )
646+ )
647+ )
648+
649+ # DataLoggers and Dispatchers have expected_fragments_per_event set to
650+ # 1 by bookkeeping when the parameter is present; warn if it is missing.
651+ if "DataLogger" in procinfo .name or "Dispatcher" in procinfo .name :
652+ if not re .search (
653+ r"\n[^#\n]*expected_fragments_per_event\s*:" ,
654+ fhicl_with_leading_newline ,
655+ ):
656+ self .print_log (
657+ "w" ,
658+ make_paragraph (
659+ "FHiCL parameter 'expected_fragments_per_event' was not found in "
660+ "the configuration for %s (%s). DAQInterface sets this to 1 "
661+ "during bookkeeping when the parameter is present - consider "
662+ "adding 'expected_fragments_per_event: 0' to the FHiCL document."
663+ % (procinfo .label , procinfo .name )
664+ ),
665+ )
666+
667+ # Non-BoardReader processes receive data and must have a 'sources'
668+ # table placeholder so that bookkeeping can fill in the correct
669+ # upstream connections.
670+ if "BoardReader" not in procinfo .name :
671+ (sources_start , _ ) = table_range (procinfo .fhicl_used , "sources" )
672+ if sources_start == - 1 :
673+ raise Exception (
674+ make_paragraph (
675+ "Required FHiCL table 'sources' was not found in the "
676+ "configuration for %s (%s). DAQInterface fills in this table "
677+ "during bookkeeping - please add 'sources: {}' to the FHiCL "
678+ "document."
679+ % (procinfo .label , procinfo .name )
680+ )
681+ )
682+
683+ # BoardReader processes must have a 'destinations' table placeholder
684+ # so that bookkeeping can fill in the EventBuilders to send data to.
685+ if "BoardReader" in procinfo .name :
686+ (destinations_start , _ ) = table_range (
687+ procinfo .fhicl_used , "destinations"
688+ )
689+ if destinations_start == - 1 :
690+ raise Exception (
691+ make_paragraph (
692+ "Required FHiCL table 'destinations' was not found in the "
693+ "configuration for %s (%s). DAQInterface fills in this table "
694+ "during bookkeeping - please add 'destinations: {}' to the "
695+ "FHiCL document."
696+ % (procinfo .label , procinfo .name )
697+ )
698+ )
699+
618700 for i_proc in range (len (self .procinfos )):
619701
620702 for tablename in ["sources" , "destinations" ]:
0 commit comments