ana

package
v0.0.0-...-46257ac Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 26, 2021 License: BSD-3-Clause Imports: 19 Imported by: 0

Documentation

Overview

Package allowing to wrap all needed element of a TTree plotting analysis

Example (ASimpleUseCase)
package main

import (
	"image/color"
	"math"

	"golang.org/x/exp/rand"

	"gonum.org/v1/gonum/stat/distuv"

	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Define samples
	samples := []*ana.Sample{
		ana.CreateSample("data", "data", `Data`, fData, tName),
		ana.CreateSample("bkg1", "bkg", `Proc 1 (2.1 pb)`, fBkg1, tName,
			ana.WithWeight(w1), ana.WithXsec(1.2)),
		ana.CreateSample("bkg2", "bkg", `Proc 2 (0.5 pb)`, fBkg2, tName,
			ana.WithWeight(w2), ana.WithXsec(0.6)),
		ana.CreateSample("bkg3", "bkg", `Proc 3 (0.9 pb)`, fBkg1, tName,
			ana.WithWeight(w2), ana.WithXsec(0.9)),
	}

	// Define variables
	variables := []*ana.Variable{
		ana.NewVariable("Mttbar", ana.TreeVarF32("ttbar_m"), 25, 350, 1000,
			ana.WithAxisLabels(`M(t,t) [GeV]`, "Events Yields"),
		),
		ana.NewVariable("DphiLL", ana.TreeVarF64("truth_dphi_ll"), 10, 0, math.Pi,
			ana.WithAxisLabels(`dPhi(l,l)`, "Events Yields"),
			ana.WithLegLeft(true)),
	}

	// Create analyzer object
	analyzer := ana.New(samples, variables,
		ana.WithSavePath("testdata/Plots_simpleUseCase"),
	)

	// Run the analyzer to produce all the plots
	if err := analyzer.Run(); err != nil {
		panic(err)
	}
}

var (
	fData = "../testdata/file1.root"
	fBkg1 = "../testdata/file2.root"
	fBkg2 = "../testdata/file3.root"
	tName = "truth"

	w1 = ana.TreeValF64(1.0)
	w2 = ana.TreeValF64(0.5)
)
Output:

Example (MultiComponentSamples)

Creation of the default analysis maker type with multi-component samples. The files, trees and variables are dummy, they are here just for the example.

package main

import (
	"image/color"
	"math"

	"golang.org/x/exp/rand"

	"gonum.org/v1/gonum/stat/distuv"

	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Weights and cuts
	w := ana.TreeVarF32("weight")
	isQQ := ana.TreeVarBool("init_qq")

	// Data sample.
	data := ana.NewSample("data", "data", `Data 18-20`)
	data.AddComponent(fData, tName)
	data.AddComponent(fBkg1, tName)

	// Background A sample including three components.
	bkgA := ana.NewSample("BkgTotA", "bkg", `Total Bkg A`, ana.WithWeight(w))
	bkgA.AddComponent(fBkg1, tName)
	bkgA.AddComponent(fBkg2, tName)
	bkgA.AddComponent(fBkg1, tName, ana.WithCut(isQQ))

	// Background B sample including two components.
	bkgB := ana.NewSample("BkgTotB", "bkg", `Total Bkg B`, ana.WithWeight(w))
	bkgB.AddComponent(fBkg1, tName)
	bkgB.AddComponent(fBkg2, tName)

	// Put samples together.
	samples := []*ana.Sample{data, bkgA, bkgB}

	// Define variables
	variables := []*ana.Variable{
		ana.NewVariable("Mttbar", ana.TreeVarF32("ttbar_m"), 25, 350, 1000),
		ana.NewVariable("DphiLL", ana.TreeVarF64("truth_dphi_ll"), 10, 0, math.Pi),
	}

	// Create analyzer object with normalized histograms.
	analyzer := ana.New(samples, variables,
		ana.WithHistoNorm(true),
		ana.WithSavePath("testdata/Plots_multiComponents"),
	)

	// Run the analyzer to produce all the plots
	if err := analyzer.Run(); err != nil {
		panic(err)
	}
}

var (
	fData = "../testdata/file1.root"
	fBkg1 = "../testdata/file2.root"
	fBkg2 = "../testdata/file3.root"
	tName = "truth"
)
Output:

Example (ProduceTreesNewVariables)
package main

import (
	"image/color"
	"math"

	"golang.org/x/exp/rand"

	"gonum.org/v1/gonum/stat/distuv"

	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Sample to process
	data := ana.CreateSample("data", "data", `Data 18-20`, fData, tName)
	bkgA := ana.CreateSample("BkgTotA", "bkg", `Total Bkg A`, fBkg1, tName)
	bkgB := ana.CreateSample("BkgTotB", "bkg", `Total Bkg B`, fBkg2, tName)

	// Put samples together.
	samples := []*ana.Sample{data, bkgA, bkgB}

	// Define variables from the original tree
	variables := []*ana.Variable{
		ana.NewVariable("Mttbar", ana.TreeVarF32("ttbar_m"), 0, 0, 0),
		ana.NewVariable("DphiLL", ana.TreeVarF64("truth_dphi_ll"), 0, 0, 0),
	}

	// Add a new (relarively) complex variable: a smeared ttbar mass by 10%
	smearedMtt := ana.TreeFunc{
		VarsName: []string{"ttbar_m"},
		Fct: func(m float32) float64 {
			return float64(m) * (1.0 + gausDist(0, 0.10).Rand())
		},
	}
	variables = append(variables, ana.NewVariable("smearMttbar", smearedMtt, 0, 0, 0))

	// Create analyzer object with normalized histograms.
	analyzer := ana.New(samples, variables,
		ana.WithDumpTree(true),
		ana.WithPlotHisto(false),
		ana.WithSavePath("testdata/Plots_produceTreeNewVar"),
	)

	// Run the analyzer and dump on tree per sample
	if err := analyzer.Run(); err != nil {
		panic(err)
	}

	// Read back 'data.root' and plot the two variables.
	newFilePath := "testdata/Plots_produceTreeNewVar/ntuples/data.root"
	newTreeName := "GOtree"
	plotter := ana.New(
		[]*ana.Sample{
			ana.CreateSample("new", "bkg", `new ntuple`, newFilePath, newTreeName),
		},
		[]*ana.Variable{
			ana.NewVariable("Mttbar", ana.TreeVarF64("Mttbar"),
				50, 0, 1500, ana.WithTickFormats("", "%.0f"),
				ana.WithAxisLabels("Orignal Mass [GeV]", "Events"),
			),
			ana.NewVariable("smearMttbar", ana.TreeVarF64("smearMttbar"),
				50, 0, 1500, ana.WithTickFormats("", "%.0f"),
				ana.WithAxisLabels("Smeared Mass [GeV]", "Events"),
			),
		},
		ana.WithSavePath("testdata/Plots_produceTreeNewVar"),
	)
	if err := plotter.Run(); err != nil {
		panic(err)
	}

}

var (
	fData = "../testdata/file1.root"
	fBkg1 = "../testdata/file2.root"
	fBkg2 = "../testdata/file3.root"
	tName = "truth"

	gausDist = func(mu, sigma float64) distuv.Normal {
		return distuv.Normal{
			Mu:    mu,
			Sigma: sigma,
			Src:   rand.New(rand.NewSource(0)),
		}
	}
)
Output:

Example (ShapeComparison)
package main

