Skip to content

Commit 68707cb

Browse files
committed
ability to take inject external vertices in collision context
an important step for the mc-on-data embedding
1 parent 5a2ecfc commit 68707cb

File tree

3 files changed

+105
-1
lines changed

3 files changed

+105
-1
lines changed

DataFormats/simulation/include/SimulationDataFormat/DigitizationContext.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,12 @@ class DigitizationContext
141141
// have to have same vertex, as well as event ids associated to same collision.
142142
void sampleInteractionVertices(o2::dataformats::MeanVertexObject const& v);
143143

144+
// Function allowing to inject interaction vertixes from the outside.
145+
// Useful when this is given from data for instance. The vertex vector needs to be of same
146+
// size as the interaction record.
147+
// Returns 0 if success. 1 if there is a problem.
148+
int setInteractionVertices(std::vector<math_utils::Point3D<float>> const& vertices);
149+
144150
// helper functions to save and load a context
145151
void saveToFile(std::string_view filename) const;
146152

DataFormats/simulation/src/DigitizationContext.cxx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,17 @@ struct pair_hash {
622622
};
623623
} // namespace
624624

625+
int DigitizationContext::setInteractionVertices(std::vector<math_utils::Point3D<float>> const& external_vertices)
626+
{
627+
if (external_vertices.size() != mEventRecords.size()) {
628+
LOG(error) << "Size mismatch with event record";
629+
return 1;
630+
}
631+
mInteractionVertices.clear();
632+
std::copy(external_vertices.begin(), external_vertices.end(), std::back_inserter(mInteractionVertices));
633+
return 0;
634+
}
635+
625636
void DigitizationContext::sampleInteractionVertices(o2::dataformats::MeanVertexObject const& meanv)
626637
{
627638
// mapping of source x event --> index into mInteractionVertices

Steer/src/CollisionContextTool.cxx

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
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

6469
enum 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+
252300
int 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

Comments
 (0)