@@ -892,3 +892,101 @@ ROOT::Internal::RDF::UntypedSnapshotTTreeHelperMT::MakeNew(void *newName, std::s
892892 fInputLoopManager ,
893893 fInputColumnTypeIDs };
894894}
895+
896+ ROOT::Internal::RDF::UntypedSnapshotRNTupleHelper::UntypedSnapshotRNTupleHelper (
897+ std::string_view filename, std::string_view dirname, std::string_view ntuplename, const ColumnNames_t &vfnames,
898+ const ColumnNames_t &fnames, const RSnapshotOptions &options, ROOT::Detail::RDF::RLoopManager *inputLM,
899+ ROOT::Detail::RDF::RLoopManager *outputLM, std::vector<bool > &&isDefine,
900+ const std::vector<const std::type_info *> &colTypeIDs)
901+ : fFileName (filename),
902+ fDirName (dirname),
903+ fNTupleName(ntuplename),
904+ fOptions(options),
905+ fInputLoopManager(inputLM),
906+ fOutputLoopManager(outputLM),
907+ fInputFieldNames(vfnames),
908+ fOutputFieldNames(ReplaceDotWithUnderscore(fnames)),
909+ fIsDefine(std::move(isDefine)),
910+ fInputColumnTypeIDs(colTypeIDs)
911+ {
912+ EnsureValidSnapshotRNTupleOutput (fOptions , fNTupleName , fFileName );
913+ }
914+
915+ ROOT::Internal::RDF::UntypedSnapshotRNTupleHelper::~UntypedSnapshotRNTupleHelper ()
916+ {
917+ if (!fNTupleName .empty () && !fOutputLoopManager ->GetDataSource () && fOptions .fLazy )
918+ Warning (" Snapshot" , " A lazy Snapshot action was booked but never triggered." );
919+ }
920+
921+ void ROOT::Internal::RDF::UntypedSnapshotRNTupleHelper::Exec (unsigned int /* slot */ , const std::vector<void *> &values)
922+ {
923+ assert (values.size () == fOutputFieldNames .size ());
924+ for (decltype (values.size ()) i = 0 ; i < values.size (); i++) {
925+ fOutputEntry ->BindRawPtr (fOutputFieldNames [i], values[i]);
926+ }
927+ fWriter ->Fill ();
928+ }
929+
930+ void ROOT::Internal::RDF::UntypedSnapshotRNTupleHelper::Initialize ()
931+ {
932+ auto model = ROOT::RNTupleModel::Create ();
933+ auto nFields = fOutputFieldNames .size ();
934+ for (decltype (nFields) i = 0 ; i < nFields; i++) {
935+ // Need to retrieve the type of every field to create as a string
936+ // If the input type for a field does not have RTTI, internally we store it as the tag UseNativeDataType. When
937+ // that is detected, we need to ask the data source which is the type name based on the on-disk information.
938+ const auto typeName = *fInputColumnTypeIDs [i] == typeid (ROOT::Internal::RDF::UseNativeDataType)
939+ ? ROOT::Internal::RDF::GetTypeNameWithOpts (*fInputLoopManager ->GetDataSource (),
940+ fInputFieldNames [i], fOptions .fVector2RVec )
941+ : ROOT::Internal::RDF::TypeID2TypeName (*fInputColumnTypeIDs [i]);
942+ model->AddField (ROOT::RFieldBase::Create (fOutputFieldNames [i], typeName).Unwrap ());
943+ }
944+ fOutputEntry = &model->GetDefaultEntry ();
945+
946+ ROOT::RNTupleWriteOptions writeOptions;
947+ writeOptions.SetCompression (fOptions .fCompressionAlgorithm , fOptions .fCompressionLevel );
948+
949+ fOutputFile .reset (TFile::Open (fFileName .c_str (), fOptions .fMode .c_str ()));
950+ if (!fOutputFile )
951+ throw std::runtime_error (" Snapshot: could not create output file " + fFileName );
952+
953+ TDirectory *outputDir = fOutputFile .get ();
954+ if (!fDirName .empty ()) {
955+ TString checkupdate = fOptions .fMode ;
956+ checkupdate.ToLower ();
957+ if (checkupdate == " update" )
958+ outputDir = fOutputFile ->mkdir (fDirName .c_str (), " " , true ); // do not overwrite existing directory
959+ else
960+ outputDir = fOutputFile ->mkdir (fDirName .c_str ());
961+ }
962+
963+ fWriter = ROOT::RNTupleWriter::Append (std::move (model), fNTupleName , *outputDir, writeOptions);
964+ }
965+
966+ void ROOT::Internal::RDF::UntypedSnapshotRNTupleHelper::Finalize ()
967+ {
968+ fWriter .reset ();
969+ // We can now set the data source of the loop manager for the RDataFrame that is returned by the Snapshot call.
970+ fOutputLoopManager ->SetDataSource (std::make_unique<ROOT::RDF::RNTupleDS>(fDirName + " /" + fNTupleName , fFileName ));
971+ }
972+
973+ /* *
974+ * Create a new UntypedSnapshotRNTupleHelper with a different output file name.
975+ *
976+ * \param[in] newName A type-erased string with the output file name
977+ * \return UntypedSnapshotRNTupleHelper
978+ *
979+ * This MakeNew implementation is tied to the cloning feature of actions
980+ * of the computation graph. In particular, cloning a Snapshot node usually
981+ * also involves changing the name of the output file, otherwise the cloned
982+ * Snapshot would overwrite the same file.
983+ */
984+ ROOT::Internal::RDF::UntypedSnapshotRNTupleHelper
985+ ROOT::Internal::RDF::UntypedSnapshotRNTupleHelper::MakeNew (void *newName)
986+ {
987+ const std::string finalName = *reinterpret_cast <const std::string *>(newName);
988+ return UntypedSnapshotRNTupleHelper{finalName, fDirName , fNTupleName ,
989+ fInputFieldNames , fOutputFieldNames , fOptions ,
990+ fInputLoopManager , fOutputLoopManager , std::vector<bool >(fIsDefine ),
991+ fInputColumnTypeIDs };
992+ }
0 commit comments