diff --git a/form/CMakeLists.txt b/form/CMakeLists.txt index 35d7d591f..e7b3ed99c 100644 --- a/form/CMakeLists.txt +++ b/form/CMakeLists.txt @@ -8,6 +8,8 @@ # ############################################################################## # Copyright (C) 2025 ... +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + include_directories(${PROJECT_SOURCE_DIR}/form) # ROOT Storage toggle @@ -18,7 +20,6 @@ endif() # Add sub directories add_subdirectory(form) -add_subdirectory(mock_phlex) add_subdirectory(core) add_subdirectory(util) add_subdirectory(persistence) @@ -26,3 +27,9 @@ add_subdirectory(storage) if(FORM_USE_ROOT_STORAGE) add_subdirectory(root_storage) endif() + +add_library(form_module MODULE form_module.cpp) + +target_link_libraries(form_module PRIVATE phlex::module form) + +target_include_directories(form_module PRIVATE ${PROJECT_SOURCE_DIR}) diff --git a/form/form/form.cpp b/form/form/form.cpp index eb2d5721c..8689685d2 100644 --- a/form/form/form.cpp +++ b/form/form/form.cpp @@ -4,88 +4,85 @@ namespace form::experimental { - // Accept and store config - form_interface::form_interface(std::shared_ptr tm, - mock_phlex::config::parse_config const& config) : + form_interface::form_interface(std::shared_ptr tm, + config::output_item_config const& output_config, + config::tech_setting_config const& tech_config) : m_pers(nullptr), m_type_map(tm) { - // Convert phlex config to form config - form::experimental::config::output_item_config output_items; - for (auto const& phlex_item : config.getItems()) { - output_items.addItem(phlex_item.product_name, phlex_item.file_name, phlex_item.technology); - m_product_to_config.emplace( - phlex_item.product_name, - form::experimental::config::PersistenceItem( - phlex_item.product_name, phlex_item.file_name, phlex_item.technology)); + for (auto const& item : output_config.getItems()) { + m_product_to_config.emplace(item.product_name, + form::experimental::config::PersistenceItem( + item.product_name, item.file_name, item.technology)); } - config::tech_setting_config tech_config_settings; - tech_config_settings.file_settings = config.getFileSettings(); - tech_config_settings.container_settings = config.getContainerSettings(); - m_pers = form::detail::experimental::createPersistence(); - m_pers->configureOutputItems(output_items); - m_pers->configureTechSettings(tech_config_settings); + m_pers->configureOutputItems(output_config); + m_pers->configureTechSettings(tech_config); } - void form_interface::write(std::string const& creator, mock_phlex::product_base const& pb) + void form_interface::write(std::string const& creator, + std::string const& segment_id, + product_with_name const& pb) { - // Look up creator from PersistenceItem. + auto it = m_product_to_config.find(pb.label); if (it == m_product_to_config.end()) { throw std::runtime_error("No configuration found for product: " + pb.label); } std::string const type = m_type_map->names[pb.type]; - // FIXME: Really only needed on first call + std::map products = {{pb.label, type}}; m_pers->createContainers(creator, products); + m_pers->registerWrite(creator, pb.label, pb.data, type); - m_pers->commitOutput(creator, pb.id); + + m_pers->commitOutput(creator, segment_id); } - // Look up creator from config void form_interface::write(std::string const& creator, - std::vector const& batch) + std::string const& segment_id, + std::vector const& products) { - if (batch.empty()) + + if (products.empty()) return; - // Look up creator from config based on product name. O(1) lookup instead of loop - auto it = m_product_to_config.find(batch[0].label); + auto it = m_product_to_config.find(products[0].label); if (it == m_product_to_config.end()) { - throw std::runtime_error("No configuration found for product: " + batch[0].label); + throw std::runtime_error("No configuration found for product: " + products[0].label); } // FIXME: Really only needed on first call - std::map products; - for (auto const& pb : batch) { + std::map product_types; + for (auto const& pb : products) { std::string const& type = m_type_map->names[pb.type]; - products.insert(std::make_pair(pb.label, type)); + product_types.insert(std::make_pair(pb.label, type)); } - m_pers->createContainers(creator, products); - for (auto const& pb : batch) { + + m_pers->createContainers(creator, product_types); + + for (auto const& pb : products) { std::string const& type = m_type_map->names[pb.type]; // FIXME: We could consider checking id to be identical for all product bases here m_pers->registerWrite(creator, pb.label, pb.data, type); } - // Single commit per segment (product ID shared among products in the same segment) - std::string const& id = batch[0].id; - m_pers->commitOutput(creator, id); + + m_pers->commitOutput(creator, segment_id); } - void form_interface::read(std::string const& creator, mock_phlex::product_base& pb) + void form_interface::read(std::string const& creator, + std::string const& segment_id, + product_with_name& pb) { - // Look up creator from config based on product name. O(1) lookup instead of loop + auto it = m_product_to_config.find(pb.label); if (it == m_product_to_config.end()) { throw std::runtime_error("No configuration found for product: " + pb.label); } - // Original type lookup std::string type = m_type_map->names[pb.type]; - // Use full_label instead of pb.label - m_pers->read(creator, pb.label, pb.id, &pb.data, type); + m_pers->read(creator, pb.label, segment_id, &pb.data, type); } } diff --git a/form/form/form.hpp b/form/form/form.hpp index 97efbd8da..52b8e076d 100644 --- a/form/form/form.hpp +++ b/form/form/form.hpp @@ -4,29 +4,49 @@ #define __FORM_HPP__ #include "form/config.hpp" -#include "mock_phlex/phlex_toy_config.hpp" -#include "mock_phlex/phlex_toy_core.hpp" // FORM Interface may include core phlex modules #include "persistence/ipersistence.hpp" +#include #include #include +#include +#include +#include namespace form::experimental { + + struct product_type_names { + std::unordered_map names; + }; + + struct product_with_name { + std::string label; + void const* data; + std::type_index type; + }; + class form_interface { public: - form_interface(std::shared_ptr tm, - mock_phlex::config::parse_config const& config); + form_interface(std::shared_ptr tm, + config::output_item_config const& output_config, + config::tech_setting_config const& tech_config); ~form_interface() = default; - void write(std::string const& creator, mock_phlex::product_base const& pb); void write(std::string const& creator, - std::vector const& batch); // batch version - void read(std::string const& creator, mock_phlex::product_base& pb); + std::string const& segment_id, + product_with_name const& product); + + void write(std::string const& creator, + std::string const& segment_id, + std::vector const& products); + + void read(std::string const& creator, + std::string const& segment_id, + product_with_name& product); private: std::unique_ptr m_pers; - std::shared_ptr m_type_map; - // Fast lookup maps built once in constructor + std::shared_ptr m_type_map; std::map m_product_to_config; }; } diff --git a/form/form_module.cpp b/form/form_module.cpp new file mode 100644 index 000000000..a2067af79 --- /dev/null +++ b/form/form_module.cpp @@ -0,0 +1,156 @@ +#include "phlex/model/product_store.hpp" +#include "phlex/model/products.hpp" +#include "phlex/module.hpp" + +// FORM headers - these need to be available via CMake configuration +// need to set up the build system to find these headers +#include "form/config.hpp" +#include "form/form.hpp" +#include "form/technology.hpp" + +#include + +namespace { + + class FormOutputModule { + public: + FormOutputModule(std::shared_ptr type_map, + std::string output_file, + int technology, + std::vector const& products_to_save) : + m_type_map(type_map), m_output_file(std::move(output_file)), m_technology(technology) + { + std::cout << "FormOutputModule initialized\n"; + std::cout << " Output file: " << m_output_file << "\n"; + std::cout << " Technology: " << m_technology << "\n"; + + // Build FORM configuration + form::experimental::config::output_item_config output_cfg; + form::experimental::config::tech_setting_config tech_cfg; + + // FIXME: Temporary solution to accommodate Phlex limitation. + // Eventually, Phlex will communicate to FORM which products will be written + // before executing any algorithms + + // Temp. Sol for Phlex Prototype 0.1 + // Register products from config + for (auto const& product : products_to_save) { + output_cfg.addItem(product, m_output_file, m_technology); + } + + // Initialize FORM interface + m_form_interface = + std::make_unique(type_map, output_cfg, tech_cfg); + } + + // This method is called by Phlex - signature must be: void(product_store const&) + void save_data_products(phlex::experimental::product_store const& store) + { + // Check if store is empty - smart way, check store not products vector + if (store.empty()) { + return; + } + + // STEP 1: Extract metadata from Phlex's product_store + + // Extract creator (algorithm name) + std::string creator = store.source(); + + // Extract segment ID (partition) - extract once for entire store + std::string segment_id = store.id()->to_string(); + + std::cout << "\n=== FormOutputModule::save_data_products ===\n"; + std::cout << "Creator: " << creator << "\n"; + std::cout << "Segment ID: " << segment_id << "\n"; + std::cout << "Number of products: " << store.size() << "\n"; + + // STEP 2: Convert each Phlex product to FORM format + + // Collect all products for writing + std::vector products; + + // Reserve space for efficiency - avoid reallocations + products.reserve(store.size()); + + // Iterate through all products in the store + for (auto const& [product_name, product_ptr] : store) { + // product_name: "tracks" (from the map key) + // product_ptr: pointer to the actual product data + + std::cout << " Product: " << product_name << "\n"; + + // Create FORM product with metadata + products.emplace_back(product_name, // label, from map key + product_ptr->address(), // data, from phlex product_base + product_ptr->type() // type, from phlex product_base + ); + } + + // STEP 3: Send everything to FORM for persistence + + // Write all products to FORM + // Pass segment_id once for entire collection (not duplicated in each product) + // No need to check if products is empty - already checked store.empty() above + m_form_interface->write(creator, segment_id, products); + std::cout << "Wrote " << products.size() << " products to FORM\n"; + } + + private: + std::shared_ptr m_type_map; + std::string m_output_file; + int m_technology; + std::unique_ptr m_form_interface; + }; + +} + +PHLEX_EXPERIMENTAL_REGISTER_ALGORITHMS(m, config) +{ + std::cout << "Registering FORM output module...\n"; + + // Create type map + auto type_map = std::make_shared(); + + // Register some fundamental type for simple products + type_map->names[std::type_index(typeid(int))] = "int"; + type_map->names[std::type_index(typeid(long))] = "long"; + type_map->names[std::type_index(typeid(float))] = "float"; + type_map->names[std::type_index(typeid(double))] = "double"; + type_map->names[std::type_index(typeid(std::vector))] = "std::vector"; + type_map->names[std::type_index(typeid(std::vector))] = "std::vector"; + type_map->names[std::type_index(typeid(std::vector))] = "std::vector"; + type_map->names[std::type_index(typeid(std::vector))] = "std::vector"; + + // Extract configuration from Phlex config + std::string output_file = config.get("output_file", "output.root"); + std::string tech_string = config.get("technology", "ROOT_TTREE"); + + std::cout << "Configuration:\n"; + std::cout << " output_file: " << output_file << "\n"; + std::cout << " technology: " << tech_string << "\n"; + + // Map Phlex config string to FORM technology constant + int technology = form::technology::ROOT_TTREE; // default + + if (tech_string == "ROOT_TTREE") { + technology = form::technology::ROOT_TTREE; + } else if (tech_string == "ROOT_RNTUPLE") { + technology = form::technology::ROOT_RNTUPLE; + } else if (tech_string == "HDF5") { + technology = form::technology::HDF5; + } else { + throw std::runtime_error("Unknown technology: " + tech_string); + } + + auto products_to_save = config.get>("products"); + + // Phlex needs an OBJECT + // Create the FORM output module + auto form_output = m.make(type_map, output_file, technology, products_to_save); + + // Phlex needs a MEMBER FUNCTION to call + // Register the callback that Phlex will invoke + form_output.output("save_data_products", &FormOutputModule::save_data_products); + + std::cout << "FORM output module registered successfully\n"; +} diff --git a/form/mock_phlex/CMakeLists.txt b/form/mock_phlex/CMakeLists.txt deleted file mode 100644 index 55e65c9bf..000000000 --- a/form/mock_phlex/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_library(mock_phlex phlex_toy_core.cpp phlex_toy_config.cpp) diff --git a/form/mock_phlex/phlex_toy_config.cpp b/form/mock_phlex/phlex_toy_config.cpp deleted file mode 100644 index 74cd8c909..000000000 --- a/form/mock_phlex/phlex_toy_config.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "phlex_toy_config.hpp" - -namespace mock_phlex::config { - - void parse_config::addItem(std::string const& product_name, - std::string const& file_name, - int technology) - { - m_items.emplace_back(product_name, file_name, technology); - } - - PersistenceItem const* parse_config::findItem(std::string const& product_name) const - { - for (auto const& item : m_items) { - if (item.product_name == product_name) { - return &item; - } - } - return nullptr; - } - - void parse_config::addFileSetting(int const tech, - std::string const& fileName, - std::string const& key, - std::string const& value) - { - m_file_settings[tech][fileName].emplace_back(key, value); - } - - void parse_config::addContainerSetting(int const tech, - std::string const& containerName, - std::string const& key, - std::string const& value) - { - m_container_settings[tech][containerName].emplace_back(key, value); - } - -} // namespace mock_phlex::config diff --git a/form/mock_phlex/phlex_toy_config.hpp b/form/mock_phlex/phlex_toy_config.hpp deleted file mode 100644 index 79ae5508f..000000000 --- a/form/mock_phlex/phlex_toy_config.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef __PARSE_CONFIG_HPP__ -#define __PARSE_CONFIG_HPP__ - -#include -#include -#include -#include -#include - -namespace mock_phlex::config { - - struct PersistenceItem { - std::string product_name; // e.g. "trackStart", "trackNumberHits" - std::string file_name; // e.g. "toy.root", "output.hdf5" - int technology; // Technology::ROOT_TTREE, Technology::ROOT_RNTUPLE, Technology::HDF5 - - PersistenceItem(std::string const& product, std::string const& file, int tech) : - product_name(product), file_name(file), technology(tech) - { - } - }; - - class parse_config { - public: - parse_config() = default; - ~parse_config() = default; - - // Add a configuration item - void addItem(std::string const& product_name, std::string const& file_name, int technology); - void addFileSetting(int const tech, - std::string const& fileName, - std::string const& key, - std::string const& value); - void addContainerSetting(int const tech, - std::string const& containerName, - std::string const& key, - std::string const& value); - - // Find configuration for a product+creator combination - PersistenceItem const* findItem(std::string const& product_name) const; - - // Get all items (for debugging/validation) - std::vector const& getItems() const { return m_items; } - auto const& getFileSettings() const { return m_file_settings; } - auto const& getContainerSettings() const { return m_container_settings; } - - private: - std::vector m_items; - - using table_t = std::vector>; - using map_t = std::map>; - map_t m_file_settings; - map_t m_container_settings; - }; - -} // namespace mock_phlex::config - -#endif diff --git a/form/mock_phlex/phlex_toy_core.cpp b/form/mock_phlex/phlex_toy_core.cpp deleted file mode 100644 index ec022d1e9..000000000 --- a/form/mock_phlex/phlex_toy_core.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (C) 2025 ... - -#include "phlex_toy_core.hpp" - -namespace mock_phlex { - std::shared_ptr createTypeMap() - { - return std::make_shared(); - } -} diff --git a/form/mock_phlex/phlex_toy_core.hpp b/form/mock_phlex/phlex_toy_core.hpp deleted file mode 100644 index 79e6cad66..000000000 --- a/form/mock_phlex/phlex_toy_core.hpp +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (C) 2025 ... - -#ifndef __PHLEX_TOY_CORE_HPP__ -#define __PHLEX_TOY_CORE_HPP__ - -#include -#include -#include -#include -#include - -namespace mock_phlex { - struct product_base { - std::string label; // Containing data product name only? - std::string id; - void const* data; - std::type_index type; - }; - struct product_type_names { - std::unordered_map - names; // Phlex has to provide product type name - }; - std::shared_ptr createTypeMap(); -}; - -#endif diff --git a/form/root_storage/root_ttree_container.cpp b/form/root_storage/root_ttree_container.cpp index 8c40ca05d..1300f1ce6 100644 --- a/form/root_storage/root_ttree_container.cpp +++ b/form/root_storage/root_ttree_container.cpp @@ -16,7 +16,13 @@ ROOT_TTree_ContainerImp::ROOT_TTree_ContainerImp(std::string const& name) : ROOT_TTree_ContainerImp::~ROOT_TTree_ContainerImp() { if (m_tree != nullptr) { - m_tree->Write(); + // Calling: + // m_tree->Write(); + // requires the TTree's directory to be the current directory, so we could do + // TDirectory::TContext ctxt(m_tree->GetDirectory()); + // m_tree->Write(); + // or let's just do: + m_tree->AutoSave("flushbaskets"); delete m_tree; } } @@ -47,6 +53,9 @@ void ROOT_TTree_ContainerImp::setupWrite(std::string const& /* type*/) if (m_tree == nullptr) { throw std::runtime_error("ROOT_TTree_ContainerImp::setupWrite no tree created"); } + if (m_tree->GetDirectory() == nullptr) { + throw std::runtime_error("ROOT_TTree_ContainerImp::setupWrite not attached to any file"); + } return; } diff --git a/test/form/CMakeLists.txt b/test/form/CMakeLists.txt index a8859d061..9f1ea9a30 100644 --- a/test/form/CMakeLists.txt +++ b/test/form/CMakeLists.txt @@ -2,14 +2,12 @@ if(FORM_USE_ROOT_STORAGE) add_subdirectory(data_products) - cet_test( WriteVector SOURCE writer.cpp toy_tracker.cpp LIBRARIES - mock_phlex form form_test_data_products TEST_ARGS @@ -22,7 +20,6 @@ if(FORM_USE_ROOT_STORAGE) SOURCE reader.cpp LIBRARIES - mock_phlex form form_test_data_products TEST_ARGS @@ -33,3 +30,16 @@ if(FORM_USE_ROOT_STORAGE) ) target_include_directories(ReadVector PRIVATE ${PROJECT_SOURCE_DIR}/form) endif() + +cet_test( + job:form_module + HANDBUILT + TEST_EXEC + phlex + TEST_ARGS + -c + ${CMAKE_CURRENT_SOURCE_DIR}/form_test.jsonnet + TEST_PROPERTIES + ENVIRONMENT + "PHLEX_PLUGIN_PATH=${PROJECT_BINARY_DIR}:${CMAKE_BINARY_DIR}/form" + ) diff --git a/test/form/form_test.jsonnet b/test/form/form_test.jsonnet new file mode 100644 index 000000000..a73d69267 --- /dev/null +++ b/test/form/form_test.jsonnet @@ -0,0 +1,17 @@ +{ + source: { + plugin: 'generate_layers', + layers: { + event: { total: 10 } + } + }, + modules: { + add: { + plugin: 'module', + }, + form_output: { + plugin: 'form_module', + products: ["sum"], + }, + }, +} \ No newline at end of file diff --git a/test/form/reader.cpp b/test/form/reader.cpp index e578741f2..aa30ceb26 100644 --- a/test/form/reader.cpp +++ b/test/form/reader.cpp @@ -3,10 +3,9 @@ #include "data_products/track_start.hpp" #include "form/form.hpp" #include "form/technology.hpp" -#include "mock_phlex/phlex_toy_config.hpp" -#include "mock_phlex/phlex_toy_core.hpp" // toy of phlex core components +#include "test_helpers.hpp" -#include // For cout +#include #include static int const NUMBER_EVENT = 4; @@ -21,52 +20,59 @@ int main(int argc, char** argv) std::string const filename = (argc > 1) ? argv[1] : "toy.root"; - std::shared_ptr type_map = mock_phlex::createTypeMap(); + std::shared_ptr type_map = + form::experimental::createTypeMap(); // TODO: Read configuration from config file instead of hardcoding - // Should be: phlex::config::parse_config config = phlex::config::loadFromFile("phlex_config.json"); - // Create configuration and pass to form - mock_phlex::config::parse_config config; - config.addItem("trackStart", filename, form::technology::ROOT_TTREE); - config.addItem("trackNumberHits", filename, form::technology::ROOT_TTREE); - config.addItem("trackStartPoints", filename, form::technology::ROOT_TTREE); - config.addItem("trackStartX", filename, form::technology::ROOT_TTREE); + form::experimental::config::output_item_config output_config; + output_config.addItem("trackStart", filename, form::technology::ROOT_TTREE); + output_config.addItem("trackNumberHits", filename, form::technology::ROOT_TTREE); + output_config.addItem("trackStartPoints", filename, form::technology::ROOT_TTREE); + output_config.addItem("trackStartX", filename, form::technology::ROOT_TTREE); - form::experimental::form_interface form(type_map, config); + form::experimental::config::tech_setting_config tech_config; + + form::experimental::form_interface form(type_map, output_config, tech_config); for (int nevent = 0; nevent < NUMBER_EVENT; nevent++) { std::cout << "PHLEX: Read Event No. " << nevent << std::endl; - // Processing per event / data creation std::vector const* track_x = nullptr; for (int nseg = 0; nseg < NUMBER_SEGMENT; nseg++) { - // phlex Alg per segment - // Processing per sub-event + std::vector const* track_start_x = nullptr; char seg_id_text[64]; snprintf(seg_id_text, 64, seg_id, nevent, nseg); + + std::string segment_id(seg_id_text); + std::string const creator = "Toy_Tracker"; - mock_phlex::product_base pb = { - "trackStart", seg_id_text, track_start_x, std::type_index{typeid(std::vector)}}; + + form::experimental::product_with_name pb = { + "trackStart", track_start_x, std::type_index{typeid(std::vector)}}; type_map->names[std::type_index(typeid(std::vector))] = "std::vector"; - form.read(creator, pb); + + form.read(creator, segment_id, pb); track_start_x = static_cast const*>(pb.data); //FIXME: Can this be done by FORM? + std::vector const* track_n_hits = nullptr; - mock_phlex::product_base pb_int = { - "trackNumberHits", seg_id_text, track_n_hits, std::type_index{typeid(std::vector)}}; + + form::experimental::product_with_name pb_int = { + "trackNumberHits", track_n_hits, std::type_index{typeid(std::vector)}}; type_map->names[std::type_index(typeid(std::vector))] = "std::vector"; - form.read(creator, pb_int); + + form.read(creator, segment_id, pb_int); track_n_hits = static_cast const*>(pb_int.data); std::vector const* start_points = nullptr; - mock_phlex::product_base pb_points = {"trackStartPoints", - seg_id_text, - start_points, - std::type_index{typeid(std::vector)}}; + + form::experimental::product_with_name pb_points = { + "trackStartPoints", start_points, std::type_index{typeid(std::vector)}}; type_map->names[std::type_index(typeid(std::vector))] = "std::vector"; - form.read(creator, pb_points); + + form.read(creator, segment_id, pb_points); start_points = static_cast const*>(pb_points.data); float check = 0.0; @@ -90,12 +96,18 @@ int main(int argc, char** argv) char evt_id_text[64]; snprintf(evt_id_text, 64, evt_id, nevent); + + std::string event_id(evt_id_text); + std::string const creator = "Toy_Tracker_Event"; - mock_phlex::product_base pb = { - "trackStartX", evt_id_text, track_x, std::type_index{typeid(std::vector)}}; + + form::experimental::product_with_name pb = { + "trackStartX", track_x, std::type_index{typeid(std::vector)}}; type_map->names[std::type_index(typeid(std::vector))] = "std::vector"; - form.read(creator, pb); + + form.read(creator, event_id, pb); track_x = static_cast const*>(pb.data); //FIXME: Can this be done by FORM? + float check = 0.0; for (float val : *track_x) check += val; diff --git a/test/form/test_helpers.hpp b/test/form/test_helpers.hpp new file mode 100644 index 000000000..c17ba03e4 --- /dev/null +++ b/test/form/test_helpers.hpp @@ -0,0 +1,39 @@ +#ifndef TEST_HELPERS_HPP +#define TEST_HELPERS_HPP + +#include "data_products/track_start.hpp" +#include "form/form.hpp" + +#include +#include +#include + +namespace form::experimental { + + // Helper to register a single type + template + void registerType(product_type_names& map, std::string const& name) + { + map.names[std::type_index(typeid(T))] = name; + } + + // Register vector types automatically + template + void registerVectorType(product_type_names& map, std::string const& base_name) + { + map.names[std::type_index(typeid(T))] = base_name; + map.names[std::type_index(typeid(std::vector))] = "std::vector<" + base_name + ">"; + } + + inline std::shared_ptr createTypeMap() + { + auto type_map = std::make_shared(); + registerVectorType(*type_map, "TrackStart"); + + // Register all your data product types here + // Easy to add more in the future: + return type_map; + } +} + +#endif diff --git a/test/form/writer.cpp b/test/form/writer.cpp index 167af426c..954dbbd9b 100644 --- a/test/form/writer.cpp +++ b/test/form/writer.cpp @@ -3,12 +3,11 @@ #include "data_products/track_start.hpp" #include "form/form.hpp" #include "form/technology.hpp" -#include "mock_phlex/phlex_toy_config.hpp" -#include "mock_phlex/phlex_toy_core.hpp" // toy of phlex core components +#include "test_helpers.hpp" #include "toy_tracker.hpp" -#include // For rand() and srand() -#include // For cout +#include +#include #include static int const NUMBER_EVENT = 4; @@ -37,52 +36,54 @@ int main(int argc, char** argv) std::string const filename = (argc > 1) ? argv[1] : "toy.root"; - std::shared_ptr type_map = mock_phlex::createTypeMap(); + std::shared_ptr type_map = + form::experimental::createTypeMap(); // TODO: Read configuration from config file instead of hardcoding - // Should be: phlex::config::parse_config config = phlex::config::loadFromFile("phlex_config.json"); - // Create configuration and pass to form - mock_phlex::config::parse_config config; - config.addItem("trackStart", filename, form::technology::ROOT_TTREE); - config.addItem("trackNumberHits", filename, form::technology::ROOT_TTREE); - config.addItem("trackStartPoints", filename, form::technology::ROOT_TTREE); - config.addItem("trackStartX", filename, form::technology::ROOT_TTREE); - config.addContainerSetting(form::technology::ROOT_TTREE, "trackStart", "auto_flush", "1"); - config.addFileSetting(form::technology::ROOT_TTREE, filename, "compression", "kZSTD"); - config.addContainerSetting( - form::technology::ROOT_RNTUPLE, "Toy_Tracker/trackStartPoints", "force_streamer_field", "true"); - - form::experimental::form_interface form(type_map, config); + form::experimental::config::output_item_config output_config; + output_config.addItem("trackStart", filename, form::technology::ROOT_TTREE); + output_config.addItem("trackNumberHits", filename, form::technology::ROOT_TTREE); + output_config.addItem("trackStartPoints", filename, form::technology::ROOT_TTREE); + output_config.addItem("trackStartX", filename, form::technology::ROOT_TTREE); + + form::experimental::config::tech_setting_config tech_config; + tech_config.container_settings[form::technology::ROOT_TTREE]["trackStart"].emplace_back( + "auto_flush", "1"); + tech_config.file_settings[form::technology::ROOT_TTREE]["toy.root"].emplace_back("compression", + "kZSTD"); + tech_config.container_settings[form::technology::ROOT_RNTUPLE]["Toy_Tracker/trackStartPoints"] + .emplace_back("force_streamer_field", "true"); + + form::experimental::form_interface form(type_map, output_config, tech_config); ToyTracker tracker(4 * 1024); for (int nevent = 0; nevent < NUMBER_EVENT; nevent++) { std::cout << "PHLEX: Write Event No. " << nevent << std::endl; - // Processing per event / data creation std::vector track_x; for (int nseg = 0; nseg < NUMBER_SEGMENT; nseg++) { - // phlex Alg per segment - // Processing per sub-event + std::vector track_start_x; generate(track_start_x, 4 * 1024 /* * 1024*/); // sub-event processing float check = 0.0; for (float val : track_start_x) check += val; - // done, phlex call write(mock_phlex::product_base) - // sub-event writing called by phlex char seg_id_text[64]; snprintf(seg_id_text, 64, seg_id, nevent, nseg); - std::vector batch; + + std::string segment_id(seg_id_text); + + std::vector products; std::string const creator = "Toy_Tracker"; - mock_phlex::product_base pb = { - "trackStart", seg_id_text, &track_start_x, std::type_index{typeid(std::vector)}}; + + form::experimental::product_with_name pb = { + "trackStart", &track_start_x, std::type_index{typeid(std::vector)}}; type_map->names[std::type_index(typeid(std::vector))] = "std::vector"; - batch.push_back(pb); + products.push_back(pb); - // Now write an int vector for the same event/data grain, and the same algorithm std::vector track_n_hits; for (int i = 0; i < 100; ++i) { track_n_hits.push_back(i); @@ -91,28 +92,26 @@ int main(int argc, char** argv) check += val; std::cout << "PHLEX: Segment = " << nseg << ": seg_id_text = " << seg_id_text << ", check = " << check << std::endl; - mock_phlex::product_base pb_int = { - "trackNumberHits", seg_id_text, &track_n_hits, std::type_index{typeid(std::vector)}}; + + form::experimental::product_with_name pb_int = { + "trackNumberHits", &track_n_hits, std::type_index{typeid(std::vector)}}; type_map->names[std::type_index(typeid(std::vector))] = "std::vector"; - batch.push_back(pb_int); + products.push_back(pb_int); - // Now write a vector of a user-defined class for the same event/data grain std::vector start_points = tracker(); TrackStart checkPoints; for (TrackStart const& point : start_points) checkPoints += point; std::cout << "PHLEX: Segment = " << nseg << ": seg_id_text = " << seg_id_text << ", checkPoints = " << checkPoints << std::endl; - mock_phlex::product_base pb_points = {"trackStartPoints", - seg_id_text, - &start_points, - std::type_index{typeid(std::vector)}}; + + form::experimental::product_with_name pb_points = { + "trackStartPoints", &start_points, std::type_index{typeid(std::vector)}}; type_map->names[std::type_index(typeid(std::vector))] = "std::vector"; - batch.push_back(pb_points); + products.push_back(pb_points); - form.write(creator, batch); // writes all data products for only this segment + form.write(creator, segment_id, products); - // Accumulate Data track_x.insert(track_x.end(), track_start_x.begin(), track_start_x.end()); } @@ -122,16 +121,20 @@ int main(int argc, char** argv) for (float val : track_x) check += val; - // event writing, current framework, will also write references char evt_id_text[64]; snprintf(evt_id_text, 64, evt_id, nevent); + + std::string event_id(evt_id_text); + std::string const creator = "Toy_Tracker_Event"; - mock_phlex::product_base pb = { - "trackStartX", evt_id_text, &track_x, std::type_index{typeid(std::vector)}}; + + form::experimental::product_with_name pb = { + "trackStartX", &track_x, std::type_index{typeid(std::vector)}}; type_map->names[std::type_index(typeid(std::vector))] = "std::vector"; std::cout << "PHLEX: Event = " << nevent << ": evt_id_text = " << evt_id_text << ", check = " << check << std::endl; - form.write(creator, pb); + + form.write(creator, event_id, pb); std::cout << "PHLEX: Write Event done " << nevent << std::endl; }