Exemple #1
0
        /// <summary>
        /// Convert everything and save it to the directory! Also write out
        /// all the sub-directories.
        /// </summary>
        /// <param name="calculateEverything">If true, then trigger all calculations here and below. Normally call with false.</param>
        public void Write(bool calculateEverything = true)
        {
            // Write everything associated with this directory.
            using (ROOTLock.Lock())
            {
                Directory.Write();
            }

            // Trigger all the calculatiosn that are needed for these directories.
            // This drives the ability for parallel calculation of everything.
            if (calculateEverything)
            {
                TriggerResolutions().Wait();
            }

            // Local values
            foreach (var item in _heldValues)
            {
                item.Save(Directory);
            }
            _heldValues.Clear();

            // Next, the subdirectories
            if (_subDirs.IsValueCreated)
            {
                foreach (var item in _subDirs.Value)
                {
                    item.Write();
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Called after running to load the results.
        /// </summary>
        /// <returns></returns>
        private async Task <IDictionary <string, NTObject> > LoadSelectorResults(FileInfo queryResultsFile)
        {
            using (var holder = await ROOTLock.LockAsync())
            {
                if (!queryResultsFile.Exists)
                {
                    throw new FileNotFoundException($"Unable to find the file {queryResultsFile.FullName} - it should contain the results of the query.");
                }

                // Read the data from the file.
                var results = new Dictionary <string, ROOTNET.Interface.NTObject>();
                var f       = ROOTNET.NTFile.Open(queryResultsFile.FullName);
                try
                {
                    var list = f.Get("output") as NTList;
                    foreach (var o in list)
                    {
                        results[o.Name] = o;
                    }
                }
                finally
                {
                    f.Close();
                }

                return(results);
            }
        }
Exemple #3
0
        /// <summary>
        /// Create a TH1F plot from a stream of objects (with a lambda function to give flexability in conversion).
        /// </summary>
        /// <typeparam name="TSource">The type of the sequence that the plot will be run over</typeparam>
        /// <param name="source">The sequence over which a plot should be made. There will be one entry per item in the sequence.</param>
        /// <param name="plotName">The histogram will be created with this name</param>
        /// <param name="plotTitle">The histogram will be created with this title</param>
        /// <param name="nbins">Number of bins this histogram should have</param>
        /// <param name="lowBin">The xmin value for this histogram</param>
        /// <param name="highBin">The xmax value for this histogram</param>
        /// <param name="xValue">A lambda that returns the xvalue for each sequence item.</param>
        /// <param name="weight">A lambda that returns the weight for each sequence item. By default every entry has a weight of 1.</param>
        /// <returns></returns>
        public static ROOTNET.NTH1F Plot <TSource>
        (
            this IQueryable <TSource> source,
            string plotName, string plotTitle,
            int nbins, double lowBin, double highBin,
            Expression <Func <TSource, double> > xValue,
            Expression <Func <TSource, double> > weight = null)
        {
            using (ROOTLock.Lock())
            {
                if (weight == null)
                {
                    Expression <Func <TSource, double> > constWeight = s => 1.0;
                    weight = constWeight;
                }

                var hParameter = Expression.Parameter(typeof(ROOTNET.NTH1F), "h");
                var vParameter = Expression.Parameter(typeof(TSource), "v");

                // h.Fill(getter(v), weight(v)) is what we want to code up

                var callGetter = Expression.Invoke(xValue, vParameter);
                var callWeight = Expression.Invoke(weight, vParameter);

                var fillMethod = typeof(ROOTNET.NTH1F).GetMethod("Fill", new[] { typeof(double), typeof(double) });
                var callFill   = Expression.Call(hParameter, fillMethod, callGetter, callWeight);

                var lambda = Expression.Lambda <Action <ROOTNET.NTH1F, TSource> >(callFill, hParameter, vParameter);
                var h      = new ROOTNET.NTH1F(plotName, plotTitle.ReplaceLatexStrings(), nbins, lowBin, highBin);
                ConfigureHisto(h);
                return(source.ApplyToObject(h, lambda));
            }
        }
 async Task GenerateValue()
 {
     using (await ROOTLock.LockAsync())
     {
         _histo = new ROOTNET.NTH1F("hi", "there", 10, 0.0, 100.0);
         _histo.Fill(5.0);
     }
 }
Exemple #5
0
        /// <summary>
        /// A clone of an int is an int.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="o"></param>
        /// <returns></returns>
        public async Task <T> Clone <T>(T o)
        {
            var h = o as ROOTNET.Interface.NTH1;

            using (await ROOTLock.LockAsync())
            {
                return((T)h.Clone());
            }
        }
Exemple #6
0
        /// <summary>
        /// Put all variables we have to move over to the running root in a file so it can be open and read.
        /// </summary>
        /// <param name="cmds"></param>
        /// <param name="queryResultsFile"></param>
        /// <param name="varsToTransfer"></param>
        private async Task WriteInputVariablesForTransfer(StringBuilder cmds, FileInfo queryResultsFile, IEnumerable <KeyValuePair <string, object> > varsToTransfer, DirectoryInfo queryDirectory)
        {
            // Objects that are headed over need to be stored in a file and then loaded into the selector.
            if (varsToTransfer != null && varsToTransfer.Count() > 0)
            {
                TraceHelpers.TraceInfo(20, "RunNtupleQuery: Saving the objects we are going to ship over");
                var inputFilesFilename = new FileInfo(Path.Combine(queryResultsFile.DirectoryName, "TSelectorInputFiles.root"));

                // Next, move through and actually write everything out.
                using (await ROOTLock.LockAsync())
                {
                    Debug.WriteLine($"Aquired ROOTLOCK WriteInputVariablesForTransfer");
                    // Clone the objects. Do it outside of writing so we can make sure that we do not
                    // accidentally clone them or assign them in the wrong place (we are in a multithreaded environment).
                    ROOTNET.NTH1.AddDirectory(false);
                    ROOTNET.NTROOT.gROOT.cd();
                    var clonedObjects = varsToTransfer
                                        .Select(i => (v: i.Value as ROOTNET.Interface.NTObject, k: i.Key))
                                        .Select(i => i.v.Clone(i.k))
                                        .ToArray();

                    // Now, write them out to a file, and code up the stuff that reads them and puts them into the TSelector input list.
                    var outgoingVariables = ROOTNET.NTFile.Open(inputFilesFilename.FullName, "RECREATE");
                    if (!outgoingVariables.IsOpen())
                    {
                        Trace.WriteLine($"Unable to open {inputFilesFilename.FullName} for writing TSelector input variables!");
                        throw new UnableToWriteOutVariablesForQueryException($"Unable to open {inputFilesFilename.FullName} for writing TSelector input variables!");
                    }

                    // Write out the code to load them and stash them remotely if need be.
                    // It is important to do this after the file is created, or the assumption logic in NormalizeFileForTarget will fail.
                    try
                    {
                        var safeInputFilename = await NormalizeFileForTarget(inputFilesFilename, queryDirectory);

                        cmds.AppendLine($"TFile *varsInFile = TFile::Open(\"{safeInputFilename}\", \"READ\");");
                        cmds.AppendLine("selector->SetInputList(new TList());");

                        // Write out the files now
                        foreach (var item in clonedObjects)
                        {
                            outgoingVariables.WriteTObject(item);
                            cmds.AppendLine($"selector->GetInputList()->Add(varsInFile->Get(\"{item.Name}\"));");
                            item.SetNull(); // Make sure we aren't tracking this any more.
                        }
                    }
                    finally
                    {
                        outgoingVariables.Close();
                    }
                }
            }
        }
        private static async Task <ROOTNET.Interface.NTFile> CreateOpenFile(string name)
        {
            var oldDir = ROOTNET.NTDirectory.CurrentDirectory();

            using (await ROOTLock.LockAsync())
            {
                try
                {
                    var f = ROOTNET.NTFile.Open(name, "RECREATE");
                    if (!f.IsOpen())
                    {
                        throw new InvalidOperationException(string.Format("Unable to create file '{0}'. It could be the file is locked by another process (like ROOT!!??)", name));
                    }
                    return(f);
                }
                finally
                {
                    oldDir.cd();
                }
            }
        }
Exemple #8
0
        /// <summary>
        /// Ok, back on the client with the result. We need to try and load the thing in.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="iVariable"></param>
        /// <param name="obj"></param>
        /// <returns></returns>
        /// <remarks>
        /// WARNING: this must be protected by the ROOT lock!
        /// </remarks>
        public async Task <T> LoadResult <T>(IDeclaredParameter iVariable, RunInfo[] obj)
        {
            if (obj == null)
            {
                throw new ArgumentNullException("Obj cannot be null");
            }

            var named = obj[0]._result as ROOTNET.Interface.NTNamed;

            if (named == null)
            {
                throw new ArgumentException("Object isn't named");
            }

            if (iVariable == null)
            {
                throw new ArgumentNullException("Variable can't be null");
            }

            var rootObjInfo = iVariable.InitialValue as TypeHandlerROOT.ROOTObjectStaticHolder;

            if (rootObjInfo == null)
            {
                throw new InvalidOperationException("iVariable must be a ROOTObjectCopiedValue!");
            }

            using (await ROOTLock.LockAsync())
            {
                ROOTNET.NTH1.AddDirectory(false);
                var result = named.Clone() as ROOTNET.Interface.NTNamed;

                // Restore name and title - which might be different since our cache is blind
                // to those things.
                result.Name  = rootObjInfo.OriginalName;
                result.Title = rootObjInfo.OriginalTitle;

                return((T)result);
            }
        }
Exemple #9
0
        /// <summary>
        /// Write out an object. Eventually, with ROOTNET improvements this will work better and perahps
        /// won't be needed!
        /// </summary>
        /// <param name="obj">The object to be written. Assumed not null.</param>
        /// <param name="dir"></param>
        internal static void InternalWriteObject(this ROOTNET.Interface.NTObject obj, ROOTNET.Interface.NTDirectory dir)
        {
            if (obj == null)
            {
                Console.WriteLine("WARNING: Unable to write out null object to a TDirectory!");
                return;
            }

            using (ROOTLock.Lock())
            {
                if (obj is ROOTNET.Interface.NTH1 h)
                {
                    var copy = h.Clone();
                    dir.WriteTObject(copy); // Ugly from a memory pov, but...
                    copy.SetNull();
                }

                else
                {
                    dir.WriteTObject(obj);
                    obj.SetNull();
                }
            }
        }
Exemple #10
0
        /// <summary>
        /// Create a canvas that is a set of stacked plots.
        /// </summary>
        /// <remarks>
        /// Only TH1F plots are dealt with properly here. Everything else is ignored and no stacked plot will be emitted.
        /// </remarks>
        /// <param name="histos"></param>
        /// <param name="canvasName">Name given to the canvas</param>
        /// <param name="canvasTitle">Title that will be put at the top of the canvas</param>
        /// <param name="colorize">True if colors should be automattically assigned to the canvas.</param>
        /// <param name="logy">True if the y axis should be log scale</param>
        /// <param name="normalize">True if the histograms should be set to normal area (1) before being plotted</param>
        /// <param name="legendContainsOnlyUniqueTitleWords">If true, then common words in the  histogram titles are removed before they are used for the legend</param>
        /// <returns></returns>
        public static ROOTNET.Interface.NTCanvas PlotStacked(this ROOTNET.Interface.NTH1[] histos, string canvasName, string canvasTitle,
                                                             bool logy      = false,
                                                             bool normalize = false,
                                                             bool legendContainsOnlyUniqueTitleWords = true,
                                                             bool colorize = true)
        {
            if (histos == null || histos.Length == 0)
            {
                return(null);
            }

            // Always build a clone... because that way if the histogram is modified after we look at it, the plot will be what
            // the user intended.
            using (ROOTLock.Lock())
            {
                var hToPlot = (from h in histos where (h as ROOTNET.Interface.NTH1) != null select h.Clone(string.Format("{0}{1}", h.Name, canvasName)) as ROOTNET.Interface.NTH1).ToArray();
                if (hToPlot.Length == 0)
                {
                    var msg = new StringBuilder();
                    msg.Append("Warning: Only able to build a stacked plot for TH1F type plots (");
                    foreach (var p in histos)
                    {
                        msg.AppendFormat(" {0}", p.Name);
                    }
                    msg.Append(")");
                    Console.WriteLine(msg.ToString());
                    return(null);
                }

                foreach (var h in hToPlot)
                {
                    h.SetDirectory(null);
                }

                //
                // If we have to normalize first, we need to normalize first!
                //

                if (normalize)
                {
                    hToPlot = (from h in hToPlot
                               select h.Normalize()).ToArray();
                }

                //
                // Reset the colors on these guys
                //

                if (colorize)
                {
                    var cloop = new ColorLoop();
                    foreach (var h in hToPlot)
                    {
                        h.LineColor = cloop.NextColor();
                    }
                }

                //
                // Remove common words from the titles.
                //

                if (legendContainsOnlyUniqueTitleWords && hToPlot.Length > 1)
                {
                    var splitTitles = from h in hToPlot
                                      select h.Title.Split();

                    var wordList = from index in Enumerable.Range(0, splitTitles.Select(ar => ar.Count()).Max())
                                   select(from titleWords in splitTitles select titleWords.Skip(index).FirstOrDefault()).ToArray();

                    var isTheSame = (from wl in wordList
                                     select(wl.All(tword => tword == wl.First()))).ToArray();

                    var fixedTitleStrings = from twords in splitTitles
                                            select(
                        from h in twords.Zip(isTheSame, (tword, issame) => issame ? "" : tword)
                        where !string.IsNullOrWhiteSpace(h)
                        select h
                        );

                    foreach (var histAndTitle in hToPlot.Zip(fixedTitleStrings, (h, strArr) => Tuple.Create(h, strArr)))
                    {
                        string title = string.Join(" ", histAndTitle.Item2);
                        histAndTitle.Item1.Title = title;
                    }
                }

                //
                // Grab the x and y axis titles from the first histogram
                //

                var xaxisTitle = hToPlot[0].Xaxis.Title;
                var yaxisTitle = hToPlot[0].Yaxis.Title;

                //
                // Use the nice ROOT utility THStack to make the plot. Once we do this, the plot is now owned by the TCanvas.
                //

                var stack = new ROOTNET.NTHStack(canvasName + "Stack", canvasTitle.ReplaceLatexStrings());
                foreach (var h in hToPlot)
                {
                    stack.Add(h);
                    h.SetNull();
                }

                //
                // Now do the plotting. Use the THStack to get all the axis stuff correct.
                // If we are plotting a log plot, then make sure to set that first before
                // calling it as it will use that information during its painting.
                //

                var result = new ROOTNET.NTCanvas(canvasName, canvasTitle.ReplaceLatexStrings())
                {
                    FillColor = ROOTNET.NTStyle.gStyle.FrameFillColor // This is not a sticky setting!
                };
                if (logy)
                {
                    result.Logy = 1;
                }
                stack.Draw("nostack");

                if (!string.IsNullOrWhiteSpace(xaxisTitle))
                {
                    stack.Xaxis.Title = xaxisTitle;
                }
                if (!string.IsNullOrWhiteSpace(yaxisTitle))
                {
                    stack.Yaxis.Title = yaxisTitle;
                }

                stack.Draw("nostack");

                //
                // The stack is now "attached" to the canvas. This means the canvas now owns it. So we
                // definately don't want the GC to delete it - so here we need to turn off the delete.
                //

                stack.SetNull();

                //
                // And a legend!
                //

                result.BuildLegend();

                //
                // Return the canvas so it can be saved to the file (or whatever).
                //

                return(result);
            }
        }
Exemple #11
0
        /// <summary>
        /// The detailed code that runs the query.
        /// </summary>
        /// <param name="tSelectorClassName">Name of the TSelector object</param>
        /// <param name="outputFileInfo">Where the output results should be written for eventual reading</param>
        private async Task <Dictionary <string, ROOTNET.Interface.NTObject> > RunNtupleQuery(string tSelectorClassName, IEnumerable <KeyValuePair <string, object> > variablesToLoad,
                                                                                             string treeName, FileInfo[] rootFiles)
        {
            ///
            /// Create a new TSelector to run
            ///

            TraceHelpers.TraceInfo(18, "RunNtupleQuery: Startup - doing selector lookup");
            var cls = ROOTNET.NTClass.GetClass(tSelectorClassName);

            if (cls == null)
            {
                throw new InvalidOperationException("Unable find class '" + tSelectorClassName + "' in the ROOT TClass registry that was just successfully compiled - can't run ntuple query - major inconsistency");
            }

            var selector = cls.New() as ROOTNET.Interface.NTSelector;

            ///
            /// Create the chain and load file files into it.
            ///

            TraceHelpers.TraceInfo(19, "RunNtupleQuery: Creating the TChain");
            using (var tree = new ROOTNET.NTChain(treeName))
            {
                foreach (var f in rootFiles)
                {
                    tree.Add(f.FullName);
                }

                // If there are any objects we need to send to the selector, then send them on now
                TraceHelpers.TraceInfo(20, "RunNtupleQuery: Saving the objects we are going to ship over");
                var objInputList = new ROOTNET.NTList();
                selector.InputList = objInputList;

                using (await ROOTLock.LockAsync())
                {
                    ROOTNET.NTH1.AddDirectory(false);
                    foreach (var item in variablesToLoad)
                    {
                        var obj = item.Value as ROOTNET.Interface.NTNamed;
                        if (obj == null)
                        {
                            throw new InvalidOperationException("Can only deal with named objects");
                        }
                        var cloned = obj.Clone(item.Key);
                        objInputList.Add(cloned);
                    }
                }

                // Setup the cache for more efficient reading. We assume we are on a machine with plenty of memory
                // for this.
                tree.CacheSize = 1024 * 1024 * 100; // 100 MB cache
                if (LeafNames == null)
                {
                    tree.AddBranchToCache("*", true);
                }
                else
                {
                    foreach (var leaf in LeafNames)
                    {
                        tree.AddBranchToCache(leaf, true);
                    }
                }
                tree.StopCacheLearningPhase();

                // Always Do the async prefetching (this is off by default for some reason, but...).
                ROOTNET.Globals.gEnv.Value.SetValue("TFile.AsynchPrefetching", 1);

                // Finally, run the whole thing
                TraceHelpers.TraceInfo(21, "RunNtupleQuery: Running TSelector");
                if (Environment.BreakToDebugger)
                {
                    System.Diagnostics.Debugger.Break();
                }
                tree.Process(selector);
                TraceHelpers.TraceInfo(22, "RunNtupleQuery: Done");

                // If debug, dump some stats...
                if (Environment.CompileDebug)
                {
                    tree.PrintCacheStats();
                }

                //
                // Get the results and put them into a map for safe keeping!
                // Also, since we want the results to live beyond this guy, make sure that when
                // the selector is deleted the objects don't go away!
                //

                var results = new Dictionary <string, ROOTNET.Interface.NTObject>();
                foreach (var o in selector.OutputList)
                {
                    results[o.Name] = o;
                }
                selector.OutputList.SetOwner(false);

                return(results);
            }
        }