import (
	"image/color"
	"math"

	"golang.org/x/exp/rand"

	"gonum.org/v1/gonum/stat/distuv"

	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Define samples
	samples := []*ana.Sample{
		ana.CreateSample("data", "data", `Data`, fBkg1, tName),
		ana.CreateSample("proc1", "bkg", `Simulation A`, fBkg1, tName,
			ana.WithWeight(w3),
			ana.WithLineColor(darkBlue),
			ana.WithLineWidth(2),
			ana.WithBand(true),
		),
		ana.CreateSample("proc2", "bkg", `Simulation B`, fBkg2, tName,
			ana.WithWeight(w4),
			ana.WithLineColor(darkRed),
			ana.WithLineWidth(2),
			ana.WithBand(true),
		),
	}

	// Define variables
	variables := []*ana.Variable{
		ana.NewVariable("TopPt", ana.TreeVarF32("t_pt"), 10, 0, 500),
		ana.NewVariable("DphiLL", ana.TreeVarF64("truth_dphi_ll"), 10, 0, math.Pi,
			ana.WithLegLeft(true)),
	}

	// Create analyzer object
	analyzer := ana.New(samples, variables,
		ana.WithNevtsMax(500),
		ana.WithHistoStack(false),
		ana.WithHistoNorm(true),
		ana.WithRatioPlot(false),
		ana.WithSavePath("testdata/Plots_shapeComparison"),
	)

	// Run the analyzer to produce all the plots
	if err := analyzer.Run(); err != nil {
		panic(err)
	}

}

var (
	fBkg1 = "../testdata/file2.root"
	fBkg2 = "../testdata/file3.root"
	tName = "truth"

	w3 = ana.TreeFunc{
		VarsName: []string{"t_pt"},
		Fct:      func(pt float32) float64 { return 1.0 + float64(pt)/50. },
	}
	w4 = ana.TreeFunc{
		VarsName: []string{"t_pt"},
		Fct:      func(pt float32) float64 { return 1.0 - float64(pt)/250. },
	}

	darkRed = color.NRGBA{R: 180, G: 30, B: 50, A: 200}

	darkBlue = color.NRGBA{B: 180, G: 30, R: 50, A: 200}
)
Output:

Example (ShapeDistortion)
package main

import (
	"image/color"
	"math"

	"golang.org/x/exp/rand"

	"gonum.org/v1/gonum/stat/distuv"

	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Selection TreeFunc generator
	ptTopGT := func(th float32) ana.TreeFunc {
		return ana.TreeFunc{
			VarsName: []string{"t_pt"},
			Fct:      func(pt float32) bool { return pt > th },
		}
	}

	// Samples
	samples := []*ana.Sample{
		ana.CreateSample("noCut", "bkg", `No cut`, fBkg1, tName,
			ana.WithFillColor(shadowBlue),
		),
		ana.CreateSample("cut1", "bkg", `pT>50`, fBkg1, tName,
			ana.WithCut(ptTopGT(50)),
			ana.WithLineColor(darkRed),
			ana.WithLineWidth(2),
		),
		ana.CreateSample("cut2", "bkg", `pT>100`, fBkg1, tName,
			ana.WithCut(ptTopGT(100)),
			ana.WithLineColor(darkBlue),
			ana.WithLineWidth(2),
		),
		ana.CreateSample("cut3", "bkg", `pT>200`, fBkg1, tName,
			ana.WithCut(ptTopGT(200)),
			ana.WithLineColor(darkGreen),
			ana.WithLineWidth(2),
		),
	}

	// Define variables
	variables := []*ana.Variable{
		ana.NewVariable("Mttbar", ana.TreeVarF32("ttbar_m"), 25, 350, 1500,
			ana.WithAxisLabels("M(t,t) [GeV]", "PDF"),
		),
		ana.NewVariable("DphiLL", ana.TreeVarF64("truth_dphi_ll"), 10, 0, math.Pi,
			ana.WithLegLeft(true),
			ana.WithAxisLabels("dPhi(l,l)", "PDF"),
			ana.WithYRange(0, 0.3),
		),
	}

	// Create analyzer object
	analyzer := ana.New(samples, variables,
		ana.WithAutoStyle(false),
		ana.WithHistoStack(false),
		ana.WithRatioPlot(false),
		ana.WithHistoNorm(true),
		ana.WithSavePath("testdata/Plots_shapeDistortion"),
	)

	// Run the analyzer to produce all the plots
	if err := analyzer.Run(); err != nil {
		panic(err)
	}
}

var (
	fBkg1 = "../testdata/file2.root"

	tName = "truth"

	shadowBlue = color.NRGBA{R: 50, G: 20, B: 150, A: 20}
	darkRed    = color.NRGBA{R: 180, G: 30, B: 50, A: 200}
	darkGreen  = color.NRGBA{G: 180, R: 30, B: 50, A: 200}
	darkBlue   = color.NRGBA{B: 180, G: 30, R: 50, A: 200}
)
Output:

Example (SystematicVariations)
package main

import (
	"image/color"
	"math"

	"golang.org/x/exp/rand"

	"gonum.org/v1/gonum/stat/distuv"
	"gonum.org/v1/plot/vg"

	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Samples
	samples := []*ana.Sample{
		ana.CreateSample("nom", "bkg", `Nominal`, fBkg1, tName,
			ana.WithLineColor(softBlack),
			ana.WithLineWidth(2.0),
			ana.WithBand(true),
		),
		ana.CreateSample("up", "bkg", `Up`, fBkg1, tName,
			ana.WithWeight(w3),
			ana.WithLineColor(darkRed),
			ana.WithLineWidth(1.5),
			ana.WithLineDashes([]vg.Length{3, 2}),
		),
		ana.CreateSample("down", "bkg", `Down`, fBkg1, tName,
			ana.WithWeight(w4),
			ana.WithLineColor(darkBlue),
			ana.WithLineWidth(1.5),
			ana.WithLineDashes([]vg.Length{3, 2}),
		),
	}

	// Define variables
	variables := []*ana.Variable{
		ana.NewVariable("Mttbar", ana.TreeVarF32("ttbar_m"), 25, 350, 1500,
			ana.WithRatioYRange(0.7, 1.3)),
		ana.NewVariable("DphiLL", ana.TreeVarF64("truth_dphi_ll"), 10, 0, math.Pi,
			ana.WithRatioYRange(0.7, 1.3),
			ana.WithYRange(0, 0.2),
			ana.WithLegLeft(true),
		),
	}

	// Create analyzer object
	analyzer := ana.New(samples, variables,
		ana.WithRatioPlot(true),
		ana.WithHistoStack(false),
		ana.WithHistoNorm(true),
		ana.WithSavePath("testdata/Plots_systVariations"),
	)

	// Run the analyzer to produce all the plots
	if err := analyzer.Run(); err != nil {
		panic(err)
	}
}

var (
	fBkg1 = "../testdata/file2.root"

	tName = "truth"

	w3 = ana.TreeFunc{
		VarsName: []string{"t_pt"},
		Fct:      func(pt float32) float64 { return 1.0 + float64(pt)/50. },
	}
	w4 = ana.TreeFunc{
		VarsName: []string{"t_pt"},
		Fct:      func(pt float32) float64 { return 1.0 - float64(pt)/250. },
	}

	softBlack = color.NRGBA{R: 50, G: 30, B: 50, A: 200}

	darkRed = color.NRGBA{R: 180, G: 30, B: 50, A: 200}

	darkBlue = color.NRGBA{B: 180, G: 30, R: 50, A: 200}
)
Output:

Example (WithJointTrees)
package main

import (
	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// File and tree names
	fNameM, tNameM := "../testdata/fileSlices.root", "modules"
	fNameJ, tNameJ := "../testdata/fileSlicesJoint.root", "constants"

	// Samples
	samples := []*ana.Sample{
		ana.CreateSample("HGTD", "bkg", `Minimum Bias`, fNameM, tNameM,
			ana.WithJointTree(fNameJ, tNameJ),
		),
	}

	calibHits := ana.TreeFunc{
		VarsName: []string{"hits_time_mc", "c_mc_excl_mean"},
		Fct: func(ts []float32, c float64) []float64 {
			res := make([]float64, len(ts))
			for i, t := range ts {
				res[i] = float64(t) - c
			}
			return res
		},
	}

	// Variables
	variables := []*ana.Variable{

		// Variable in the main Tree
		ana.NewVariable("hitTimes", ana.TreeVarF32s("hits_time_mc"), 100, 10, 15,
			ana.WithAxisLabels("Uncalibrated times", "Number of Hits"),
		),

		// Variable in the joint Tree
		ana.NewVariable("calibCon", ana.TreeVarF64("c_mc_excl_mean"), 50, 10, 15,
			ana.WithAxisLabels("Calibration constants", "Number of Modules"),
		),

		// Newly computed based on both
		ana.NewVariable("calibHit", calibHits, 100, -2, 3,
			ana.WithAxisLabels("Calibrated Time", "Number of Hits"),
		),
	}

	// Analyzer
	analyzer := ana.New(samples, variables,
		ana.WithHistoStack(false),
		ana.WithRatioPlot(false),
		ana.WithSavePath("testdata/Plots_withJointTrees"),
	)

	// Run the analyzer to produce all the plots
	if err := analyzer.Run(); err != nil {
		panic(err)
	}
}
Output:

