2828#include < CCDB/BasicCCDBManager.h>
2929#include " DataFormatsParameters/GRPLHCIFData.h"
3030#include " SimConfig/SimConfig.h"
31+ #include < filesystem>
3132
3233//
3334// Created by Sandro Wenzel on 13.07.21.
@@ -59,6 +60,10 @@ struct Options {
5960 // format is path prefix
6061 std::string vertexModeString{" kNoVertex" }; // Vertex Mode; vertices will be assigned to collisions of mode != kNoVertex
6162 o2::conf::VertexMode vertexMode = o2::conf::VertexMode::kNoVertex ;
63+ std::string external_path = " " ; // optional external path where we can directly take the collision contexts
64+ // This is useful when someone else is creating the contexts (MC-data embedding) and we
65+ // merely want to pass these through. If this is given, we simply take the timeframe ID, number of orbits
66+ // and copy the right amount of timeframes into the destination folder (implies individualTFextraction)
6267};
6368
6469enum class InteractionLockMode {
@@ -210,7 +215,9 @@ bool parseOptions(int argc, char* argv[], Options& optvalues)
210215 " with-vertices" , bpo::value<std::string>(&optvalues.vertexModeString )->default_value (" kNoVertex" ), " Assign vertices to collisions. Argument is the vertex mode. Defaults to no vertexing applied" )(
211216 " timestamp" , bpo::value<long >(&optvalues.timestamp )->default_value (-1L ), " Timestamp for CCDB queries / anchoring" )(
212217 " extract-per-timeframe" , bpo::value<std::string>(&optvalues.individualTFextraction )->default_value (" " ),
213- " Extract individual timeframe contexts. Format required: time_frame_prefix[:comma_separated_list_of_signals_to_offset]" );
218+ " Extract individual timeframe contexts. Format required: time_frame_prefix[:comma_separated_list_of_signals_to_offset]" )(
219+ " import-external" , bpo::value<std::string>(&optvalues.external_path )->default_value (" " ),
220+ " Take collision contexts (per timeframe) from external files for instance for data-anchoring use-case. Needs timeframeID and number of orbits to be given as well." );
214221
215222 options.add_options ()(" help,h" , " Produce help message." );
216223
@@ -249,6 +256,47 @@ bool parseOptions(int argc, char* argv[], Options& optvalues)
249256 return true ;
250257}
251258
259+ bool copy_collision_context (const std::string& external_path, int this_tf_id, int target_tf_id)
260+ {
261+ namespace fs = std::filesystem;
262+ try {
263+ // Construct source file path
264+ fs::path filename = fs::path (external_path) / (" collission_context_" + std::to_string (this_tf_id) + " .root" );
265+
266+ LOG (info) << " Checking existence of file: " << filename;
267+
268+ if (fs::exists (filename)) {
269+ // Build destination path
270+ std::string path_prefix = " tf" ; // Can be made configurable
271+ std::stringstream destination_path_stream;
272+ destination_path_stream << path_prefix << (target_tf_id) << " /collisioncontext.root" ;
273+ fs::path destination_path = destination_path_stream.str ();
274+
275+ // Ensure parent directory exists
276+ fs::path destination_dir = destination_path.parent_path ();
277+ if (!fs::exists (destination_dir)) {
278+ fs::create_directories (destination_dir);
279+ LOG (info) << " Created directory: " << destination_dir;
280+ }
281+
282+ // Copy file
283+ fs::copy_file (filename, destination_path, fs::copy_options::overwrite_existing);
284+ LOG (info) << " Copied file to: " << destination_path;
285+ return true ;
286+ } else {
287+ LOG (warning) << " Source file does not exist: " << filename;
288+ return false ;
289+ }
290+ } catch (const fs::filesystem_error& e) {
291+ LOG (error) << " Filesystem error: " << e.what ();
292+ return false ;
293+ } catch (const std::exception& e) {
294+ LOG (error) << " Unexpected error: " << e.what ();
295+ return false ;
296+ }
297+ return true ;
298+ }
299+
252300int main (int argc, char * argv[])
253301{
254302 Options options;
@@ -259,6 +307,45 @@ int main(int argc, char* argv[])
259307 // init params
260308 o2::conf::ConfigurableParam::updateFromString (options.configKeyValues );
261309
310+ // See if this is external mode, which simplifies things
311+ if (options.external_path .size () > 0 ) {
312+ // in this mode, we don't actually have to do much work.
313+ // all we do is to
314+ // - determine how many timeframes are asked
315+ // - check if the right files are present in the external path (someone else needs to create/put them there)
316+ // - check if the given contexts are consistent with options given (orbitsPerTF, ...)
317+ // - copy the files into the MC destination folder (this implies timeframeextraction mode)
318+ // - return
319+
320+ if (options.orbits < 0 ) {
321+ LOG (error) << " External mode; orbits need to be given" ;
322+ return 1 ;
323+ }
324+
325+ if (options.orbitsPerTF == 0 ) {
326+ LOG (error) << " External mode; need to have orbitsPerTF" ;
327+ return 1 ;
328+ }
329+
330+ if (options.individualTFextraction .size () == 0 ) {
331+ LOG (error) << " External mode: This requires --extract-per-timeframe" ;
332+ return 1 ;
333+ }
334+
335+ // calculate number of timeframes
336+ auto num_timeframes = options.orbits / options.orbitsPerTF ;
337+ LOG (info) << " External mode for " << num_timeframes << " consecutive timeframes; starting from " << options.tfid ;
338+
339+ // loop over all timeframe ids - check if file is present - (check consistency) - copy to final destination
340+ for (int i = 0 ; i < num_timeframes; ++i) {
341+ auto this_tf_id = options.tfid + i;
342+ if (!copy_collision_context (options.external_path , this_tf_id, i + 1 )) {
343+ return 1 ;
344+ }
345+ }
346+ return 0 ;
347+ }
348+
262349 // init random generator
263350 gRandom ->SetSeed (options.seed );
264351
0 commit comments