412 auto is_comment_line = [](
const std::string& value) {
413 const auto first = value.find_first_not_of(
" \t");
414 return first != std::string::npos
415 && value.compare(first, 2,
"//") == 0;
418 if (this->skip_old_main) {
422 if (this->usesGenericTreeFirst()) {
423 if (currentLine.find(
"<iostream>") != std::string::npos) {
424 outputFile << currentLine <<
"\n";
425 if (this->disable_non_sm_particles || this->bsm_split_generation) {
426 outputFile <<
"#include <string>\n";
427 outputFile <<
"#include <unordered_set>\n";
428 outputFile <<
"#include <vector>\n";
430 outputFile <<
"#include \"" + this->model_path +
"\"\n";
431 outputFile <<
"#include \"" + this->marty_path +
"\"\n";
432 outputFile <<
"// " <<
modelSignature(this->target_model, this->model_path, this->model_template_index) <<
"\n";
433 outputFile <<
"// HYPERISO_MARTY_TREE_FIRST: TreeLevel then OneLoop fallback\n";
437 if ((this->disable_non_sm_particles || this->bsm_split_generation)
438 && currentLine.find(
"using namespace sm_input;") != std::string::npos) {
439 outputFile << currentLine <<
"\n";
440 outputFile << makeSmFilterHelper() <<
"\n";
444 if (currentLine.find(
"int calculate") != std::string::npos) {
445 std::string signature = currentLine;
446 const auto int_pos = signature.find(
"int ");
447 const auto open = signature.find(
'(', int_pos == std::string::npos ? 0 : int_pos + 4);
448 const auto close = signature.rfind(
')');
449 if (int_pos == std::string::npos || open == std::string::npos
450 || close == std::string::npos || close <= open) {
451 throw std::runtime_error(
452 "Cannot rewrite MARTY calculate signature for tree-first mode: " + currentLine
455 this->generic_builder_name = signature.substr(int_pos + 4, open - (int_pos + 4));
461 signature.insert(close,
", mty::Order hyperiso_marty_order");
462 signature.replace(int_pos, 3,
"Expr");
463 outputFile << signature <<
"\n";
464 this->inside_calculate_function =
true;
465 this->expression_returned =
false;
469 if (this->inside_calculate_function
470 && currentLine.find(
"FeynOptions opts;") != std::string::npos) {
471 outputFile << currentLine <<
"\n";
472 if (this->disable_non_sm_particles) {
473 outputFile <<
" hyperiso_marty_disable_non_sm_particles(opts, model);\n";
474 }
else if (this->bsm_split_generation && !this->full_target_generation) {
475 outputFile <<
" hyperiso_marty_require_non_sm_diagram_particle(opts);\n";
480 if (this->inside_calculate_function
481 && consumeTreeSafeWilsonCall(outputFile, currentLine,
false,
false)) {
485 if (this->inside_calculate_function
486 && (currentLine.find(
"[[maybe_unused]] int sysres") != std::string::npos
487 || currentLine.find(
"mty::Library wilsonLib") != std::string::npos
488 || currentLine.find(
"wilsonLib.cleanExistingSources") != std::string::npos
489 || currentLine.find(
"defineLibPath(wilsonLib)") != std::string::npos
490 || currentLine.find(
"wilsonLib.print") != std::string::npos)) {
494 if (this->inside_calculate_function
495 && currentLine.find(
"wilsonLib.addFunction") != std::string::npos) {
496 if (!this->expression_returned) {
497 const auto comma = currentLine.find_last_of(
',');
498 const auto close = currentLine.rfind(
')');
499 if (comma == std::string::npos || close == std::string::npos || close <= comma) {
500 throw std::runtime_error(
501 "Cannot rewrite MARTY addFunction line for tree-first mode: " + currentLine
504 const std::string expr = currentLine.substr(comma + 1, close - comma - 1);
505 outputFile <<
" return " << expr <<
";\n";
506 this->expression_returned =
true;
511 if (this->inside_calculate_function
512 && currentLine.find(
"return 0;") != std::string::npos) {
513 if (!this->expression_returned) {
514 outputFile <<
" return CSL_0;\n";
515 this->expression_returned =
true;
520 if (this->inside_calculate_function && currentLine ==
"}") {
521 this->inside_calculate_function =
false;
522 this->expression_returned =
false;
523 outputFile << currentLine <<
"\n";
527 if (currentLine.find(
"int main") != std::string::npos) {
528 if (this->generic_builder_name.empty()) {
529 throw std::runtime_error(
530 "MARTY tree-first generation reached main before calculate function"
533 outputFile <<
"int main() {\n";
534 outputFile <<
" " << this->model_instantiation <<
" model;\n";
535 outputFile <<
" Expr hyperiso_marty_tree = " << this->generic_builder_name
536 <<
"(model, gauge::Type::Feynman, mty::Order::TreeLevel);\n";
537 outputFile <<
" const bool hyperiso_marty_use_tree = hyperiso_marty_tree != CSL_0;\n";
538 outputFile <<
" Expr hyperiso_marty_selected = hyperiso_marty_tree;\n";
539 outputFile <<
" if (!hyperiso_marty_use_tree) {\n";
540 outputFile <<
" hyperiso_marty_selected = " << this->generic_builder_name
541 <<
"(model, gauge::Type::Feynman, mty::Order::OneLoop);\n";
542 outputFile <<
" }\n";
543 outputFile <<
" std::cout << \"[MARTY " << this->
wilson
544 <<
"] selected order=\" << (hyperiso_marty_use_tree ? \"TreeLevel\" : \"OneLoop\")"
545 <<
" << std::endl;\n";
546 outputFile <<
" [[maybe_unused]] int sysres = system(\"rm -rf libs/"
547 << this->wilson <<
"_" << this->output_model <<
"\");\n";
548 outputFile <<
" mty::Library wilsonLib(\"" << this->wilson <<
"_"
549 << this->output_model <<
"\", \"libs\");\n";
550 outputFile <<
" wilsonLib.cleanExistingSources();\n";
551 outputFile <<
" wilsonLib.addFunction(\"" << this->wilson
552 <<
"\", hyperiso_marty_selected);\n";
553 outputFile <<
" defineLibPath(wilsonLib);\n";
554 outputFile <<
" wilsonLib.print();\n";
555 outputFile <<
" return 0;\n";
557 this->skip_old_main =
true;
561 outputFile << currentLine <<
"\n";
565 if (this->usesRegPropSplit()) {
566 if (currentLine.find(
"<iostream>") != std::string::npos) {
567 outputFile << currentLine <<
"\n";
568 outputFile <<
"#include <string>\n";
569 outputFile <<
"#include <unordered_set>\n";
570 outputFile <<
"#include <vector>\n";
571 outputFile <<
"#include <cstddef>\n";
572 outputFile <<
"#include <utility>\n";
573 outputFile <<
"#include \"" + this->model_path +
"\"" <<
"\n";
574 outputFile <<
"#include \"" + this->marty_path +
"\"" <<
"\n";
575 outputFile <<
"// " <<
modelSignature(this->target_model, this->model_path, this->model_template_index) <<
"\n";
576 if (this->full_target_generation) {
577 outputFile <<
"// HYPERISO_MARTY_TARGET_SPLIT: complete target-model diagrams in "
578 << this->model_instantiation <<
"\n";
580 outputFile <<
"// HYPERISO_MARTY_BSM_SPLIT: diagrams with at least one non-SM diagram particle in "
581 << this->model_instantiation <<
"\n";
583 outputFile <<
"// HYPERISO_MARTY_BSM_SPLIT_ABI: model-split-v26\n";
587 if (currentLine.find(
"using namespace sm_input;") != std::string::npos) {
588 outputFile << currentLine <<
"\n";
589 outputFile << makeSmFilterHelper() <<
"\n";
593 if (currentLine.find(
"int calculate") != std::string::npos) {
594 outputFile <<
"std::pair<Expr, std::size_t> hyperiso_marty_build_" << this->
wilson
595 <<
"(Model &model, gauge::Type gauge, mty::Order hyperiso_marty_order, "
596 <<
"bool hyperiso_marty_sm_like_filter = false) {\n";
597 outputFile <<
" std::size_t hyperiso_marty_graph_count = 0;\n";
598 outputFile <<
" hyperiso_marty_set_semileptonic_order(hyperiso_marty_order);\n";
599 this->inside_calculate_function =
true;
600 this->expression_returned =
false;
604 if (this->inside_calculate_function && currentLine.find(
"FeynOptions opts;") != std::string::npos) {
605 outputFile << currentLine <<
"\n";
606 outputFile <<
" if (hyperiso_marty_sm_like_filter) {\n";
607 outputFile <<
" hyperiso_marty_disable_non_sm_particles(opts, model);\n";
608 if (!this->full_target_generation) {
609 outputFile <<
" } else {\n";
611 if (!this->full_target_generation) {
612 outputFile <<
" hyperiso_marty_require_non_sm_diagram_particle(opts);\n";
614 outputFile <<
" }\n";
618 if (this->inside_calculate_function
619 && consumeTreeSafeWilsonCall(outputFile, currentLine,
true,
true)) {
623 if (is_comment_line(currentLine)) {
624 outputFile << currentLine <<
"\n";
628 if (this->inside_calculate_function && currentLine.find(
"[[maybe_unused]] int sysres") != std::string::npos) {
631 if (this->inside_calculate_function && currentLine.find(
"mty::Library wilsonLib") != std::string::npos) {
634 if (this->inside_calculate_function && currentLine.find(
"wilsonLib.cleanExistingSources") != std::string::npos) {
637 if (this->inside_calculate_function && currentLine.find(
"defineLibPath(wilsonLib)") != std::string::npos) {
640 if (this->inside_calculate_function && currentLine.find(
"wilsonLib.print") != std::string::npos) {
643 if (this->inside_calculate_function && currentLine.find(
"wilsonLib.addFunction") != std::string::npos) {
644 if (!this->expression_returned) {
645 const auto comma = currentLine.find_last_of(
',');
646 const auto close = currentLine.rfind(
')');
647 if (comma == std::string::npos || close == std::string::npos || close <= comma) {
648 throw std::runtime_error(
"Cannot rewrite MARTY addFunction line for BSM split: " + currentLine);
650 std::string expr = currentLine.substr(comma + 1, close - comma - 1);
651 outputFile <<
" return std::make_pair(" << expr <<
", hyperiso_marty_graph_count);\n";
652 this->expression_returned =
true;
656 if (this->inside_calculate_function && currentLine.find(
"return 0;") != std::string::npos) {
657 if (!this->expression_returned) {
658 outputFile <<
" return std::make_pair(CSL_0, hyperiso_marty_graph_count);\n";
659 this->expression_returned =
true;
663 if (this->inside_calculate_function && currentLine ==
"}") {
664 this->inside_calculate_function =
false;
665 this->expression_returned =
false;
666 outputFile << currentLine <<
"\n";
670 if (currentLine.find(
"int main") != std::string::npos) {
671 const bool split_sm_components =
false;
672 const bool split_linker_components = (this->
wilson ==
"CP10");
673 outputFile <<
"int main() {\n";
674 const bool isolate_c9_tree_probe = (this->
wilson ==
"C9");
675 const std::string tree_model_name = isolate_c9_tree_probe ?
"tree_model" :
"model";
676 const std::string loop_model_name = isolate_c9_tree_probe ?
"loop_model" :
"model";
677 if (isolate_c9_tree_probe) {
678 outputFile <<
" // C9 is sensitive to MARTY state accumulated while probing TreeLevel.\n";
679 outputFile <<
" // Use a fresh target model for the OneLoop fallback so loop-only models\n";
680 outputFile <<
" // reproduce the historical one-loop-only result exactly.\n";
681 outputFile <<
" " << this->model_instantiation <<
" tree_model;\n";
682 outputFile <<
" " << this->model_instantiation <<
" loop_model;\n";
684 outputFile <<
" " << this->model_instantiation <<
" model;\n";
686 outputFile <<
" // Semileptonic BSM matching is tree-first. A non-zero tree-level\n";
687 outputFile <<
" // coefficient suppresses the one-loop calculation entirely; otherwise\n";
688 outputFile <<
" // MARTY falls back to the one-loop split-reg_prop path.\n";
689 outputFile <<
" hyperiso_marty_set_c9_linker_selection(HyperisoMartyC9LinkerSelection::NonPhotonVector);\n";
690 outputFile <<
" auto hyperiso_marty_bsm_tree = hyperiso_marty_build_" << this->
wilson
691 <<
"(" << tree_model_name
692 <<
", gauge::Type::Feynman, mty::Order::TreeLevel, false);\n";
693 outputFile <<
" const bool hyperiso_marty_use_tree_level = hyperiso_marty_bsm_tree.first != CSL_0;\n";
694 outputFile <<
" const char* hyperiso_marty_selected_order = hyperiso_marty_use_tree_level ? \"TreeLevel\" : \"OneLoop\";\n";
695 outputFile <<
" Expr hyperiso_marty_bsm = hyperiso_marty_bsm_tree.first;\n";
696 outputFile <<
" Expr hyperiso_marty_bsm_photon = CSL_0;\n";
697 outputFile <<
" Expr hyperiso_marty_bsm_scalar = CSL_0;\n";
698 outputFile <<
" Expr hyperiso_marty_bsm_vector = hyperiso_marty_bsm_tree.first;\n";
699 outputFile <<
" std::size_t hyperiso_marty_non_photon_graph_count = hyperiso_marty_bsm_tree.second;\n";
700 outputFile <<
" std::size_t hyperiso_marty_photon_graph_count = 0;\n";
701 outputFile <<
" std::size_t hyperiso_marty_scalar_graph_count = 0;\n";
702 outputFile <<
" std::size_t hyperiso_marty_vector_graph_count = hyperiso_marty_bsm_tree.second;\n";
703 outputFile <<
" if (!hyperiso_marty_use_tree_level) {\n";
704 outputFile <<
" hyperiso_marty_set_c9_linker_selection(HyperisoMartyC9LinkerSelection::NonPhotonVector);\n";
705 outputFile <<
" auto hyperiso_marty_bsm_loop = hyperiso_marty_build_" << this->
wilson
706 <<
"(" << loop_model_name
707 <<
", gauge::Type::Feynman, mty::Order::OneLoop, false);\n";
708 outputFile <<
" hyperiso_marty_bsm = hyperiso_marty_bsm_loop.first;\n";
709 outputFile <<
" hyperiso_marty_non_photon_graph_count = hyperiso_marty_bsm_loop.second;\n";
710 outputFile <<
" hyperiso_marty_set_c9_linker_selection(HyperisoMartyC9LinkerSelection::PhotonOnly);\n";
711 outputFile <<
" auto hyperiso_marty_bsm_photon_loop = hyperiso_marty_build_" << this->
wilson
712 <<
"(" << loop_model_name
713 <<
", gauge::Type::Feynman, mty::Order::OneLoop, false);\n";
714 outputFile <<
" hyperiso_marty_bsm_photon = hyperiso_marty_bsm_photon_loop.first;\n";
715 outputFile <<
" hyperiso_marty_photon_graph_count = hyperiso_marty_bsm_photon_loop.second;\n";
716 if (split_linker_components) {
717 outputFile <<
" hyperiso_marty_set_c9_linker_selection(HyperisoMartyC9LinkerSelection::ScalarOnly);\n";
718 outputFile <<
" auto hyperiso_marty_bsm_scalar_loop = hyperiso_marty_build_" << this->
wilson
719 <<
"(" << loop_model_name
720 <<
", gauge::Type::Feynman, mty::Order::OneLoop, false);\n";
721 outputFile <<
" hyperiso_marty_bsm_scalar = hyperiso_marty_bsm_scalar_loop.first;\n";
722 outputFile <<
" hyperiso_marty_scalar_graph_count = hyperiso_marty_bsm_scalar_loop.second;\n";
723 outputFile <<
" hyperiso_marty_set_c9_linker_selection(HyperisoMartyC9LinkerSelection::VectorOnly);\n";
724 outputFile <<
" auto hyperiso_marty_bsm_vector_loop = hyperiso_marty_build_" << this->
wilson
725 <<
"(" << loop_model_name
726 <<
", gauge::Type::Feynman, mty::Order::OneLoop, false);\n";
727 outputFile <<
" hyperiso_marty_bsm_vector = hyperiso_marty_bsm_vector_loop.first;\n";
728 outputFile <<
" hyperiso_marty_vector_graph_count = hyperiso_marty_bsm_vector_loop.second;\n";
730 outputFile <<
" hyperiso_marty_bsm_vector = hyperiso_marty_bsm;\n";
731 outputFile <<
" hyperiso_marty_vector_graph_count = hyperiso_marty_non_photon_graph_count;\n";
733 outputFile <<
" }\n";
734 if (split_linker_components) {
735 outputFile <<
" else {\n";
736 outputFile <<
" // At tree level the penguin linker split is disabled. Expose the\n";
737 outputFile <<
" // complete tree coefficient as VECTOR for diagnostics and do not\n";
738 outputFile <<
" // trigger additional tree or one-loop calculations.\n";
739 outputFile <<
" hyperiso_marty_bsm_vector = hyperiso_marty_bsm;\n";
740 outputFile <<
" hyperiso_marty_vector_graph_count = hyperiso_marty_bsm_tree.second;\n";
741 outputFile <<
" }\n";
743 outputFile <<
" std::cout << \"[MARTY " << this->
wilson <<
"] "
744 << (this->full_target_generation ?
"target" :
"BSM")
745 <<
" selected order=\" << hyperiso_marty_selected_order"
746 <<
" << \", tree=\" << hyperiso_marty_bsm_tree.second"
747 <<
" << \", non-photon=\" << hyperiso_marty_non_photon_graph_count"
748 <<
" << \", photon=\" << hyperiso_marty_photon_graph_count";
749 if (split_linker_components) {
750 outputFile <<
" << \", scalar=\" << hyperiso_marty_scalar_graph_count"
751 <<
" << \", vector=\" << hyperiso_marty_vector_graph_count";
753 outputFile <<
" << std::endl;\n";
754 if (split_sm_components) {
755 outputFile <<
" hyperiso_marty_set_c9_linker_selection(HyperisoMartyC9LinkerSelection::NonPhotonVector);\n";
756 outputFile <<
" auto hyperiso_marty_sm_loop = hyperiso_marty_build_" << this->
wilson
757 <<
"(model, gauge::Type::Feynman, mty::Order::OneLoop, true);\n";
758 outputFile <<
" Expr hyperiso_marty_sm = hyperiso_marty_sm_loop.first;\n";
759 outputFile <<
" hyperiso_marty_set_c9_linker_selection(HyperisoMartyC9LinkerSelection::PhotonOnly);\n";
760 outputFile <<
" auto hyperiso_marty_sm_photon_loop = hyperiso_marty_build_" << this->wilson
761 <<
"(model, gauge::Type::Feynman, mty::Order::OneLoop, true);\n";
762 outputFile <<
" Expr hyperiso_marty_sm_photon = hyperiso_marty_sm_photon_loop.first;\n";
763 outputFile <<
" hyperiso_marty_set_c9_linker_selection(HyperisoMartyC9LinkerSelection::ScalarOnly);\n";
764 outputFile <<
" auto hyperiso_marty_sm_scalar_loop = hyperiso_marty_build_" << this->wilson
765 <<
"(model, gauge::Type::Feynman, mty::Order::OneLoop, true);\n";
766 outputFile <<
" Expr hyperiso_marty_sm_scalar = hyperiso_marty_sm_scalar_loop.first;\n";
767 outputFile <<
" hyperiso_marty_set_c9_linker_selection(HyperisoMartyC9LinkerSelection::VectorOnly);\n";
768 outputFile <<
" auto hyperiso_marty_sm_vector_loop = hyperiso_marty_build_" << this->wilson
769 <<
"(model, gauge::Type::Feynman, mty::Order::OneLoop, true);\n";
770 outputFile <<
" Expr hyperiso_marty_sm_vector = hyperiso_marty_sm_vector_loop.first;\n";
772 outputFile <<
" Expr hyperiso_marty_sm = CSL_0;\n";
773 outputFile <<
" Expr hyperiso_marty_sm_photon = CSL_0;\n";
774 outputFile <<
" Expr hyperiso_marty_sm_scalar = CSL_0;\n";
775 outputFile <<
" Expr hyperiso_marty_sm_vector = CSL_0;\n";
777 outputFile <<
" hyperiso_marty_set_c9_linker_selection(HyperisoMartyC9LinkerSelection::NonPhotonVector);\n";
778 outputFile <<
" [[maybe_unused]] int sysres = system(\"rm -rf libs/" << this->
wilson <<
"_" << this->output_model <<
"\");\n";
779 outputFile <<
" mty::Library wilsonLib(\"" << this->
wilson <<
"_" << this->output_model <<
"\", \"libs\");\n";
780 outputFile <<
" wilsonLib.cleanExistingSources();\n";
781 outputFile <<
" wilsonLib.addFunction(\"" << this->
wilson <<
"\", hyperiso_marty_bsm);\n";
782 outputFile <<
" wilsonLib.addFunction(\"" << this->wilson <<
"_A\", hyperiso_marty_bsm_photon);\n";
783 outputFile <<
" wilsonLib.addFunction(\"" << this->wilson <<
"_SCALAR\", hyperiso_marty_bsm_scalar);\n";
784 outputFile <<
" wilsonLib.addFunction(\"" << this->wilson <<
"_VECTOR\", hyperiso_marty_bsm_vector);\n";
785 outputFile <<
" wilsonLib.addFunction(\"" << this->wilson <<
"_SM\", hyperiso_marty_sm);\n";
786 outputFile <<
" wilsonLib.addFunction(\"" << this->wilson <<
"_SM_A\", hyperiso_marty_sm_photon);\n";
787 outputFile <<
" wilsonLib.addFunction(\"" << this->wilson <<
"_SM_SCALAR\", hyperiso_marty_sm_scalar);\n";
788 outputFile <<
" wilsonLib.addFunction(\"" << this->wilson <<
"_SM_VECTOR\", hyperiso_marty_sm_vector);\n";
789 outputFile <<
" wilsonLib.addFunction(\"" << this->wilson <<
"_TOT\", hyperiso_marty_sm + hyperiso_marty_bsm);\n";
790 outputFile <<
" wilsonLib.addFunction(\"" << this->wilson <<
"_TOT_A\", hyperiso_marty_sm_photon + hyperiso_marty_bsm_photon);\n";
791 outputFile <<
" wilsonLib.addFunction(\"" << this->wilson <<
"_TOT_SCALAR\", hyperiso_marty_sm_scalar + hyperiso_marty_bsm_scalar);\n";
792 outputFile <<
" wilsonLib.addFunction(\"" << this->wilson <<
"_TOT_VECTOR\", hyperiso_marty_sm_vector + hyperiso_marty_bsm_vector);\n";
793 outputFile <<
" defineLibPath(wilsonLib);\n";
794 outputFile <<
" wilsonLib.print();\n";
795 outputFile <<
" return 0;\n";
797 this->skip_old_main =
true;
801 outputFile << currentLine <<
"\n";
805 if (currentLine.find(
"<iostream>") != std::string::npos) {
806 outputFile << currentLine <<
"\n";
807 if (this->disable_non_sm_particles || this->bsm_split_generation) {
808 outputFile <<
"#include <string>\n";
809 outputFile <<
"#include <unordered_set>\n";
810 outputFile <<
"#include <vector>\n";
812 outputFile <<
"#include \"" + this->model_path +
"\"" <<
"\n";
813 outputFile <<
"#include \"" + this->marty_path +
"\"" <<
"\n";
814 outputFile <<
"// " <<
modelSignature(this->target_model, this->model_path, this->model_template_index) <<
"\n";
815 if (this->disable_non_sm_particles) {
816 outputFile <<
"// HYPERISO_MARTY_SM_LIKE_FILTER: disable non-SM particles in "
817 << this->model_instantiation <<
"\n";
818 }
else if (this->bsm_split_generation) {
819 outputFile <<
"// HYPERISO_MARTY_BSM_ONLY_FILTER: require a non-SM diagram particle in "
820 << this->model_instantiation <<
"\n";
823 else if ((this->disable_non_sm_particles || this->bsm_split_generation)
824 && currentLine.find(
"using namespace sm_input;") != std::string::npos) {
825 outputFile << currentLine <<
"\n";
826 outputFile << makeSmFilterHelper() <<
"\n";
828 else if (this->disable_non_sm_particles
829 && currentLine.find(
"FeynOptions opts;") != std::string::npos) {
830 outputFile << currentLine <<
"\n";
831 outputFile <<
" hyperiso_marty_disable_non_sm_particles(opts, model);\n";
833 else if (this->bsm_split_generation
834 && currentLine.find(
"FeynOptions opts;") != std::string::npos) {
835 outputFile << currentLine <<
"\n";
836 outputFile <<
" hyperiso_marty_require_non_sm_diagram_particle(opts);\n";
839 outputFile << currentLine <<
"\n";