Example (WithKinemCuts)
package main

import ()

func main() {

}
Output:

Example (WithLogScale)
package main

import (
	"image/color"
	"math"

	"golang.org/x/exp/rand"

	"gonum.org/v1/gonum/stat/distuv"

	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Define samples
	samples := []*ana.Sample{
		ana.CreateSample("data", "data", `Data`, fData, tName),
		ana.CreateSample("bkg1", "bkg", `Proc 1`, fBkg1, tName, ana.WithWeight(w1)),
		ana.CreateSample("bkg2", "bkg", `Proc 2`, fBkg2, tName, ana.WithWeight(w2)),
		ana.CreateSample("bkg3", "bkg", `Proc 3`, fBkg1, tName, ana.WithWeight(w2)),
	}

	// Define variables
	variables := []*ana.Variable{
		ana.NewVariable("Mttbar", ana.TreeVarF32("ttbar_m"), 30, 0, 3000,
			ana.WithAxisLabels("M(t,t) [GeV]", "Events Yields"),
			ana.WithLogY(true),
		),
		ana.NewVariable("DphiLL", ana.TreeVarF64("truth_dphi_ll"), 10, 0, math.Pi,
			ana.WithAxisLabels("dPhi(l,l)", "Events Yields"),
			ana.WithLegLeft(true),
			ana.WithLogY(true),
		),
	}

	// Create analyzer object
	analyzer := ana.New(samples, variables,
		ana.WithSavePath("testdata/Plots_LogScale"),
		ana.WithHistoStack(true),
	)

	// Run the analyzer to produce all the plots
	if err := analyzer.Run(); err != nil {
		panic(err)
	}
}

var (
	fData = "../testdata/file1.root"
	fBkg1 = "../testdata/file2.root"
	fBkg2 = "../testdata/file3.root"
	tName = "truth"

	w1 = ana.TreeValF64(1.0)
	w2 = ana.TreeValF64(0.5)
)
Output:

Example (WithSignals)
package main

import (
	"image/color"
	"math"

	"golang.org/x/exp/rand"

	"gonum.org/v1/gonum/stat/distuv"
	"gonum.org/v1/plot/vg"

	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Define samples
	samples := []*ana.Sample{
		ana.CreateSample("data", "data", `Data`, fData, tName),
		ana.CreateSample("bkg1", "bkg", `Proc 1`, fBkg1, tName, ana.WithWeight(w1)),
		ana.CreateSample("bkg2", "bkg", `Proc 2`, fBkg2, tName, ana.WithWeight(w2)),
		ana.CreateSample("bkg3", "bkg", `Proc 3`, fBkg1, tName, ana.WithWeight(w2)),
		ana.CreateSample("sig1", "sig", `Sig 1`, fBkg2, tName,
			ana.WithWeight(wSigM(500, 0.04)),
			ana.WithLineColor(darkRed),
			ana.WithLineDashes([]vg.Length{2, 3, 2}),
			ana.WithLineWidth(3),
		),
		ana.CreateSample("sig2", "sig", `Sig 2`, fBkg2, tName,
			ana.WithWeight(wSigM(650, 0.02)),
			ana.WithLineColor(darkGreen),
			ana.WithLineDashes([]vg.Length{1, 1, 1}),
			ana.WithLineWidth(3),
		),
		ana.CreateSample("sig3", "sig", `Sig 2`, fBkg2, tName,
			ana.WithWeight(wSigM(800, 0.01)),
			ana.WithLineColor(darkBlue),
			ana.WithLineDashes([]vg.Length{3, 3, 3}),
			ana.WithLineWidth(3),
		),
	}

	// Define variables
	variables := []*ana.Variable{
		ana.NewVariable("Mttbar", ana.TreeVarF32("ttbar_m"), 100, 350, 1000,
			ana.WithAxisLabels("M(t,t) [GeV]", "Events Yields"),
		),
		ana.NewVariable("DphiLL", ana.TreeVarF64("truth_dphi_ll"), 10, 0, math.Pi,
			ana.WithAxisLabels("dPhi(l,l)", "Events Yields"),
			ana.WithLegLeft(true)),
	}

	// Create analyzer object
	analyzer := ana.New(samples, variables,
		ana.WithSavePath("testdata/Plots_withSignals"),
	)

	// Run the analyzer to produce all the plots
	if err := analyzer.Run(); err != nil {
		panic(err)
	}
}

var (
	fData = "../testdata/file1.root"
	fBkg1 = "../testdata/file2.root"
	fBkg2 = "../testdata/file3.root"
	tName = "truth"

	w1 = ana.TreeValF64(1.0)
	w2 = ana.TreeValF64(0.5)

	wSigM = func(mass, relWidth float32) ana.TreeFunc {
		return ana.TreeFunc{
			VarsName: []string{"ttbar_m"},
			Fct: func(m float32) float64 {
				dM2 := float64((m - mass) * (m - mass))
				sigma2 := float64(mass * relWidth * mass * relWidth)
				return 50 * 1 / float64(mass*relWidth) * math.Exp(-dM2/sigma2)
			},
		}
	}

	darkRed   = color.NRGBA{R: 180, G: 30, B: 50, A: 200}
	darkGreen = color.NRGBA{G: 180, R: 30, B: 50, A: 200}
	darkBlue  = color.NRGBA{B: 180, G: 30, R: 50, A: 200}
)
Output:

Example (WithSignalsStacked)
package main

import (
	"image/color"
	"math"

	"golang.org/x/exp/rand"

	"gonum.org/v1/gonum/stat/distuv"

	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Define samples
	samples := []*ana.Sample{
		ana.CreateSample("data", "data", `Data`, fData, tName,
			ana.WithCircleSize(2.8),
			ana.WithYErrBarsCapWidth(0.01),
		),
		ana.CreateSample("bkg1", "bkg", `Proc 1`, fBkg1, tName, ana.WithWeight(w1)),
		ana.CreateSample("bkg2", "bkg", `Proc 2`, fBkg2, tName, ana.WithWeight(w2)),
		ana.CreateSample("bkg3", "bkg", `Proc 3`, fBkg1, tName, ana.WithWeight(w2)),
		ana.CreateSample("sig1", "sig", `Sig 1`, fBkg2, tName,
			ana.WithWeight(wSigM(500, 0.04))),
		ana.CreateSample("sig2", "sig", `Sig 2`, fBkg2, tName,
			ana.WithWeight(wSigM(650, 0.02))),
		ana.CreateSample("sig3", "sig", `Sig 2`, fBkg2, tName,
			ana.WithWeight(wSigM(800, 0.01))),
	}

	// Define variables
	variables := []*ana.Variable{
		ana.NewVariable("Mttbar", ana.TreeVarF32("ttbar_m"), 100, 350, 1000,
			ana.WithAxisLabels("M(t,t) [GeV]", "Events Yields"),
		),
		ana.NewVariable("DphiLL", ana.TreeVarF64("truth_dphi_ll"), 10, 0, math.Pi,
			ana.WithAxisLabels("dPhi(l,l)", "Events Yields"),
			ana.WithLegLeft(true)),
	}

	// Create analyzer object
	analyzer := ana.New(samples, variables,
		ana.WithSignalStack(true),
		ana.WithSavePath("testdata/Plots_withStackedSignals"),
	)

	// Run the analyzer to produce all the plots
	if err := analyzer.Run(); err != nil {
		panic(err)
	}
}

