371):
372 """Simple script to create an OKS configuration file for all
373 ReadoutApplications defined in a readout map.
374
375 The file will automatically include the relevant schema files and
376 any other OKS files you specify.
377
378 Example:
379 generate_readoutOKS -i hosts \
380 -i appmodel/connections.data.xml -i appmodel/moduleconfs \
381 config/np04readoutmap.data.xml readoutApps.data.xml
382
383 Will load hosts, connections and moduleconfs data files as well as
384 the readoutmap (config/np04readoutmap.data.xml) and write the
385 generated apps to readoutApps.data.xml.
386
387 generate_readoutOKS --session --segment \
388 -i appmodel/fsm -i hosts \
389 -i appmodel/connections.data.xml -i appmodel/moduleconfs \
390 config/np04readoutmap.data.xml np04readout-session.data.xml
391
392 Will do the same but in addition it will generate a containing
393 Segment for the apps and a containing Session for the Segment.
394
395 NB: Currently FSM generation is not implemented so you must include
396 an fsm file in order to generate a Segment
397
398 """
399
400 if not readoutmap.endswith(".data.xml"):
401 readoutmap = readoutmap + ".data.xml"
402
403 print(f"Readout map file {readoutmap}")
404
405 includefiles = (
406 [
407 "schema/confmodel/dunedaq.schema.xml",
408 "schema/appmodel/application.schema.xml",
409 "schema/appmodel/trigger.schema.xml",
410 "schema/appmodel/fdmodules.schema.xml",
411 "schema/appmodel/wiec.schema.xml",
412 ]
413 + [readoutmap]
414 if os.path.exists(readoutmap)
415 else []
416 )
417
418 searchdirs = [path for path in os.environ["DUNEDAQ_DB_PATH"].split(":")]
419 searchdirs.append(os.path.dirname(oksfile))
420 for inc in include:
421
422 match = False
423 inc = inc.removesuffix(".xml")
424 if inc.endswith(".data"):
425 sub_dirs = ["config", "data"]
426 elif inc.endswith(".schema"):
427 sub_dirs = ["schema"]
428 else:
429 sub_dirs = ["*"]
430 inc = inc + "*"
431 for path in searchdirs:
432
433 matches = glob.glob(f"{inc}.xml", root_dir=path)
434 if len(matches) == 0:
435 for search_dir in sub_dirs:
436
437 matches = glob.glob(f"{search_dir}/{inc}.xml", root_dir=path)
438 for filename in matches:
439 if filename not in includefiles:
440 print(f"Adding {filename} to include list")
441 includefiles.append(filename)
442 else:
443 print(f"{filename} already in include list")
444 match = True
445 break
446 if match:
447 break
448 if match:
449 break
450 else:
451 for filename in matches:
452 if filename not in includefiles:
453 print(f"Adding {filename} to include list")
454 includefiles.append(filename)
455 else:
456 print(f"{filename} already in include list")
457 match = True
458 break
459
460 if not match:
461 print(f"Error could not find include file for {inc}")
462 return
463
466 if not oksfile.endswith(".data.xml"):
467 oksfile = oksfile + ".data.xml"
468 print(f"Creating OKS database file {oksfile}")
469 db.create_db(oksfile, includefiles)
470 db.set_active(oksfile)
471
472 detector_connections = db.get_dals(class_name="DetectorToDaqConnection")
473 daqapp_control = db.get_dal(class_name="Service", uid="daqapp_control")
474 rccontroller_control = db.get_dal(class_name="Service", uid="rccontroller_control")
475
476 try:
477 rule = db.get_dal(
478 class_name="NetworkConnectionRule", uid="data-req-readout-net-rule"
479 )
480 except:
481 print(
482 'Expected NetworkConnectionRule "data-req-readout-net-rule" not found in input databases!'
483 )
484 else:
485 netrules = [rule]
486
487 for rule in ["tpset-net-rule", "ts-net-rule", "ta-net-rule"]:
488 netrules.append(db.get_dal(class_name="NetworkConnectionRule", uid=rule))
489
490 try:
491 rule = db.get_dal(
492 class_name="QueueConnectionRule", uid="fd-dlh-data-requests-queue-rule"
493 )
494 except:
495 print(
496 'Expected QueueConnectionRule "fd-dlh-data-requests-queue-rule" not found in input databases!'
497 )
498 else:
499 qrules = [rule]
500 for rule in [
501 "fa-queue-rule",
502 "tp-queue-rule",
503 ]:
504 qrules.append(db.get_dal(class_name="QueueConnectionRule", uid=rule))
505
506 hosts = []
507 if len(hosts_to_use) == 0:
508 for vhost in db.get_dals(class_name="VirtualHost"):
509 if vhost.id == "vlocalhost":
510 hosts.append(vhost.id)
511 if "vlocalhost" not in hosts:
512 cpus = dal.ProcessingResource("cpus", cpu_cores=[0, 1, 2, 3])
513 db.update_dal(cpus)
514 phdal = dal.PhysicalHost("localhost", contains=[cpus])
515 db.update_dal(phdal)
516 host = dal.VirtualHost("vlocalhost", runs_on=phdal, uses=[cpus])
517 db.update_dal(host)
518 hosts.append("vlocalhost")
519 else:
520 for vhost in db.get_dals(class_name="VirtualHost"):
521 if vhost.id in hosts_to_use:
522 hosts.append(vhost.id)
523 assert len(hosts) > 0
524
525 rohw = dal.RoHwConfig(f"rohw-{detector_connections[0].id}")
526 db.update_dal(rohw)
527
528 opmon_conf = db.get_dal(class_name="OpMonConf", uid="slow-all-monitoring")
529 fragagg = db.get_dal(class_name="FragmentAggregatorConf", uid="frag-agg-01")
530
531 appnum = 0
532 nicrec = None
533 flxcard = None
534 wm_conf = None
535 hermes_conf = None
536 ruapps = []
537 for connection in detector_connections:
538
539 geo_id = connection.get("GeoId")
540 det_id = geo_id[0].detector_id
541 if det_id == 0:
542 raise Exception(f"Unable to determine detector ID from Hardware Map!")
543
544 tphandler = db.get_dal(class_name="DataHandlerConf", uid="def-tp-handler")
545
546 if det_id == 2:
547 if "DAPHNEStream" in emulated_file_name:
548 linkhandler = db.get_dal(
549 class_name="DataHandlerConf", uid="def-pds-stream-link-handler"
550 )
551 cb_desc = db.get_dal(
552 class_name="DataMoveCallbackDescriptor", uid="pds-stream-raw-input"
553 )
554 else:
555 linkhandler = db.get_dal(
556 class_name="DataHandlerConf", uid="def-pds-link-handler"
557 )
558 cb_desc = db.get_dal(
559 class_name="DataMoveCallbackDescriptor", uid="pds-raw-input"
560 )
561
562 elif det_id == 3 or det_id == 10:
563 linkhandler = db.get_dal(
564 class_name="DataHandlerConf", uid="def-link-handler"
565 )
566 cb_desc = db.get_dal(
567 class_name="DataMoveCallbackDescriptor", uid="wib-eth-raw-input"
568 )
569 elif det_id == 11:
570 linkhandler = db.get_dal(
571 class_name="DataHandlerConf", uid="def-tde-link-handler"
572 )
573 cb_desc = db.get_dal(
574 class_name="DataMoveCallbackDescriptor", uid="tde-raw-input"
575 )
576 elif det_id == 12:
577 linkhandler = db.get_dal(
578 class_name="DataHandlerConf", uid="def-crt-bern-link-handler"
579 )
580
581 cb_desc = db.get_dal(
582 class_name="DataMoveCallbackDescriptor", uid="crt-bern-raw-input"
583 )
584 elif det_id == 13:
585 linkhandler = db.get_dal(
586 class_name="DataHandlerConf", uid="def-crt-grenoble-link-handler"
587 )
588
589 cb_desc = db.get_dal(
590 class_name="DataMoveCallbackDescriptor", uid="crt-grenoble-raw-input"
591 )
592
593 hostnum = appnum % len(hosts)
594
595 host = db.get_dal(class_name="VirtualHost", uid=hosts[hostnum])
596
597
598 if connection.className() == "NetworkDetectorToDaqConnection":
599 receiver = connection.net_receiver
600 elif connection.className() == "FelixDetectorToDaqConnection":
601 receiver = connection.felix_receiver
602
603
604 readout_start = db.get_dal(class_name="ActionPlan", uid="readout-start")
605 readout_stop = db.get_dal(class_name="ActionPlan", uid="readout-stop")
606
607
608 if type(receiver).__name__ == "FakeDataReceiver":
609 if nicrec == None:
610 try:
611 stream_emu = db.get_dal(
612 class_name="StreamEmulationParameters", uid="stream-emu"
613 )
614 stream_emu.data_file_name = resolve_asset_file(emulated_file_name)
615 db.update_dal(stream_emu)
616 except:
617 stream_emu = dal.StreamEmulationParameters(
618 "stream-emu",
619 data_file_name=resolve_asset_file(emulated_file_name),
620 input_file_size_limit=5777280,
621 set_t0=True,
622 random_population_size=100000,
623 frame_error_rate_hz=0,
624 generate_periodic_adc_pattern=True,
625 TP_rate_per_channel=1,
626 )
627 db.update_dal(stream_emu)
628
629 print("Generating fake DataReaderConf")
630 nicrec = dal.DPDKReaderConf(
631 f"nicrcvr-fake-gen",
632 template_for="FDFakeReaderModule",
633 emulation_mode=1,
634 emulation_conf=stream_emu,
635 )
636 db.update_dal(nicrec)
637 datareader = nicrec
638 elif type(receiver).__name__ == "DPDKReceiver":
639 if nicrec == None:
640 print("Generating DPDKReaderConf")
641 nicrec = dal.DPDKReaderConf(
642 f"nicrcvr-dpdk-gen", template_for="DPDKReaderModule"
643 )
644 db.update_dal(nicrec)
645 if wm_conf == None:
646 try:
647 wm_conf = db.get_dal("WIBModuleConf", "def-wib-conf")
648 except:
649 print(
650 'Expected WIBModuleConf "def-wib-conf" not found in input databases!'
651 )
652 if hermes_conf == None:
653 try:
654 hermes_conf = db.get_dal("HermesModuleConf", "def-hermes-conf")
655 except:
656 print(
657 'Expected HermesModuleConf "def-hermes-conf" not found in input databases!'
658 )
659
660 datareader = nicrec
661
662 wiec_app = dal.WIECApplication(
663 f"wiec-{connection.id}",
664 application_name="daq_application",
665 runs_on=host,
666 detector_connections=[connection],
667 wib_module_conf=wm_conf,
668 hermes_module_conf=hermes_conf,
669 exposes_service=[daqapp_control],
670 )
671 db.update_dal(wiec_app)
672
673 elif type(receiver).__name__ == "FelixInterface":
674 if flxcard == None:
675 print("Generating Felix DataReaderConf")
676 flxcard = dal.DataReaderConf(
677 f"flxConf-1", template_for="FelixReaderModule"
678 )
679 db.update_dal(flxcard)
680 datareader = flxcard
681 elif type(receiver).__name__ == "FileReaderReceiver":
682 if nicrec == None:
683 try:
684 snb_files = db.get_dal(
685 class_name="SNBFileSourceParameters",
686 uid=f"snb-files-{connection.id}",
687 )
688 snb_files.data_files = [resolve_asset_file(emulated_file_name)]
689 db.update_dal(snb_files)
690 except:
691 snb_files = dal.SNBFileSourceParameters(
692 "snb-files-0",
693 data_files=[resolve_asset_file(emulated_file_name)],
694 input_buffer_size=5777280,
695 file_compression_algorithm="None",
696 )
697 db.update_dal(snb_files)
698
699 print("Generating fake DataReaderConf")
700 nicrec = dal.SNBFileReaderConf(
701 f"nicrcvr-file-reader",
702 template_for="SNBFileReaderModule",
703 emulation_mode=1,
704 snb_conf=snb_files,
705 )
706 db.update_dal(nicrec)
707 datareader = nicrec
708
709 print(f"Using SNB DataHandler")
710 linkhandler.template_for = "SNBDataHandlerModule"
711 db.update_dal(linkhandler)
712
713 readout_start = db.get_dal(class_name="ActionPlan", uid="snb-readout-start")
714 readout_stop = db.get_dal(class_name="ActionPlan", uid="snb-readout-stop")
715 else:
716 print(
717 f"ReadoutGroup contains unknown interface type {type(receiver).__name__}"
718 )
719 continue
720
721 db.commit()
722
723
724 dataRequests = db.get_dal(class_name="Service", uid="dataRequests")
725 timeSyncs = db.get_dal(class_name="Service", uid="timeSyncs")
726 triggerActivities = db.get_dal(class_name="Service", uid="triggerActivities")
727 triggerPrimitives = db.get_dal(class_name="Service", uid="triggerPrimitives")
728
729 ru = dal.ReadoutApplication(
730 f"ru-{connection.id}",
731 application_name="daq_application",
732 runs_on=host,
733 detector_connections=[connection],
734 network_rules=netrules,
735 queue_rules=qrules,
736 link_handler=linkhandler,
737 data_reader=datareader,
738 fragment_aggregator=fragagg,
739 opmon_conf=opmon_conf,
740 tp_generation_enabled=tpg_enabled,
741 ta_generation_enabled=tpg_enabled,
742 uses=rohw,
743 exposes_service=[daqapp_control, dataRequests, timeSyncs],
744 action_plans=[readout_start, readout_stop],
745 callback_desc=cb_desc,
746 )
747 if tpg_enabled:
748 ru.tp_handler = tphandler
749 tp_sources = []
750 tpbaseid = (appnum * 3) + 100
751
752
753 for plane in range(1 if det_id not in [3, 10, 11] else 3):
754 s_id = tpbaseid + plane
755 tps_dal = dal.SourceIDConf(
756 f"tp-srcid-{s_id}", sid=s_id, subsystem="Trigger"
757 )
758 db.update_dal(tps_dal)
759 tp_sources.append(tps_dal)
760 ru.tp_source_ids = tp_sources
761 ru.exposes_service += [triggerActivities, triggerPrimitives]
762 appnum = appnum + 1
763 print(f"{ru=}")
764 db.update_dal(ru)
765 db.commit()
766 ruapps.append(ru)
767 if appnum == 0:
768 print(f"No ReadoutApplications generated\n")
769 return
770
771 db.commit()
772
773 if generate_segment:
774
775 fsm = db.get_dal(class_name="FSMconfiguration", uid="FSMconfiguration_noAction")
776 controller = dal.RCApplication(
777 "ru-controller",
778 application_name="drunc-controller",
779 runs_on=host,
780 fsm=fsm,
781 opmon_conf=opmon_conf,
782 exposes_service=[rccontroller_control],
783 )
784 db.update_dal(controller)
785 db.commit()
786
787 seg = dal.Segment(f"ru-segment", controller=controller, applications=ruapps)
788 db.update_dal(seg)
789 db.commit()
790
791 db.commit()
792 return
793
794