Making Plots

While it is possible to use raw LINQ structures to make plots, the library comes with some easy-to-use (I hope) extension methods that make making plots easy.

Getting A Queriable Object

The first step is getting a hold of an object that you can write queries against. Helper routines are provided for this – and generated automatically when your ntuple structure is parsed. For example:

var files = ROOTLINQ.QueryableCollectionTree.Create(new FileInfo(“junk.root”);

The variable files is what you will make your queries against. The Create function takes a single file or a list of files as an argument – so you can chain a large number of files together if you wish.

Filtering

Filtering is done exactly as you normally would with a LINQ query. For example:

            var allPVs = from evt in files
                         from pv in evt.PVs
                         select pv;

            var allGoodPVs = from p in allPVs
                             where p.nTracks != 0
                             select p;

This first takes all primary verticies in each event and turns them into a single stream (basically, flattens them out), and then selects the primary verticies that have at least one track.

There are some limitations. None of the sorting or grouping operators currently work – that is for a future version of the LINQ translator, I’m afraid.

Counting

Counting the # of primary vertices is easy. Just append the LINQ Count() operator: int number = allGoodPVs.Count(). Doing that will cause the library to generate a ROOT TSelector object, compile it, and run it over the files, and return a count.

Plotting

Plotting is done by calling the Plot extension function on a query and making sure the system knows how to turn whatever it is looking at into a floating point number. So, for example, the following two bits of source code will make the same plots.

            var hist1 = allGoodPVs.Select(pv => pv.nTracks).Plot("nTracks", "Number of tracks associated with each vertex", 100, 0.0, 100.0);
            var hist2= allGoodPVs.Plot("nTracks", "Number of tracks associated with each vertex", 100, 0.0, 100.0, p => p.nTracks);

The first one uses a Select statement to change the stream of primary vertices into an integer stream of the number of tracks. The Plot extension then puts those into the plot. The second one includes a lambda function at the end which tells Plot how to do the conversion. Each of these lines will generate the required C++, compile it, and run it.

One thing to note – the histogram is not saved to any file – not even a file currently open. In stead you must explicitly save it. You’ll find there is an extension method called SaveToROOTDirectory as a shortcut.

To see how the plot helpers are written – so you can write similar ones your self if you wish – look at the Heleprs.cs file in the source code.

Batching Operations

While the above means that code can be quite composable, it is horribly slow. If each run through the data takes 1 minute and you have 30 plots… It is much more efficient to, instead, run all 30 plots at once. This can be done by replacing Plot and Count with FuturePlot and FutureCount. Each of the two returns a FutureValue object. No evaluation occurs, though the query is queued up for execution next time an execution is forced. After you’ve queued up all your plots, just ask for the value on any FutureValue object and everything will run at once.

            var qu = ROOTLINQ.QueryableCollectionTree.Create(f);

            var count = qu.FutureCount();
            var trackPts = qu.SelectMany(evt => evt.Tracks).Select(trk => trk.pt / 1000.0).FuturePlot("trackPt", "Track Pts", 100, 0.0, 20.0);
            var jetPts = qu.SelectMany(evt => evt.jet04).Select(j => j.Et / 1000.0).FuturePlot("jetET", "Jet E_{T}", 100, 0.0, 40.0);

            var output = ROOTNET.NTFile.Open("DemoFuturesOutput.root", "RECREATE");
            trackPts.Value.SaveToROOTDirectory(output);
            jetPts.Value.SaveToROOTDirectory(output);

            Console.WriteLine("There were {0} events we processed.", count.Value);

            output.Write();
            output.Close();

This will create one run and all the code will be in there together (don’t look at the code… a the current version the combination is seriously lame!!).

Last edited May 30, 2011 at 1:56 PM by gwatts, version 2

Comments

No comments yet.