var (
	fData = "../testdata/file1.root"
	fBkg1 = "../testdata/file2.root"
	fBkg2 = "../testdata/file3.root"
	tName = "truth"

	w1 = ana.TreeValF64(1.0)
	w2 = ana.TreeValF64(0.5)

	wSigM = func(mass, relWidth float32) ana.TreeFunc {
		return ana.TreeFunc{
			VarsName: []string{"ttbar_m"},
			Fct: func(m float32) float64 {
				dM2 := float64((m - mass) * (m - mass))
				sigma2 := float64(mass * relWidth * mass * relWidth)
				return 50 * 1 / float64(mass*relWidth) * math.Exp(-dM2/sigma2)
			},
		}
	}
)
Output:

Example (WithSliceVariables)
package main

import (
	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// File and tree names
	fName, tName := "../testdata/fileSlices.root", "modules"

	// Samples
	samples := []*ana.Sample{
		ana.CreateSample("HGTD", "bkg", `w/o calib.`, fName, tName),
	}

	// Variables
	variables := []*ana.Variable{
		ana.NewVariable("hitTimes", ana.TreeVarF32s("hits_time_mc"), 100, 10, 15),
	}

	// Analyzer
	analyzer := ana.New(samples, variables,
		ana.WithHistoStack(false),
		ana.WithRatioPlot(false),
		ana.WithSavePath("testdata/Plots_withSliceVariables"),
	)

	// Run the analyzer to produce all the plots
	if err := analyzer.Run(); err != nil {
		panic(err)
	}
}
Output:

Example (WithTreeDumping)
package main

import (
	"image/color"
	"math"

	"golang.org/x/exp/rand"

	"gonum.org/v1/gonum/stat/distuv"

	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Weights and cuts
	w := ana.TreeVarF32("weight")
	isQQ := ana.TreeCutBool("init_qq")

	// Data sample.
	data := ana.NewSample("data", "data", `Data 18-20`)
	data.AddComponent(fData, tName)
	data.AddComponent(fBkg1, tName)

	// Background A sample including three components.
	bkgA := ana.NewSample("BkgTotA", "bkg", `Total Bkg A`, ana.WithWeight(w))
	bkgA.AddComponent(fBkg1, tName)
	bkgA.AddComponent(fBkg2, tName)
	bkgA.AddComponent(fBkg1, tName, ana.WithCut(isQQ))

	// Background B sample including two components.
	bkgB := ana.NewSample("BkgTotB", "bkg", `Total Bkg B`, ana.WithWeight(w))
	bkgB.AddComponent(fBkg1, tName)
	bkgB.AddComponent(fBkg2, tName)

	// Put samples together.
	samples := []*ana.Sample{data, bkgA, bkgB}

	// Define variables
	variables := []*ana.Variable{
		ana.NewVariable("Mttbar", ana.TreeVarF32("ttbar_m"), 25, 350, 1000),
		ana.NewVariable("DphiLL", ana.TreeVarF64("truth_dphi_ll"), 10, 0, math.Pi),
	}

	// Define some selections
	selections := []*ana.Selection{
		ana.NewSelection("LowM", cutMlt500),
		ana.NewSelection("HighM", cutMgt500),
	}

	// Create analyzer object with normalized histograms.
	analyzer := ana.New(samples, variables,
		ana.WithKinemCuts(selections),
		ana.WithDumpTree(true),
		ana.WithSavePath("testdata/Plots_withTreeDumping"),
	)

	// Run the analyzer to produce all the plots
	if err := analyzer.Run(); err != nil {
		panic(err)
	}
}

var (
	fData = "../testdata/file1.root"
	fBkg1 = "../testdata/file2.root"
	fBkg2 = "../testdata/file3.root"
	tName = "truth"

	cutMlt500 = ana.TreeFunc{
		VarsName: []string{"ttbar_m"},
		Fct:      func(m float32) bool { return m < 500 },
	}
	cutMgt500 = ana.TreeFunc{
		VarsName: []string{"ttbar_m"},
		Fct:      func(m float32) bool { return m >= 500 },
	}
)
Output:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Maker

type Maker struct {

	// Inputs
	Samples   []*Sample    // List of samples on which to run.
	Variables []*Variable  // List of variables to plot.
	KinemCuts []*Selection // List of cuts to apply (default: no cut).
	NevtsMax  int64        // Maximum event number per components (default: -1),
	Lumi      float64      // Integrated luminosity en 1/fb (default: 1/pb).
	SampleMT  bool         // Enable concurency accross samples (default: true).

	// Ouputs
	SavePath     string // Path to which plot will be saved (default: 'outputs').
	SaveFormat   string // Plot file extension: 'png' (default), 'pdf' or 'png'.
	CompileLatex bool   // On-the-fly latex compilation (default: true).
	DumpTree     bool   // Dump a TTree in a file for each sample (default: false).
	PlotHisto    bool   // Enable histogram plotting (default: true).

	// Plots
	AutoStyle      bool        // Enable automatic styling (default: true).
	PlotTitle      string      // General plot title (default: 'TTree GOnalyzer').
	HistoStack     bool        // Enable histogram stacking (default: true).
	SignalStack    bool        // Enable signal stack (default: false).
	HistoNorm      bool        // Normalize distributions to unit area (default: false).
	TotalBand      bool        // Enable total error band in stack mode (default: true).
	TotalBandColor color.NRGBA // Color for the uncertainty band (default: gray).

	// Enable ratio plot (default: true).
	// If stack is on, the ratio is defined as data over total bkg.
	// If stack is off, ratios are defined as sample[i] / data when
	// a data sample is defined, sample[i] / sample[0] otherwise.
	RatioPlot bool
	// contains filtered or unexported fields
}

Analysis maker type is the main object of the ana package. It contains all samples and variables on which to loop to produce and plot histograms. Several options can be specified to normalize and/or stack histograms, add a ratio plot, or a list of kinematic selections.

func New

func New(s []*Sample, v []*Variable, opts ...Options) Maker

New creates a default analysis maker from a list of sample and a list of variables.

func (*Maker) Normalizations

func (ana *Maker) Normalizations() ([][]float64, []float64)

Helper function computing the normalisation of of all samples for a given cut

func (*Maker) PlotVariables

func (ana *Maker) PlotVariables() error

PlotVariables loops over all filled histograms and produce one plot for each variable and selection, including all sample histograms.

func (Maker) PrintReport

func (ana Maker) PrintReport()

PrintReport prints some general information about the number of processed samples, events and produced histograms.

func (*Maker) PrintSlowTreeFuncs

func (ana *Maker) PrintSlowTreeFuncs()

PrintSlowTreeFuncs prints the list of TreeFunc which relies on a generic groot/rfunc formula, ie based on 'reflect' calls. These function are ~ 5 times slower than the one defined using this example https://godoc.org/go-hep.org/x/hep/groot/rtree#example-Reader--WithFormulaFromUser

func (*Maker) Run

func (ana *Maker) Run() error

Run performs the three steps in one function: fill histos, plot histos and print report.

func (*Maker) RunEventLoops

func (ana *Maker) RunEventLoops() error

RunEventLoops runs one event loop per sample to fill histograms for each variables and selections. If DumpTree is true, a tree is also dumped with all variables and one branch per selection.

func (*Maker) RunTimePerKEvts

func (ana *Maker) RunTimePerKEvts() float64

RunTimePerKEvts returns the running time in millisecond per kEvents.

type Options

type Options func(cfg *config)

Options encodes the various settings to pass to an analysis, ie a Maker, as arguments of ana.New().

func WithAutoStyle

func WithAutoStyle(b bool) Options

WithAutoStyle enables automatic styling of the histograms.

func WithCompileLatex

func WithCompileLatex(b bool) Options

WithCompileLatex enables automatic latex compilation.

func WithDumpTree

func WithDumpTree(b bool) Options

WithDumpTree enables tree dumping (one per sample).

func WithHistoNorm

func WithHistoNorm(b bool) Options

WithHistoNorm enables histogram normalization to unity.

func WithHistoStack

