/// <summary> /// Return all trees that are in a given directory. Make sure that if we have multiple /// cycles in the directory we only process the first one we encounter. /// </summary> /// <param name="dir"></param> /// <returns></returns> public IEnumerable<ROOTClassShell> ParseTDirectory(ROOTNET.Interface.NTDirectory dir) { var converter = new ParseTTree(); converter.ProxyGenerationLocation = ProxyGenerationLocation; HashSet<string> seenTreeNames = new HashSet<string>(); foreach (var key in dir.ListOfKeys.Cast<ROOTNET.Interface.NTKey>()) { var c = ROOTNET.NTClass.GetClass(key.GetClassName()); if (c != null) { if (c.InheritsFrom("TTree")) { if (!seenTreeNames.Contains(key.Name)) { seenTreeNames.Add(key.Name); var t = key.ReadObj() as ROOTNET.Interface.NTTree; if (t != null) { foreach (var cshell in converter.GenerateClasses(t)) { yield return cshell; } } } } } } }
/// <summary> /// Normalize the naming of an object. We don't really care about the names for a hash... so... /// </summary> /// <param name="namedObj"></param> private void InternalAccumulateNamedHash(ROOTNET.Interface.NTNamed namedObj) { string oName = namedObj.Name; string oTitle = namedObj.Title; namedObj.Name = "name_" + _namedObjectCount.ToString(); namedObj.Title = "title_" + _namedObjectCount.ToString(); InternalAccumulateHash(namedObj); namedObj.Name = oName; namedObj.Title = oTitle; }
/// <summary> /// Dip into and return the buffer data. Avoids a memory allocation. /// </summary> /// <param name="buffer"></param> /// <returns></returns> private static IEnumerable<SByte> BufferAsBytes(ROOTNET.Interface.NTBuffer buffer) { int l = buffer.Length(); var bufferData = buffer.Buffer(); for (int i = 0; i < l; i++) { // Access the byte, but make sure to bomb with a clear error message if something // funny happens (we've seen real problems in the field). SByte r; try { r = bufferData[i]; } catch (Exception e) { throw new InvalidOperationException($"Fatal error accessing the {i} element of an array that is {l} long.", e); } yield return r; } }
/// <summary> /// Given a branch that is a template, parse it and add to the class hierarchy. /// </summary> /// <param name="branch"></param> /// <returns></returns> private IEnumerable<ROOTClassShell> ExtractROOTTemplateClass(ROOTClassShell container, ROOTNET.Interface.NTBranch branch) { return ExtractROOTTemplateClass(container, branch.Name, branch.GetClassName()); }
public ImplicitTestForTheObjectInterface(ROOTNET.Interface.NTString obj) { _s = obj; }
public static double TMVASelectorSimpleCutsTest (ROOTNET.NTMVA.NReader reader, double a1, double a2, double aux) { throw new NotImplementedException("THis should never get called!"); }
/// <summary> /// Reformat the name. /// </summary> /// <param name="h"></param> /// <param name="format">string.Format argument, arg {0} will be the old histogram name</param> /// <returns></returns> private static ROOTNET.Interface.NTH1 AppendName(ROOTNET.Interface.NTH1 h, string format) { h.Name = string.Format(format, h.Name); return h; }
/// <summary> /// Create the classes for dealing with a simple leaf. There a bunch of different things that /// could be stored in here: /// 1) Simple itmes like "int" or "float" /// 2) Arrays, like int[10], int[nTracks] /// 3) vector[int], TLorentzVector (unsplit) - objects that ROOT both knows about and also /// are not split. /// 4) unsplit, unknown objects whose structure is defined by a Streamer. /// /// Sorting out which situation is non-trival, unfortunate. /// 1) There is the item type (leaf.TypeName). This could be "int" or "vector-blah-blah" /// 2) In the title there may be a "[stuff]" whihc means if it was "int" it becomes "int[]". :-) /// This is for dealing with a c-style array. /// </summary> /// <param name="leaf"></param> /// <returns></returns> private IClassItem ExtractUnsplitKnownClass(ROOTNET.Interface.NTLeaf leaf) { return ExtractSimpleItem(new SimpleLeafInfo(leaf)); }
public SimpleLeafInfo(ROOTNET.Interface.NTLeaf leaf) { Name = leaf.Name; Title = leaf.Title; TypeName = leaf.TypeName; }
/// <summary> /// A class has been defined only in the local tree. We need to parse through it and extract /// enough into to build a class on our own so that it can be correctly referenced in LINQ. /// </summary> /// <param name="container"></param> /// <param name="branch"></param> /// <param name="cls"></param> /// <returns></returns> private IEnumerable<ROOTClassShell> BuildMetadataForTTreeClassFromBranches(ROOTClassShell container, ROOTNET.Interface.NTBranch branch, ROOTNET.Interface.NTClass cls) { // // Get a unique classname. Attempt to do "the right thing". In particular, if this is a clones array of some // struct, it is not a "named" class, so use the name of the clones array instead. // string className = cls.Name; bool mightBeClonesArray = false; if (branch is ROOTNET.Interface.NTBranchElement) { var cn = (branch as ROOTNET.Interface.NTBranchElement).ClonesName.SanitizedName(); if (!string.IsNullOrWhiteSpace(cn)) { className = cn; mightBeClonesArray = true; } } if (_classNameCounter.ContainsKey(className)) { _classNameCounter[className] += 1; className = string.Format("{0}_{1}", className, _classNameCounter[className]); } else { _classNameCounter[className] = 0; } // // We will define the class, and it will be exactly what is given to use by the // tree. // var varName = branch.Name.SanitizedName(); container.Add(new ItemSimpleType(varName, className) { NotAPointer = true }); // // We are going to build our own class type here. // var treeClass = new ROOTClassShell(className) { IsTopLevelClass = false }; // // Now, loop over the branches and add them in, returning any classes we had to generate. // foreach (var c in ExtractClassesFromBranchList(treeClass, branch.ListOfBranches.Cast<ROOTNET.Interface.NTBranch>())) { yield return c; } // // The arrays in a tclones arrays are funny. The proxy generated parses them as seperate arrays, but their length is // basically the size of the tclonesarray. So we have to use that as the length. This is implied be cause we've marked // this class as a tclones array class already (above - the IsTTreeSubClass). So for the index we mark it as an index, // but we just marked the bound as "implied" - this will be picked up by the code when it is generated later on. // if (mightBeClonesArray) { var cBoundName = string.Format("{0}_", varName); var cstyleArrayIndicies = from item in treeClass.Items where item is ItemCStyleArray let citem = item as ItemCStyleArray from index in citem.Indicies where !index.indexConst && index.indexBoundName == cBoundName select index; bool foundTClonesArray = false; foreach (var item in cstyleArrayIndicies) { item.indexBoundName = "implied"; foundTClonesArray = true; } treeClass.IsTClonesArrayClass = foundTClonesArray; } // // If this is a tclones array - and it is a real array, then we don't want to de-reference anything. // if (treeClass.IsTClonesArrayClass) { foreach (var item in treeClass.Items) { item.NotAPointer = true; } } // // Finally, the one we just built! // yield return treeClass; }
/// <summary> /// There is a plain class that needs to be extracted. We usually end up here becuase it is a split class of /// some sort. For now, we will assume it is a real root class. /// </summary> /// <param name="branch"></param> /// <returns></returns> private IEnumerable<ROOTClassShell> ExtractROOTPlainClass(ROOTClassShell container, ROOTNET.Interface.NTBranch branch) { // // Double chekc that this is a root class. Since we are looking at the Tree, ROOT's system would certianly have declared it // internally. If we can't find the cls info, then we are in trouble. // var cls = ROOTNET.NTClass.GetClass(branch.GetClassName()); if (cls == null) { throw new NotImplementedException("The class '" + branch.GetClassName() + "' is not known to ROOT's type systems - and I can't proceed unless it is"); } if (cls.Name == "string") { throw new NotImplementedException("The class 'string' is not translated yet!"); } // // There are several ways this class can be encoded in the file. They broadly break down // into two classes: // // 1) A class that is fully defined by ROOT. TLorentzVector would be such a thing. // Custom classes that ROOT has a full dictionary for are equivalent and that // we have a good wrapper for. // 2) A class that is only defined by the contents of the ROOT file. This could be // as a series of leaves in the TTree (this would be the case of a split class) // or in the streamer, which is a non-split class' case. // // // If it has some public data members, then it is a real ROOT class, and whatever was done to define it and make it known // to ROOT here we assume will also be done when the full blown LINQ interface is run (i.e. some loaded C++ files). // if (!cls.IsShellTClass()) { container.Add(new ItemROOTClass(branch.Name, branch.GetClassName())); return Enumerable.Empty<ROOTClassShell>(); } // // If we are here, then we are dealing with a locally defined class. One that ROOT made up on the fly. In short, not one // that we are going to have a translation for. So, we have to build the meta data for it. This // meta data can come from the tree branch list or from the streamer. // return BuildMetadataForTTreeClassFromBranches(container, branch, cls); }
/// <summary> /// Extract a class from a "good" streamer. /// </summary> /// <param name="cls"></param> /// <param name="streamer"></param> /// <returns></returns> private IEnumerable<ROOTClassShell> ExtractClassFromStreamer(ROOTClassShell container, string itemName, ROOTNET.Interface.NTClass cls, ROOTNET.Interface.NTVirtualStreamerInfo sInfo) { // This guy is a class with elements, so go get the elements... var c = new ROOTClassShell(cls.Name.SanitizedName()) { IsTopLevelClass = false }; if (container != null) container.Add(new ItemROOTClass() { Name = itemName, ItemType = cls.Name.SanitizedName(), NotAPointer = false }); var clist = new List<ROOTClassShell>(); clist.Add(c); foreach (var item in sInfo.Elements.Cast<ROOTNET.Interface.NTStreamerElement>()) { if (item == null) throw new ArgumentNullException("Streamer element was null"); if (item.TypeName == "BASE") { SimpleLogging.Log(string.Format("Item '{0}' has a subclass of type '{1}' - we can't parse inherritance yet", itemName, item.FullName)); continue; } var itemCls = item.ClassPointer; if (itemCls == null) { // This is going to be something like "int", or totally unknown! c.Add(ExtractSimpleItem(new SimpleLeafInfo() { Name = item.FullName, TypeName = item.TypeName, Title = item.FullName })); } else if (!itemCls.IsShellTClass()) { try { // We know about this class, and can use ROOT infrasturcutre to do the parsing for it. // Protect against funny template arguments we can't deal with now - just skip them. var itemC = ExtractSimpleItem(new SimpleLeafInfo() { Name = item.FullName, TypeName = itemCls.Name, Title = item.FullName }); c.Add(itemC); } catch (Exception e) { SimpleLogging.Log(string.Format("Unable to deal with streamer type '{0}', skiping member '{1}': {2}", itemCls.Name, item.FullName, e.Message)); } } else { // Unknown to ROOT class. How we handle this, exactly, depends if it is a template class or if it is // a raw class. if (itemCls.IsTemplateClass()) { var newClassDefs = ExtractROOTTemplateClass(c, item.FullName, itemCls.Name); clist.AddRange(newClassDefs); } else { var newClassDefs = new List<ROOTClassShell>(ExtractUnsplitUnknownClass(c, item.FullName, itemCls)); clist.AddRange(newClassDefs); } } } return clist; }
/// <summary> /// Extract info for a sub-class from a branch! The last one is the top level class we are currently parsing! /// </summary> /// <param name="branch"></param> /// <returns></returns> private IEnumerable<ROOTClassShell> ExtractClass(ROOTClassShell container, ROOTNET.Interface.NTBranch branch) { /// /// First, figure out what kind of class this is. For example, might it be a stl vector? If so, /// then we need to parse that up! /// if (branch.GetClassName().Contains("<")) { return ExtractROOTTemplateClass(container, branch); } else { return ExtractROOTPlainClass(container, branch); } }
/// <summary> /// Extract the unsplit unknown class by parsing the streamer. /// </summary> /// <param name="cls"></param> /// <returns></returns> private IEnumerable<ROOTClassShell> ExtractUnsplitUnknownClass(ROOTNET.Interface.NTClass cls) { return ExtractUnsplitUnknownClass(null, null, cls); }
/// <summary> /// The class has no def in a TClass. It has no def in the way the branches and leaves are layed out. So, /// we, really, have only one option here. Parse the streamer! /// </summary> /// <param name="leaf"></param> /// <returns></returns> private IEnumerable<ROOTClassShell> ExtractUnsplitUnknownClass(ROOTClassShell container, string itemName, ROOTNET.Interface.NTClass cls) { // Make sure that we are ok here. var streamer = cls.StreamerInfo; if (streamer == null) return Enumerable.Empty<ROOTClassShell>(); return ExtractClassFromStreamer(container, itemName, cls, streamer); }
/// <summary> /// Look at everything we have in this tree and see if we can't generate a class correctly. /// </summary> /// <param name="tree"></param> /// <returns></returns> public IEnumerable<ROOTClassShell> GenerateClasses(ROOTNET.Interface.NTTree tree) { if (tree == null) throw new ArgumentNullException("tree must not be null"); /// /// The outlying class is going to be called by the name of the tree. /// var masterClass = new ROOTClassShell(tree.Name); var subClassesByName = from sc in ExtractClassesFromBranchList(masterClass, tree.ListOfBranches.Cast<ROOTNET.Interface.NTBranch>()) group sc by sc.Name; var subClasses = from scg in subClassesByName where scg.ClassesAreIdnetical() select scg.First(); foreach (var sc in subClasses) { yield return sc; } /// /// Last thing we need to do is create a proxy for the class. /// FileInfo f = MakeProxy(tree); masterClass.NtupleProxyPath = f.FullName; /// /// Work around a ROOT bug that doesn't allow for unloading of classes /// in the STL after a query is run. Actually, it will unload them, but somehow keeps /// references in memory. /// masterClass.ClassesToGenerate = ExtractSTLDictionaryReferences(f); /// /// Analyze the TTree arrays. /// var at = new ArrayAnalyzer(); var groupInfo = at.AnalyzeTTree(masterClass, tree, 100); /// /// Any item that isn't an array should be added to the list and /// put in the "ungrouped" array. /// AddNonArrays(masterClass, groupInfo, "ungrouped"); /// /// Write out the user info /// masterClass.UserInfoPath = WriteUserInfo(groupInfo, tree.SanitizedName()).FullName; /// /// Return the master class /// yield return masterClass; }
/// <summary> /// Generate a proxy for the tree. This involves making the proxy and then putting in the proper /// text substitutions for later processing by our framework. Some ugly text hacking! /// </summary> /// <param name="tree"></param> /// <returns></returns> private FileInfo MakeProxy(ROOTNET.Interface.NTTree tree) { /// /// First create the proxy. We have to create a darn temp macro name for that. /// var oldDir = Environment.CurrentDirectory; var createItDir = new DirectoryInfo(Environment.CurrentDirectory); if (ProxyGenerationLocation != null) createItDir = ProxyGenerationLocation; FileInfo macroFile = new FileInfo(createItDir + @"\junk_macro_parsettree_" + tree.SanitizedName() + ".C"); FileInfo result = null; try { /// /// We can only use local directories /// if (ProxyGenerationLocation != null) Environment.CurrentDirectory = ProxyGenerationLocation.FullName; using (var writer = macroFile.CreateText()) { writer.WriteLine("void {0} () {{}}", Path.GetFileNameWithoutExtension(macroFile.Name)); writer.Close(); } result = new FileInfo("ntuple_" + tree.SanitizedName() + ".h"); tree.MakeProxy(Path.GetFileNameWithoutExtension(result.Name), macroFile.Name, null, "nohist"); } finally { /// /// Go back to where we were /// Environment.CurrentDirectory = oldDir; } /// /// Next, add the proper things and remove some stuff /// /// /// Return the location of the cpp file /// return result; }
/// <summary> /// Do the accumulation for a root object. /// </summary> /// <param name="nTObject"></param> private void InternalAccumulateHash(ROOTNET.Interface.NTObject nTObject) { if (nTObject == null) throw new ArgumentNullException("The argument to InternalAccumulateHash was null - not allowed."); // Write it to a ROOT buffer var buffer = new ROOTNET.NTBufferFile(ROOTNET.Interface.NTBuffer.EMode.kWrite); buffer.WriteObject(nTObject); //var result = buffer.Buffer().as_array(buffer.Length()); var result = BufferAsBytes(buffer); // And update the hash value we are holding onto. ComputeHash(result); }