func WithHistoStack(b bool) Options

WithHistoStack enables histogram stacking for bkg-typed samples.

func WithKinemCuts

func WithKinemCuts(c []*Selection) Options

WithKinemCuts sets the list of kinematic cuts to run on.

func WithLumi

func WithLumi(l float64) Options

WithLumi sets the integrated luminosity in fb-1. The full normalisation factor is (xsec*lumi)/ngen. 'ngen' and 'xsec' are given for each sample/component, via ana.CreateSample() or s.AddComponent(). While the 'lumi' is given to via ana.New(). By default, lumi = 1000/fb (=1/pb).

func WithNevtsMax

func WithNevtsMax(n int64) Options

WithNevtsMax sets the maximum processed event for each sample component. If n[sample]<n, the tool will run n[sample] events for this sample.

func WithPlotHisto

func WithPlotHisto(b bool) Options

WithPlotHisto enables histogram plotting. It can be set to false to only dump trees.

func WithPlotTitle

func WithPlotTitle(t string) Options

WithPlotTitle sets the general plot title.

func WithRatioPlot

func WithRatioPlot(b bool) Options

WithRatioPlot enables the ratio plot panel.

func WithSampleMT

func WithSampleMT(b bool) Options

WithSampleMT enables a concurent sample processing.

func WithSaveFormat

func WithSaveFormat(f string) Options

WithSaveFormat sets the format for the plots.

func WithSavePath

func WithSavePath(p string) Options

WithSavePath sets the path to save plots.

func WithSignalStack

func WithSignalStack(b bool) Options

WithSignalStack enables histogram stacking for bkg-typed samples.

func WithTotalBand

func WithTotalBand(b bool) Options

WithHistoStack enables histogram stacking for bkg-typed samples.

func WithTotalBandColor

func WithTotalBandColor(c color.NRGBA) Options

WithTotalBandColor sets the color for the error band of total histogram (and ratio).

type Sample

type Sample struct {

	// General settings
	Name     string // Sample name.
	Type     string // Sample type: 'data', 'bkg' or 'sig'.
	LegLabel string // Label used in the legend.

	// Gobal weight and cut (applied to all components).
	CutFunc    TreeFunc
	WeightFunc TreeFunc

	// Cosmetic settings
	DataStyle         bool        // Enable data-like style (default: Type == 'data').
	LineColor         color.NRGBA // Line color of the histogram (default: blue).
	LineWidth         vg.Length   // Line width of the histogram (default: 1.5).
	LineDashes        []vg.Length // Line dashes format (default: continous).
	FillColor         color.NRGBA // Fill color of the histogram (default: none).
	CircleMarkers     bool        // Enable circle markers (default: false).
	CircleSize        vg.Length   // Circle size (default: 0).
	CircleColor       color.NRGBA // Circle color (default: transparent).
	Band              bool        // Enable error band display.
	BandColor         color.NRGBA // Circle color (default: gray).
	YErrBars          bool        // Display error bars (default: false || DataStyle).
	YErrBarsLineWidth vg.Length   // Width of error bars line.
	YErrBarsCapWidth  vg.Length   // Width of horizontal bars of the error bars.
	// contains filtered or unexported fields
}

Sample contains all the information defining a single histogram of the final plot. A sample is made of (potentially) several components, or sub-sample. Each component can have different file/tree names, as well as additional cuts and weights, on top of the global ones. Concretly, the global cut is combined with the component cut with a AND, while weights are multiplied.

Example (MultiComponents)
package main

import (
	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Declare weights and cuts
	wGlobal := ana.TreeVarF64("evtWeight") // evtWeight is float64 branch
	wBljets := ana.TreeValF64(0.30)
	cIsHadr := ana.TreeCutBool("isHadronic") // isHadronic is boolean branch

	// ttbar background starting with an empty sample with a global weight
	ttbarIncl := ana.NewSample("ttbar", "bkg", `Inclusive`, ana.WithWeight(wGlobal))

	// Adding dilepont decay
	ttbarIncl.AddComponent("dilep.root", "mytree")

	// Adding l+jets decay, weighted by BR(ttbar->l+jets)
	ttbarIncl.AddComponent("ljets.root", "mytree", ana.WithWeight(wBljets))

	// Adding full hadronic decay, applying a cut to make sure of the decay
	ttbarIncl.AddComponent("fullhad.root", "mytree", ana.WithCut(cIsHadr))
}
Output:

Example (SingleComponent)
package main

import (
	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Data sample
	sData := ana.CreateSample("DATA", "data", `pp data`, "myfile.root", "mytree")

	// Background sample, say QCD pp->ttbar production
	sBkg := ana.CreateSample("ttbar", "bkg", `QCD prod.`, "myfile.root", "mytree")

	// Signal sample, say pp->H->ttbar production
	sSig := ana.CreateSample("Htt", "sig", `Higgs prod.`, "myfile.root", "mytree")

	// New analysis
	ana.New([]*ana.Sample{sData, sBkg, sSig}, []*ana.Variable{})
}
Output:

Example (WithCut)
package main

import (
	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Selection criteria computed from several branches
	sel := ana.TreeFunc{
		VarsName: []string{"pt", "eta", "m"},
		Fct: func(pt, eta, m float64) bool {
			return (pt > 150 && eta > 0) || m < 125
		},
	}

	// Sample with computed boolean
	ana.CreateSample("proc", "bkg", `leg`, "myfile.root", "mytree",
		ana.WithCut(sel),
	)

	// Sample with single branch boolean
	ana.CreateSample("proc", "bkg", `leg`, "myfile.root", "mytree",
		ana.WithCut(ana.TreeCutBool("passCriteria")),
	)
}
Output:

Example (WithWeight)
package main

import (
	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Weight computed from several branches
	w := ana.TreeFunc{
		VarsName: []string{"w1", "w2", "w3"},
		Fct: func(w1, w2, w3 float64) float64 {
			return w1 * w2 * w3
		},
	}

	// Sample with computed weight
	ana.CreateSample("proc", "bkg", `leg`, "myfile.root", "mytree",
		ana.WithWeight(w),
	)

	// Sample with single branch weight
	ana.CreateSample("proc", "bkg", `leg`, "myfile.root", "mytree",
		ana.WithWeight(ana.TreeVarF64("evtWght")),
	)
}
Output:

func CreateSample

func CreateSample(sname, stype, sleg, fname, tname string, opts ...SampleOptions) *Sample

CreateSample creates a non-empty sample having the default settings, with only one component. This function is a friendly API to ease single-component samples declaration. For multi-component samples, one can either add components on top with s.AddComponent(...), or start from an empty sample using NewSample(...) followed by few s.AddComponent(...).

func NewSample

func NewSample(sname, stype, sleg string, opts ...SampleOptions) *Sample

NewSample creates a new empty sample, ie without any components, with the default options. Components can be then added using s.AddComponent(...) function.

func (*Sample) AddComponent

func (s *Sample) AddComponent(fname, tname string, opts ...SampleOptions)

AddComponent adds a new component (ie file and tree) to the sample. A additional cut and weight can be applied to the added component only. The component cut is combined with the global cut using a AND, while the component weight is multiplied with the global weight.

func (Sample) CreateHisto

func (s Sample) CreateHisto(hdata *hbook.H1D, opts ...hplot.Options) *hplot.H1D

CreateHisto returns a hplot.H1D with the sample style.

func (*Sample) IsBkg

func (s *Sample) IsBkg() bool

IsBkg returns true it the sample Type is 'background'.

func (*Sample) IsData

func (s *Sample) IsData() bool

IsData returns true it the sample Type is 'data'.

func (*Sample) IsSig

func (s *Sample) IsSig() bool

IsSig returns true it the sample Type is 'signal'.

type SampleOptions

type SampleOptions func(cfg *config)

SampleOptions encodes the various settings to pass to a Sample type, as arguments of ana.NewSample().

func WithBand

func WithBand(b bool) SampleOptions

WithBand enables y error band.

func WithBandColor

func WithBandColor(c color.NRGBA) SampleOptions

WithBandColor sets the color of the sample error band.

func WithCircleColor

func WithCircleColor(c color.NRGBA) SampleOptions

WithCircleColor sets the color of circle markers.

func WithCircleMarkers

func WithCircleMarkers(b bool) SampleOptions

WithCircleMarkers enables the use of circle markers (as for data histogram).

func WithCircleSize

func WithCircleSize(s vg.Length) SampleOptions

WithCircleSize sets the size of circle markers.

func WithCut

func WithCut(f TreeFunc) SampleOptions

WithCut sets the cut to be applied to the sample, as defined by the TreeFunc f, which must return a bool. Maker.FillHisto() will panic otherwise.

func WithDataStyle

func WithDataStyle(b bool) SampleOptions

WithDataStyle enables the default data histogram style.

func WithFillColor

func WithFillColor(c color.NRGBA) SampleOptions

WithFillColor sets the color with which the histo will be filled.

func WithJointTree

func WithJointTree(fname, tname string) SampleOptions

WithJointTree adds a tree to be joint for this sample/component. Branches of joint tree are added to the list of available variables. Several joint trees can be added using WithJointTree() option several times.

func WithLineColor

func WithLineColor(c color.NRGBA) SampleOptions

WithLineColor sets the line color of the histogram.

func WithLineDashes

func WithLineDashes(s []vg.Length) SampleOptions

WithLineWidth sets line width of the sample histogram.

func WithLineWidth

func WithLineWidth(w vg.Length) SampleOptions

WithLineWidth sets line width of the sample histogram.

func WithNgen

func WithNgen(n float64) SampleOptions

WithNgen sets the total number of generated events for the sample/component. The full normalisation factor is (xsec*lumi)/ngen. 'ngen' and 'xsec' are given by sample/component while 'lumi' is given to via ana.New(). By default, Ngen = 1. This option cannot be passed to a sample (or component) of type "data".

func WithWeight

func WithWeight(f TreeFunc) SampleOptions

WithWeight sets the weight to be used for this sample, as defined by the TreeFunc f, which must return a float64. Maker.FillHisto() will panic otherwise.

func WithXsec

func WithXsec(s float64) SampleOptions

WithXsec sets the cross-section in pb to the sample/component. The full normalisation factor is (xsec*lumi)/ngen. 'ngen' and 'xsec' are given by sample/component while 'lumi' is given to via ana.New(). By default, xsec = 1 pb. This option cannot be passed to a sample (or component) of type "data".

func WithYErrBars

func WithYErrBars(b bool) SampleOptions

WithYErrBars enables y error bars.

func WithYErrBarsCapWidth

func WithYErrBarsCapWidth(w vg.Length) SampleOptions

WithYErrBarsCapsWidth sets the width of the y error bars caps.

func WithYErrBarsLineWidth

func WithYErrBarsLineWidth(w vg.Length) SampleOptions

WithYErrBarsLineWidth sets the width of the error bars line

type Selection

type Selection struct {
	Name     string
	TreeFunc TreeFunc
}

The returned type of TreeFunc must be a boolean.

func EmptySelection

func EmptySelection() *Selection

EmptySelection returns an empty selection type, i.e. without name (empty string) and returning always true.

func NewSelection

func NewSelection(name string, fct TreeFunc) *Selection

NewSelection returns a selection with the specified name and TreeFunc fct. Fct must return a boolean.

type TreeFunc

type TreeFunc struct {
	VarsName []string      // List of branch names, being function arguments
	Fct      interface{}   // User-defined function
	Formula  rfunc.Formula // Formula that can be bound to a ROOT tree
}

TreeFunc is a wrapper to use rtree.Formula in an easy way. It provides a set of functions to ease the simple cases of boolean, float32 and float64 branches.

Once the slice of variable (branch) names and the function are given, one can either access the rtree.Formula or directly the GO function to be called in the event loop for boolean, float32 and float64.

Except `TreeCutBool()`, all `NewXXX()` functions lead to a treeFunc.Fct returning a float64 a or []float64 in order to be accpeted by hplot.h1d.Fill(v, w) method. Instead `TreeCutBool()` lead to a treeFunc.Fct returning a bool, specifically for cuts.

Example (General)
package main

import (
	"fmt"
	"log"

	"go-hep.org/x/hep/groot"
	"go-hep.org/x/hep/groot/rtree"

	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Get a reader for the example
	f, r := getReader(5)
	defer f.Close()
	defer r.Close()

	// TreeFunc object computing t_pt*t_eta
	treeFunc := ana.TreeFunc{
		VarsName: []string{"t_pt", "t_eta"},
		Fct: func(pt, eta float32) float64 {
			fmt.Printf("pt=%.2f, eta=%.2f,", pt, eta)
			return float64(pt * eta)
		},
	}

	// Get the rtree.Formula object
	formula := treeFunc.TreeFormulaFrom(r)

	// Go function to be called in the event loop
	getValue := formula.Func().(func() float64)

	// Event loop
	r.Read(func(ctx rtree.RCtx) error {
		fmt.Printf(" pt*eta=%.2f\n", getValue())
		return nil
	})

}

// Helper function get a reader (w/o slices) for the examples
func getReader(nmax int64) (*groot.File, *rtree.Reader) {
	return getReaderFile("../testdata/file1.root", "truth", nmax)
}

// Helper function to get a tree tname from a file fname.
func getReaderFile(fname, tname string, nmax int64) (*groot.File, *rtree.Reader) {

	f, err := groot.Open(fname)
	if err != nil {
		log.Fatal("example_treefunc_test.go: could not open "+fname+": %w", err)
	}

	obj, err := f.Get(tname)
	if err != nil {
		log.Fatal("could not retrieve object: %w", err)
	}
	t := obj.(rtree.Tree)

	r, err := rtree.NewReader(t, []rtree.ReadVar{}, rtree.WithRange(0, nmax))
	if err != nil {
		log.Fatal("could not create tree reader: %w", err)
	}

	return f, r
}
Output:

pt=145.13, eta=-2.08, pt*eta=-302.15
pt=13.85, eta=-1.69, pt*eta=-23.35
pt=44.03, eta=-3.93, pt*eta=-173.06
pt=136.98, eta=0.64, pt*eta=87.88
pt=77.47, eta=2.93, pt*eta=226.79
Example (WithBranchBoolForCut)
package main

import (
	"fmt"
	"log"

	"go-hep.org/x/hep/groot"
	"go-hep.org/x/hep/groot/rtree"

	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Get a reader for the example
	f, r := getReader(5)
	defer f.Close()
	defer r.Close()

	// TreeFunc object from a boolean branch name in the TTree
	// The return type is boolean, since it's for a cut.
	treeFunc := ana.TreeCutBool("init_qq")

	// Go function to be called in the event loop
	getTreeFuncVal, ok := treeFunc.GetFuncBool(r)
	if !ok {
		log.Fatal("type assertion failed: expect bool")
	}

	// rtree.Formula object
	formula := treeFunc.TreeFormulaFrom(r)
	getFormulaVal := formula.Func().(func() bool)

	// Event loop
	r.Read(func(ctx rtree.RCtx) error {
		vTreeFunc := getTreeFuncVal()
		vFormula := getFormulaVal()
		fmt.Printf("%v %v %v\n", ctx.Entry, vTreeFunc, vFormula)
		return nil
	})

}

// Helper function get a reader (w/o slices) for the examples
func getReader(nmax int64) (*groot.File, *rtree.Reader) {
	return getReaderFile("../testdata/file1.root", "truth", nmax)
}

// Helper function to get a tree tname from a file fname.
func getReaderFile(fname, tname string, nmax int64) (*groot.File, *rtree.Reader) {

	f, err := groot.Open(fname)
	if err != nil {
		log.Fatal("example_treefunc_test.go: could not open "+fname+": %w", err)
	}

	obj, err := f.Get(tname)
	if err != nil {
		log.Fatal("could not retrieve object: %w", err)
	}
	t := obj.(rtree.Tree)

	r, err := rtree.NewReader(t, []rtree.ReadVar{}, rtree.WithRange(0, nmax))
	if err != nil {
		log.Fatal("could not create tree reader: %w", err)
	}

	return f, r
}
Output:

0 false false
1 false false
2 true true
3 false false
4 false false
Example (WithBranchBoolForPlot)
package main

import (
	"fmt"
	"log"

	"go-hep.org/x/hep/groot"
	"go-hep.org/x/hep/groot/rtree"

	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Get a reader for the example
	f, r := getReader(5)
	defer f.Close()
	defer r.Close()

	// TreeFunc object from a boolean branch name in the TTree
	treeFunc := ana.TreeVarBool("init_qq")

	// Go function to be called in the event loop
	// The return type is float64, since it's for plotting.
	getTreeFuncVal, ok := treeFunc.GetFuncF64(r)
	if !ok {
		log.Fatal("type assertion failed: expect float64")
	}

	// rtree.Formula object
	formula := treeFunc.TreeFormulaFrom(r)
	getFormulaVal := formula.Func().(func() float64)

	// Event loop
	r.Read(func(ctx rtree.RCtx) error {
		vTreeFunc := getTreeFuncVal()
		vFormula := getFormulaVal()
		fmt.Printf("%v %v %v\n", ctx.Entry, vTreeFunc, vFormula)
		return nil
	})

}

// Helper function get a reader (w/o slices) for the examples
func getReader(nmax int64) (*groot.File, *rtree.Reader) {
	return getReaderFile("../testdata/file1.root", "truth", nmax)
}

// Helper function to get a tree tname from a file fname.
func getReaderFile(fname, tname string, nmax int64) (*groot.File, *rtree.Reader) {

	f, err := groot.Open(fname)
	if err != nil {
		log.Fatal("example_treefunc_test.go: could not open "+fname+": %w", err)
	}

	obj, err := f.Get(tname)
	if err != nil {
		log.Fatal("could not retrieve object: %w", err)
	}
	t := obj.(rtree.Tree)

	r, err := rtree.NewReader(t, []rtree.ReadVar{}, rtree.WithRange(0, nmax))
	if err != nil {
		log.Fatal("could not create tree reader: %w", err)
	}

	return f, r
}
Output:

0 0 0
1 0 0
2 1 1
3 0 0
4 0 0
Example (WithBranchF32s)
package main

import (
	"fmt"
	"log"

	"go-hep.org/x/hep/groot"
	"go-hep.org/x/hep/groot/rtree"

	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Get a reader for the example
	f, r := getReaderWithSlices(5)
	defer f.Close()
	defer r.Close()

	// TreeFunc object from a []float32 branch name in the TTree.
	// The return type is []float64.
	treeFunc := ana.TreeVarF32s("hits_time_mc")

	// Go function to be called in the event loop
	getTreeFuncVal, ok := treeFunc.GetFuncF64s(r)
	if !ok {
		log.Fatal("type assertion failed: expect []float64")
	}

	// rtree.Formula object
	formula := treeFunc.TreeFormulaFrom(r)
	getFormulaVal := formula.Func().(func() []float64)

	// Event loop
	r.Read(func(ctx rtree.RCtx) error {
		vTreeFunc := getTreeFuncVal()
		vFormula := getFormulaVal()
		fmt.Printf("Evt[%v]\n -> %v\n -> %v\n\n", ctx.Entry, vTreeFunc[:5], vFormula[:5])
		return nil
	})

}

// Helper function get a reader with slices for the examples
func getReaderWithSlices(nmax int64) (*groot.File, *rtree.Reader) {
	return getReaderFile("../testdata/fileSlices.root", "modules", nmax)
}

// Helper function to get a tree tname from a file fname.
func getReaderFile(fname, tname string, nmax int64) (*groot.File, *rtree.Reader) {

	f, err := groot.Open(fname)
	if err != nil {
		log.Fatal("example_treefunc_test.go: could not open "+fname+": %w", err)
	}

	obj, err := f.Get(tname)
	if err != nil {
		log.Fatal("could not retrieve object: %w", err)
	}
	t := obj.(rtree.Tree)

	r, err := rtree.NewReader(t, []rtree.ReadVar{}, rtree.WithRange(0, nmax))
	if err != nil {
		log.Fatal("could not create tree reader: %w", err)
	}

	return f, r
}
Output:

Evt[0]
 -> [12.206398963928223 11.711121559143066 11.734919548034668 12.457039833068848 11.558056831359863]
 -> [12.206398963928223 11.711121559143066 11.734919548034668 12.457039833068848 11.558056831359863]

Evt[1]
 -> [11.718018531799316 12.985346794128418 12.231209754943848 11.825081825256348 12.405976295471191]
 -> [11.718018531799316 12.985346794128418 12.231209754943848 11.825081825256348 12.405976295471191]

Evt[2]
 -> [12.231328964233398 12.214682579040527 12.194867134094238 12.246091842651367 11.859249114990234]
 -> [12.231328964233398 12.214682579040527 12.194867134094238 12.246091842651367 11.859249114990234]

Evt[3]
 -> [11.33843994140625 11.725604057312012 12.774130821228027 12.108593940734863 12.192085266113281]
 -> [11.33843994140625 11.725604057312012 12.774130821228027 12.108593940734863 12.192085266113281]

Evt[4]
 -> [12.156414031982422 12.641215324401855 11.678815841674805 12.329707145690918 11.578168869018555]
 -> [12.156414031982422 12.641215324401855 11.678815841674805 12.329707145690918 11.578168869018555]
Example (WithBranchF64)
package main

import (
	"fmt"
	"log"

	"go-hep.org/x/hep/groot"
	"go-hep.org/x/hep/groot/rtree"

	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Get a reader for the example
	f, r := getReader(5)
	defer f.Close()
	defer r.Close()

	// TreeFunc object from a float64 branch name in the TTree.
	// The return type is []float64.
	treeFunc := ana.TreeVarF64("truth_dphi_ll")

	// Go function to be called in the event loop
	getTreeFuncVal, ok := treeFunc.GetFuncF64(r)
	if !ok {
		log.Fatal("type assertion failed: expect float64")
	}

	// rtree.Formula object
	formula := treeFunc.TreeFormulaFrom(r)
	getFormulaVal := formula.Func().(func() float64)

	// Event loop
	r.Read(func(ctx rtree.RCtx) error {
		vTreeFunc := getTreeFuncVal()
		vFormula := getFormulaVal()
		fmt.Printf("%v %.2f %.2f\n", ctx.Entry, vTreeFunc, vFormula)
		return nil
	})

}

// Helper function get a reader (w/o slices) for the examples
func getReader(nmax int64) (*groot.File, *rtree.Reader) {
	return getReaderFile("../testdata/file1.root", "truth", nmax)
}

// Helper function to get a tree tname from a file fname.
func getReaderFile(fname, tname string, nmax int64) (*groot.File, *rtree.Reader) {

	f, err := groot.Open(fname)
	if err != nil {
		log.Fatal("example_treefunc_test.go: could not open "+fname+": %w", err)
	}

	obj, err := f.Get(tname)
	if err != nil {
		log.Fatal("could not retrieve object: %w", err)
	}
	t := obj.(rtree.Tree)

	r, err := rtree.NewReader(t, []rtree.ReadVar{}, rtree.WithRange(0, nmax))
	if err != nil {
		log.Fatal("could not create tree reader: %w", err)
	}

	return f, r
}
Output:

0 2.99 2.99
1 1.07 1.07
2 3.03 3.03
3 0.07 0.07
4 2.35 2.35
Example (WithNumericalValue)

Example showing how to load a numerical value in a TreeFunc. The reason why this approach exists is to be able to pass a simple constant to a sample, using the same API ana.With.Weight(f TreeFunc).

package main

import (
	"fmt"
	"log"

	"go-hep.org/x/hep/groot"
	"go-hep.org/x/hep/groot/rtree"

	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Get a reader for the example
	f, r := getReader(5)
	defer f.Close()
	defer r.Close()

	// TreeFunc object from a float64
	treeFunc := ana.TreeValF64(0.33)

	// Go function to be called in the event loop
	getTreeFuncVal, ok := treeFunc.GetFuncF64(r)
	if !ok {
		log.Fatal("type assertion failed: expect float64")
	}

	// Event loop
	r.Read(func(ctx rtree.RCtx) error {
		vTreeFunc := getTreeFuncVal()
		fmt.Printf("%v %.2f\n", ctx.Entry, vTreeFunc)
		return nil
	})

}

// Helper function get a reader (w/o slices) for the examples
func getReader(nmax int64) (*groot.File, *rtree.Reader) {
	return getReaderFile("../testdata/file1.root", "truth", nmax)
}

// Helper function to get a tree tname from a file fname.
func getReaderFile(fname, tname string, nmax int64) (*groot.File, *rtree.Reader) {

	f, err := groot.Open(fname)
	if err != nil {
		log.Fatal("example_treefunc_test.go: could not open "+fname+": %w", err)
	}

	obj, err := f.Get(tname)
	if err != nil {
		log.Fatal("could not retrieve object: %w", err)
	}
	t := obj.(rtree.Tree)

	r, err := rtree.NewReader(t, []rtree.ReadVar{}, rtree.WithRange(0, nmax))
	if err != nil {
		log.Fatal("could not create tree reader: %w", err)
	}

	return f, r
}
Output:

0 0.33
1 0.33
2 0.33
3 0.33
4 0.33

func TreeCutBool

func TreeCutBool(v string) TreeFunc

TreeCutBool returns a TreeFunc to get a single boolean branch-based variable for cuts. The output value is a boolean and cannot be used to be plotted. To plot a boolean, use TreeVarBool(v).

func TreeValF64

func TreeValF64(v float64) TreeFunc

TreeValF64 returns a TreeFunc to get float value, ie not a branch-based variable.

func TreeVarBool

func TreeVarBool(v string) TreeFunc

TreeVarBool returns a TreeFunc to get a single boolean branch-based variable to plot. The output value is a float64 and cannot be used for selection. For cuts, use TreeCutBool(v).

func TreeVarF32

func TreeVarF32(v string) TreeFunc

TreeVarF32 returns a TreeFunc to get a single float32 branch-based variable. The output value is a float64.

func TreeVarF32s

func TreeVarF32s(v string) TreeFunc

TreeVarF32s returns a TreeFunc to get a slice of float32 branch-based variable. The output value is a float64.

func TreeVarF64

func TreeVarF64(v string) TreeFunc

TreeVarF64 returns a TreeFunc to get a single float64 branch-based variable. The output value is a float64.

func TreeVarF64s

func TreeVarF64s(v string) TreeFunc

TreeVarF64s returns a TreeFunc to get a slice of float64 branch-based variable. The output value is a float64.

func TreeVarI32

func TreeVarI32(v string) TreeFunc

TreeVarI32 returns a TreeFunc to get a single int32 branch-based variable. The output value is a float64.

func TreeVarI32s

func TreeVarI32s(v string) TreeFunc

TreeVarI32s returns a TreeFunc to get a slice of int32 branch-based variable. The output value is a float64.

func TreeVarI64

func TreeVarI64(v string) TreeFunc

TreeVarI64 returns a TreeFunc to get a single int64 branch-based variable. The output value is a float64.

func TreeVarI64s

func TreeVarI64s(v string) TreeFunc

TreeVarI64s returns a TreeFunc to get a slice of int64 branch-based variable. The output value is a float64.

func (*TreeFunc) FuncFormula

func (f *TreeFunc) FuncFormula() rfunc.Formula

FuncFormula returns the rfunc.Formula function associated to the TreeFunc f. If the type of f.Fct corresponds to either a pre-defined function from rtree/rfunc, or to a user-defined rfunc, it's loaded. A generic rtree function is loaded otherwise (~5 times slower).

func (*TreeFunc) GetFuncBool

func (f *TreeFunc) GetFuncBool(r *rtree.Reader) (func() bool, bool)

GetFuncBool returns the function to be called in the event loop to get the boolean value computed in f.Fct function.

func (*TreeFunc) GetFuncF64

func (f *TreeFunc) GetFuncF64(r *rtree.Reader) (func() float64, bool)

GetFuncF64 returns a function to be called in the event loop to get the float64 value computed in f.Fct function.

func (*TreeFunc) GetFuncF64s

func (f *TreeFunc) GetFuncF64s(r *rtree.Reader) (func() []float64, bool)

GetFuncF64s returns a function to be called in the event loop to get a slice []float64 values computed in f.Fct function.

func (*TreeFunc) IsSlow

func (f *TreeFunc) IsSlow() bool

IsSlow returns false if the f.Fct is already defined in rtree/rfunc package or in TreeFunc. If true, a generic rfunc function is used (based on refect), which is roughly 5 times slower.

func (*TreeFunc) TreeFormulaFrom

func (f *TreeFunc) TreeFormulaFrom(r *rtree.Reader) rfunc.Formula

TreeFormulaFrom returns a rfunc.Formula bound to the reader r.

type Variable

type Variable struct {
	Name                     string   // Variable name.
	TreeFunc                 TreeFunc // Variable definition from branches & functions.
	Nbins                    int      // Number of bins of final histograms.
	Xmin, Xmax               float64  // Mininum and maximum values of the histogram.
	LogY                     bool     // Enable logarithm scale for the y-axis.
	SaveName                 string   // Name of the saved plot (default 'Name').
	XLabel, YLabel           string   // Axis labels (default: 'Variable', 'Events').
	XTickFormat, YTickFormat string   // Axis tick formatting (default: hplot default).
	RangeXmin, RangeXmax     float64  // X-axis range (default: hplot default).
	RangeYmin, RangeYmax     float64  // Y-axis range (default: hplot default).
	RatioYmin, RatioYmax     float64  // Ratio Y-axis range (default: hplot default).
	LegPosTop, LegPosLeft    bool     // Legend position (default: true, false)
	// contains filtered or unexported fields
}

func NewVariable

func NewVariable(name string, tFunc TreeFunc, nBins int, xMin, xMax float64, opts ...VariableOptions) *Variable

NewVariable creates a new variable value with default settings. The TreeFunc object should returns either a float64 or a []float64. Any other returned type will panic.

Example
package main

import (
	"github.com/rmadar/tree-gonalyzer/ana"
)

func main() {
	// Variable 'name' corresponding to the branch 'branchF64'
	// to be histogrammed with 100 bins between 0 and 1
	ana.NewVariable("name", ana.TreeVarF64("branchF64"), 100, 0, 100)
}
Output:

type VariableOptions

type VariableOptions func(cfg *config)

VariableOptions encodes various settings to pass to a Variable type, as arguments of ana.NewVariable().

func WithAxisLabels

func WithAxisLabels(xlab, ylab string) VariableOptions

WithAxisLabels sets the x- and y-axis label.

func WithLegLeft

func WithLegLeft(left bool) VariableOptions

WithLegLeft sets the legend left/right position on the plot.

func WithLegTop

func WithLegTop(top bool) VariableOptions

WithLegTop sets the legend top/bottom position on the plot.

func WithLogY

func WithLogY(b bool) VariableOptions

WithLogY enable y-axis log scale

func WithRatioYRange

func WithRatioYRange(min, max float64) VariableOptions

WithRatioYRange sets the y-axis min and max for the ratio plot.

func WithSaveName

func WithSaveName(n string) VariableOptions

WithSaveName sets the file name of the plot.

func WithTickFormats

func WithTickFormats(xticks, yticks string) VariableOptions

WithTickFormats sets the x- and y-axis labels.

func WithXRange

func WithXRange(min, max float64) VariableOptions

WithXRange sets the x-axis min and max.

func WithYRange

func WithYRange(min, max float64) VariableOptions

WithYRange sets the y-axis min and max.

Directories

Path Synopsis
Package featuring a realistic example of analysis using ana package.
Package featuring a realistic example of analysis using ana package.
Package allowing to benchmark performances of the ana package.
Package allowing to benchmark performances of the ana package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL