go-hep.org/x/hep@v0.38.1/groot/gen.rhist.go (about)

     1  // Copyright ©2018 The go-hep Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build ignore
     6  
     7  package main
     8  
     9  import (
    10  	"fmt"
    11  	"log"
    12  	"os"
    13  	"text/template"
    14  
    15  	"go-hep.org/x/hep/groot/internal/genroot"
    16  )
    17  
    18  func main() {
    19  	genH1()
    20  	genH2()
    21  }
    22  
    23  func genH1() {
    24  	fname := "./rhist/h1_gen.go"
    25  	year := genroot.ExtractYear(fname)
    26  	f, err := os.Create(fname)
    27  	if err != nil {
    28  		log.Fatal(err)
    29  	}
    30  	defer f.Close()
    31  
    32  	genroot.GenImports(year, "rhist", f,
    33  		"fmt", "math", "reflect",
    34  		"",
    35  		"go-hep.org/x/hep/hbook",
    36  		"go-hep.org/x/hep/groot/root",
    37  		"go-hep.org/x/hep/groot/rcont",
    38  		"go-hep.org/x/hep/groot/rbytes",
    39  		"go-hep.org/x/hep/groot/rtypes",
    40  		"go-hep.org/x/hep/groot/rvers",
    41  	)
    42  
    43  	for i, typ := range []struct {
    44  		Name string
    45  		Type string
    46  		Elem string
    47  	}{
    48  		{
    49  			Name: "H1F",
    50  			Type: "rcont.ArrayF",
    51  			Elem: "float32",
    52  		},
    53  		{
    54  			Name: "H1D",
    55  			Type: "rcont.ArrayD",
    56  			Elem: "float64",
    57  		},
    58  		{
    59  			Name: "H1I",
    60  			Type: "rcont.ArrayI",
    61  			Elem: "int32",
    62  		},
    63  	} {
    64  		if i > 0 {
    65  			fmt.Fprintf(f, "\n")
    66  		}
    67  		tmpl := template.Must(template.New(typ.Name).Parse(h1Tmpl))
    68  		err = tmpl.Execute(f, typ)
    69  		if err != nil {
    70  			log.Fatalf("error executing template for %q: %v\n", typ.Name, err)
    71  		}
    72  	}
    73  
    74  	err = f.Close()
    75  	if err != nil {
    76  		log.Fatal(err)
    77  	}
    78  	genroot.GoFmt(f)
    79  }
    80  
    81  func genH2() {
    82  	fname := "./rhist/h2_gen.go"
    83  	year := genroot.ExtractYear(fname)
    84  	f, err := os.Create(fname)
    85  	if err != nil {
    86  		log.Fatal(err)
    87  	}
    88  	defer f.Close()
    89  
    90  	genroot.GenImports(year, "rhist", f,
    91  		"fmt", "math", "reflect",
    92  		"",
    93  		"go-hep.org/x/hep/hbook",
    94  		"go-hep.org/x/hep/groot/root",
    95  		"go-hep.org/x/hep/groot/rcont",
    96  		"go-hep.org/x/hep/groot/rbytes",
    97  		"go-hep.org/x/hep/groot/rtypes",
    98  		"go-hep.org/x/hep/groot/rvers",
    99  	)
   100  
   101  	for i, typ := range []struct {
   102  		Name string
   103  		Type string
   104  		Elem string
   105  	}{
   106  		{
   107  			Name: "H2F",
   108  			Type: "rcont.ArrayF",
   109  			Elem: "float32",
   110  		},
   111  		{
   112  			Name: "H2D",
   113  			Type: "rcont.ArrayD",
   114  			Elem: "float64",
   115  		},
   116  		{
   117  			Name: "H2I",
   118  			Type: "rcont.ArrayI",
   119  			Elem: "int32",
   120  		},
   121  	} {
   122  		if i > 0 {
   123  			fmt.Fprintf(f, "\n")
   124  		}
   125  		tmpl := template.Must(template.New(typ.Name).Parse(h2Tmpl))
   126  		err = tmpl.Execute(f, typ)
   127  		if err != nil {
   128  			log.Fatalf("error executing template for %q: %v\n", typ.Name, err)
   129  		}
   130  	}
   131  
   132  	err = f.Close()
   133  	if err != nil {
   134  		log.Fatal(err)
   135  	}
   136  	genroot.GoFmt(f)
   137  }
   138  
   139  const h1Tmpl = `// {{.Name}} implements ROOT T{{.Name}}
   140  type {{.Name}} struct {
   141  	th1
   142  	arr {{.Type}}
   143  }
   144  
   145  func new{{.Name}}() *{{.Name}} {
   146  	return &{{.Name}}{
   147  		th1:   *newH1(),
   148  	}
   149  }
   150  
   151  // New{{.Name}}From creates a new 1-dim histogram from hbook.
   152  func New{{.Name}}From(h *hbook.H1D) *{{.Name}} {
   153  	var (
   154  		hroot = new{{.Name}}()
   155  		bins  = h.Binning.Bins
   156  		nbins = len(bins)
   157  		edges = make([]float64, 0, nbins+1)
   158  		uflow = h.Binning.Underflow()
   159  		oflow = h.Binning.Overflow()
   160  	)
   161  
   162  	hroot.th1.entries = float64(h.Entries())
   163  	hroot.th1.tsumw = h.SumW()
   164  	hroot.th1.tsumw2 = h.SumW2()
   165  	hroot.th1.tsumwx = h.SumWX()
   166  	hroot.th1.tsumwx2 = h.SumWX2()
   167  	hroot.th1.ncells = nbins+2
   168  
   169  	hroot.th1.xaxis.nbins = nbins
   170  	hroot.th1.xaxis.xmin = h.XMin()
   171  	hroot.th1.xaxis.xmax = h.XMax()
   172  
   173  	hroot.arr.Data = make([]{{.Elem}}, nbins+2)
   174  	hroot.th1.sumw2.Data = make([]float64, nbins+2)
   175  
   176  	for i, bin := range bins {
   177  		if i == 0 {
   178  			edges = append(edges, bin.XMin())
   179  		}
   180  		edges = append(edges, bin.XMax())
   181  		hroot.setDist1D(i+1, bin.Dist.SumW(), bin.Dist.SumW2())
   182  	}
   183  	hroot.setDist1D(0, uflow.SumW(), uflow.SumW2())
   184  	hroot.setDist1D(nbins+1, oflow.SumW(), oflow.SumW2())
   185  
   186  	hroot.th1.SetName(h.Name())
   187  	if v, ok := h.Annotation()["title"]; ok && v != nil {
   188  		hroot.th1.SetTitle(v.(string))
   189  	}
   190  	hroot.th1.xaxis.xbins.Data = edges
   191  	return hroot
   192  }
   193  
   194  func (*{{.Name}}) RVersion() int16 {
   195  	return rvers.{{.Name}}
   196  }
   197  
   198  func (*{{.Name}}) isH1() {}
   199  
   200  // Class returns the ROOT class name.
   201  func (*{{.Name}}) Class() string {
   202  	return "T{{.Name}}"
   203  }
   204  
   205  func (h *{{.Name}}) MarshalROOT(w *rbytes.WBuffer) (int, error) {
   206  	if w.Err() != nil {
   207  		return 0, w.Err()
   208  	}
   209  
   210  	hdr := w.WriteHeader(h.Class(), h.RVersion())
   211  
   212  	w.WriteObject(&h.th1)
   213  	w.WriteObject(&h.arr)
   214  
   215  	return w.SetHeader(hdr)
   216  }
   217  
   218  func (h *{{.Name}}) UnmarshalROOT(r *rbytes.RBuffer) error {
   219  	if r.Err() != nil {
   220  		return r.Err()
   221  	}
   222  
   223  	hdr := r.ReadHeader(h.Class(), h.RVersion())
   224  
   225  	r.ReadObject(&h.th1)
   226  	r.ReadObject(&h.arr)
   227  
   228  	r.CheckHeader(hdr)
   229  	return r.Err()
   230  }
   231  
   232  func (h *{{.Name}}) RMembers() (mbrs []rbytes.Member) {
   233  	mbrs = append(mbrs, h.th1.RMembers()...)
   234  	mbrs = append(mbrs, rbytes.Member{
   235  		Name: "fArray", Value: &h.arr.Data,
   236  	})
   237  	return mbrs
   238  }
   239  
   240  func (h *{{.Name}}) Array() {{.Type}} {
   241  	return h.arr
   242  }
   243  
   244  // Rank returns the number of dimensions of this histogram.
   245  func (h *{{.Name}}) Rank() int {
   246  	return 1
   247  }
   248  
   249  // NbinsX returns the number of bins in X.
   250  func (h *{{.Name}}) NbinsX() int {
   251  	return h.th1.xaxis.nbins
   252  }
   253  
   254  // XAxis returns the axis along X.
   255  func (h*{{.Name}}) XAxis() Axis {
   256  	return &h.th1.xaxis
   257  }
   258  
   259  // bin returns the regularized bin number given an x bin pair.
   260  func (h *{{.Name}}) bin(ix int) int {
   261  	nx := h.th1.xaxis.nbins + 1 // overflow bin
   262  	switch {
   263  	case ix < 0:
   264  		ix = 0
   265  	case ix > nx:
   266  		ix = nx
   267  	}
   268  	return ix
   269  }
   270  
   271  // XBinCenter returns the bin center value in X.
   272  func (h *{{.Name}}) XBinCenter(i int) float64 {
   273  	return float64(h.th1.xaxis.BinCenter(i))
   274  }
   275  
   276  // XBinContent returns the bin content value in X.
   277  func (h *{{.Name}}) XBinContent(i int) float64 {
   278  	ibin := h.bin(i)
   279  	return float64(h.arr.Data[ibin])
   280  }
   281  
   282  // XBinError returns the bin error in X.
   283  func (h *{{.Name}}) XBinError(i int) float64 {
   284  	ibin := h.bin(i)
   285  	if len(h.th1.sumw2.Data) > 0 {
   286  		return math.Sqrt(float64(h.th1.sumw2.Data[ibin]))
   287  	}
   288  	return math.Sqrt(math.Abs(float64(h.arr.Data[ibin])))
   289  }
   290  
   291  // XBinLowEdge returns the bin lower edge value in X.
   292  func (h *{{.Name}}) XBinLowEdge(i int) float64 {
   293  	return h.th1.xaxis.BinLowEdge(i)
   294  }
   295  
   296  // XBinWidth returns the bin width in X.
   297  func (h *{{.Name}}) XBinWidth(i int) float64 {
   298  	return h.th1.xaxis.BinWidth(i)
   299  }
   300  
   301  func (h *{{.Name}}) dist1D(i int) hbook.Dist1D {
   302  	v := h.XBinContent(i)
   303  	err := h.XBinError(i)
   304  	n := h.entries(v, err)
   305  	sumw := h.arr.Data[i]
   306  	sumw2 := 0.0
   307  	if len(h.th1.sumw2.Data) > 0 {
   308  		sumw2 = h.th1.sumw2.Data[i]
   309  	}
   310  	return hbook.Dist1D{
   311  		Dist: hbook.Dist0D{
   312  			N:     n,
   313  			SumW:  float64(sumw),
   314  			SumW2: float64(sumw2),
   315  		},
   316  	}
   317  }
   318  
   319  func (h *{{.Name}}) setDist1D(i int, sumw, sumw2 float64) {
   320  	h.arr.Data[i] = {{.Elem}}(sumw)
   321  	h.th1.sumw2.Data[i] = sumw2
   322  }
   323  
   324  func (h *{{.Name}}) entries(height, err float64) int64 {
   325  	if height <= 0 {
   326  		return 0
   327  	}
   328  	v := height / err
   329  	return int64(v*v+0.5)
   330  }
   331  
   332  // AsH1D creates a new hbook.H1D from this ROOT histogram.
   333  func (h *{{.Name}}) AsH1D() *hbook.H1D {
   334  	var (
   335  		nx = h.NbinsX()
   336  		hh = hbook.NewH1D(int(nx), h.XAxis().XMin(), h.XAxis().XMax())
   337  	)
   338  	hh.Ann = hbook.Annotation{
   339  		"name":  h.Name(),
   340  		"title": h.Title(),
   341  	}
   342  
   343  	hh.Binning.Dist = hbook.Dist1D{
   344  		Dist: hbook.Dist0D{
   345  			N:     int64(h.Entries()),
   346  			SumW:  float64(h.SumW()),
   347  			SumW2: float64(h.SumW2()),
   348  		},
   349  	}
   350  	hh.Binning.Dist.Stats.SumWX = float64(h.SumWX())
   351  	hh.Binning.Dist.Stats.SumWX2 = float64(h.SumWX2())
   352  
   353  	hh.Binning.Outflows = [2]hbook.Dist1D{
   354  		h.dist1D(0),      // underflow
   355  		h.dist1D(nx + 1), // overflow
   356  	}
   357  
   358  	for i := 0; i < nx; i++ {
   359  		bin := &hh.Binning.Bins[i]
   360  		xmin := h.XBinLowEdge(i + 1)
   361  		xmax := h.XBinWidth(i+1) + xmin
   362  		bin.Dist = h.dist1D(i + 1)
   363  		bin.Range.Min = xmin
   364  		bin.Range.Max = xmax
   365  		hh.Binning.Bins[i].Dist = h.dist1D(i + 1)
   366  	}
   367  
   368  	return hh
   369  }
   370  
   371  // MarshalYODA implements the YODAMarshaler interface.
   372  func (h *{{.Name}}) MarshalYODA() ([]byte, error) {
   373  	return h.AsH1D().MarshalYODA()
   374  }
   375  
   376  // UnmarshalYODA implements the YODAUnmarshaler interface.
   377  func (h *{{.Name}}) UnmarshalYODA(raw []byte) error {
   378  	var hh hbook.H1D
   379  	err := hh.UnmarshalYODA(raw)
   380  	if err != nil {
   381  		return err
   382  	}
   383  
   384  	*h = *New{{.Name}}From(&hh)
   385  	return nil
   386  }
   387  
   388  func (h *{{.Name}}) ROOTMerge(src root.Object) error {
   389  	hsrc, ok := src.(*{{.Name}})
   390  	if !ok {
   391  		return fmt.Errorf("rhist: object %q is not a *rhist.H1F (%T)", src.(root.Named).Name(), src)
   392  	}
   393  
   394  	var (
   395  		h1   = h.AsH1D()
   396  		h2   = hsrc.AsH1D()
   397  		hadd = hbook.AddH1D(h1, h2)
   398  	)
   399  
   400  	*h = *New{{.Name}}From(hadd)
   401  	return nil
   402  }
   403  
   404  func init() {
   405  	f := func() reflect.Value {
   406  		o := new{{.Name}}()
   407  		return reflect.ValueOf(o)
   408  	}
   409  	rtypes.Factory.Add("T{{.Name}}", f)
   410  }
   411  
   412  var (
   413  	_ root.Object        = (*{{.Name}})(nil)
   414  	_ root.Merger        = (*{{.Name}})(nil)
   415  	_ root.Named         = (*{{.Name}})(nil)
   416  	_ H1                 = (*{{.Name}})(nil)
   417  	_ rbytes.Marshaler   = (*{{.Name}})(nil)
   418  	_ rbytes.Unmarshaler = (*{{.Name}})(nil)
   419  	_ rbytes.RSlicer     = (*{{.Name}})(nil)
   420  )
   421  `
   422  
   423  const h2Tmpl = `// {{.Name}} implements ROOT T{{.Name}}
   424  type {{.Name}} struct {
   425  	th2
   426  	arr {{.Type}}
   427  }
   428  
   429  func new{{.Name}}() *{{.Name}} {
   430  	return &{{.Name}}{
   431  		th2:   *newH2(),
   432  	}
   433  }
   434  
   435  // New{{.Name}}From creates a new {{.Name}} from hbook 2-dim histogram.
   436  func New{{.Name}}From(h *hbook.H2D) *{{.Name}} {
   437  	var (
   438  		hroot  = new{{.Name}}()
   439  		bins   = h.Binning.Bins
   440  		nxbins = h.Binning.Nx
   441  		nybins = h.Binning.Ny
   442  		xedges = make([]float64, 0, nxbins+1)
   443  		yedges = make([]float64, 0, nybins+1)
   444  	)
   445  
   446  	hroot.th2.th1.entries = float64(h.Entries())
   447  	hroot.th2.th1.tsumw = h.SumW()
   448  	hroot.th2.th1.tsumw2 = h.SumW2()
   449  	hroot.th2.th1.tsumwx = h.SumWX()
   450  	hroot.th2.th1.tsumwx2 = h.SumWX2()
   451  	hroot.th2.tsumwy = h.SumWY()
   452  	hroot.th2.tsumwy2 = h.SumWY2()
   453  	hroot.th2.tsumwxy = h.SumWXY()
   454  
   455  	ncells := (nxbins + 2) * (nybins + 2)
   456  	hroot.th2.th1.ncells = ncells
   457  
   458  	hroot.th2.th1.xaxis.nbins = nxbins
   459  	hroot.th2.th1.xaxis.xmin = h.XMin()
   460  	hroot.th2.th1.xaxis.xmax = h.XMax()
   461  
   462  	hroot.th2.th1.yaxis.nbins = nybins
   463  	hroot.th2.th1.yaxis.xmin = h.YMin()
   464  	hroot.th2.th1.yaxis.xmax = h.YMax()
   465  
   466  	hroot.arr.Data = make([]{{.Elem}}, ncells)
   467  	hroot.th2.th1.sumw2.Data = make([]float64, ncells)
   468  
   469  	ibin := func(ix, iy int) int { return iy*nxbins + ix }
   470  
   471  	for ix := 0; ix < h.Binning.Nx; ix++ {
   472  		for iy := 0; iy < h.Binning.Ny; iy++ {
   473  			i := ibin(ix, iy)
   474  			bin := bins[i]
   475  			if ix == 0 {
   476  				yedges = append(yedges, bin.YMin())
   477  			}
   478  			if iy == 0 {
   479  				xedges = append(xedges, bin.XMin())
   480  			}
   481  			hroot.setDist2D(ix+1, iy+1, bin.Dist.SumW(), bin.Dist.SumW2())
   482  		}
   483  	}
   484  
   485  	oflows := h.Binning.Outflows[:]
   486  	for i, v := range []struct{ix,iy int}{
   487  		{0, 0},
   488  		{0, 1},
   489  		{0, nybins+1},
   490  		{nxbins + 1, 0},
   491  		{nxbins + 1, 1},
   492  		{nxbins + 1, nybins + 1},
   493  		{1, 0},
   494  		{1, nybins + 1},
   495  	}{
   496  		hroot.setDist2D(v.ix, v.iy, oflows[i].SumW(), oflows[i].SumW2())
   497  	}
   498  
   499  	xedges = append(xedges, bins[ibin(h.Binning.Nx-1, 0)].XMax())
   500  	yedges = append(yedges, bins[ibin(0, h.Binning.Ny-1)].YMax())
   501  
   502  	hroot.th2.th1.SetName(h.Name())
   503  	if v, ok := h.Annotation()["title"]; ok && v != nil {
   504  		hroot.th2.th1.SetTitle(v.(string))
   505  	}
   506  	hroot.th2.th1.xaxis.xbins.Data = xedges
   507  	hroot.th2.th1.yaxis.xbins.Data = yedges
   508  
   509  	return hroot
   510  }
   511  
   512  func (*{{.Name}}) RVersion() int16 {
   513  	return rvers.{{.Name}}
   514  }
   515  
   516  func (*{{.Name}}) isH2() {}
   517  
   518  // Class returns the ROOT class name.
   519  func (*{{.Name}}) Class() string {
   520  	return "T{{.Name}}"
   521  }
   522  
   523  func (h *{{.Name}}) Array() {{.Type}} {
   524  	return h.arr
   525  }
   526  
   527  // Rank returns the number of dimensions of this histogram.
   528  func (h *{{.Name}}) Rank() int {
   529  	return 2
   530  }
   531  
   532  // NbinsX returns the number of bins in X.
   533  func (h *{{.Name}}) NbinsX() int {
   534  	return h.th1.xaxis.nbins
   535  }
   536  
   537  // XAxis returns the axis along X.
   538  func (h*{{.Name}}) XAxis() Axis {
   539  	return &h.th1.xaxis
   540  }
   541  
   542  // XBinCenter returns the bin center value in X.
   543  func (h *{{.Name}}) XBinCenter(i int) float64 {
   544  	return float64(h.th1.xaxis.BinCenter(i))
   545  }
   546  
   547  // XBinContent returns the bin content value in X.
   548  func (h *{{.Name}}) XBinContent(i int) float64 {
   549  	return float64(h.arr.Data[i])
   550  }
   551  
   552  // XBinError returns the bin error in X.
   553  func (h *{{.Name}}) XBinError(i int) float64 {
   554  	if len(h.th1.sumw2.Data) > 0 {
   555  		return math.Sqrt(float64(h.th1.sumw2.Data[i]))
   556  	}
   557  	return math.Sqrt(math.Abs(float64(h.arr.Data[i])))
   558  }
   559  
   560  // XBinLowEdge returns the bin lower edge value in X.
   561  func (h *{{.Name}}) XBinLowEdge(i int) float64 {
   562  	return h.th1.xaxis.BinLowEdge(i)
   563  }
   564  
   565  // XBinWidth returns the bin width in X.
   566  func (h *{{.Name}}) XBinWidth(i int) float64 {
   567  	return h.th1.xaxis.BinWidth(i)
   568  }
   569  
   570  // NbinsY returns the number of bins in Y.
   571  func (h *{{.Name}}) NbinsY() int {
   572  	return h.th1.yaxis.nbins
   573  }
   574  
   575  // YAxis returns the axis along Y.
   576  func (h*{{.Name}}) YAxis() Axis {
   577  	return &h.th1.yaxis
   578  }
   579  
   580  // YBinCenter returns the bin center value in Y.
   581  func (h *{{.Name}}) YBinCenter(i int) float64 {
   582  	return float64(h.th1.yaxis.BinCenter(i))
   583  }
   584  
   585  // YBinContent returns the bin content value in Y.
   586  func (h *{{.Name}}) YBinContent(i int) float64 {
   587  	return float64(h.arr.Data[i])
   588  }
   589  
   590  // YBinError returns the bin error in Y.
   591  func (h *{{.Name}}) YBinError(i int) float64 {
   592  	if len(h.th1.sumw2.Data) > 0 {
   593  		return math.Sqrt(float64(h.th1.sumw2.Data[i]))
   594  	}
   595  	return math.Sqrt(math.Abs(float64(h.arr.Data[i])))
   596  }
   597  
   598  // YBinLowEdge returns the bin lower edge value in Y.
   599  func (h *{{.Name}}) YBinLowEdge(i int) float64 {
   600  	return h.th1.yaxis.BinLowEdge(i)
   601  }
   602  
   603  // YBinWidth returns the bin width in Y.
   604  func (h *{{.Name}}) YBinWidth(i int) float64 {
   605  	return h.th1.yaxis.BinWidth(i)
   606  }
   607  
   608  // bin returns the regularized bin number given an (x,y) bin index pair.
   609  func (h *{{.Name}}) bin(ix, iy int) int {
   610  	nx := h.th1.xaxis.nbins + 1 // overflow bin
   611  	ny := h.th1.yaxis.nbins + 1 // overflow bin
   612  	switch {
   613  	case ix < 0:
   614  		ix = 0
   615  	case ix > nx:
   616  		ix = nx
   617  	}
   618  	switch {
   619  	case iy < 0:
   620  		iy = 0
   621  	case iy > ny:
   622  		iy = ny
   623  	}
   624  	return ix + (nx+1)*iy
   625  }
   626  
   627  func (h *{{.Name}}) dist2D(ix, iy int) hbook.Dist2D {
   628  	i := h.bin(ix, iy)
   629  	vx := h.XBinContent(i)
   630  	xerr := h.XBinError(i)
   631  	nx := h.entries(vx, xerr)
   632  	vy := h.YBinContent(i)
   633  	yerr := h.YBinError(i)
   634  	ny := h.entries(vy, yerr)
   635  
   636  	sumw := h.arr.Data[i]
   637  	sumw2 := 0.0
   638  	if len(h.th1.sumw2.Data) > 0 {
   639  		sumw2 = h.th1.sumw2.Data[i]
   640  	}
   641  	return hbook.Dist2D{
   642  		X: hbook.Dist1D{
   643  			Dist: hbook.Dist0D{
   644  				N:     nx,
   645  				SumW:  float64(sumw),
   646  				SumW2: float64(sumw2),
   647  			},
   648  		},
   649  		Y: hbook.Dist1D{
   650  			Dist: hbook.Dist0D{
   651  				N:     ny,
   652  				SumW:  float64(sumw),
   653  				SumW2: float64(sumw2),
   654  			},
   655  		},
   656  	}
   657  }
   658  
   659  func (h *{{.Name}}) setDist2D(ix, iy int, sumw, sumw2 float64) {
   660  	i := h.bin(ix, iy)
   661  	h.arr.Data[i] = {{.Elem}}(sumw)
   662  	h.th1.sumw2.Data[i] = sumw2
   663  }
   664  
   665  func (h *{{.Name}}) entries(height, err float64) int64 {
   666  	if height <= 0 {
   667  		return 0
   668  	}
   669  	v := height / err
   670  	return int64(v*v + 0.5)
   671  }
   672  
   673  // AsH2D creates a new hbook.H2D from this ROOT histogram.
   674  func (h *{{.Name}}) AsH2D() *hbook.H2D {
   675  	var (
   676  		nx = h.NbinsX()
   677  		ny = h.NbinsY()
   678  		hh = hbook.NewH2D(
   679  			nx, h.XAxis().XMin(), h.XAxis().XMax(),
   680  			ny, h.YAxis().XMin(), h.YAxis().XMax(),
   681  		)
   682  		xinrange = 1
   683  		yinrange = 1
   684  	)
   685  	hh.Ann = hbook.Annotation{
   686  		"name":  h.Name(),
   687  		"title": h.Title(),
   688  	}
   689  	hh.Binning.Outflows = [8]hbook.Dist2D{
   690  		h.dist2D(0, 0),
   691  		h.dist2D(0, yinrange),
   692  		h.dist2D(0, ny+1),
   693  		h.dist2D(nx+1, 0),
   694  		h.dist2D(nx+1, yinrange),
   695  		h.dist2D(nx+1, ny+1),
   696  		h.dist2D(xinrange, 0),
   697  		h.dist2D(xinrange, ny+1),
   698  	}
   699  
   700  	hh.Binning.Dist = hbook.Dist2D{
   701  		X: hbook.Dist1D{
   702  			Dist: hbook.Dist0D{
   703  				N:     int64(h.Entries()),
   704  				SumW:  float64(h.SumW()),
   705  				SumW2: float64(h.SumW2()),
   706  			},
   707  		},
   708  		Y: hbook.Dist1D{
   709  			Dist: hbook.Dist0D{
   710  				N:     int64(h.Entries()),
   711  				SumW:  float64(h.SumW()),
   712  				SumW2: float64(h.SumW2()),
   713  			},
   714  		},
   715  	}
   716  	hh.Binning.Dist.X.Stats.SumWX = float64(h.SumWX())
   717  	hh.Binning.Dist.X.Stats.SumWX2 = float64(h.SumWX2())
   718  	hh.Binning.Dist.Y.Stats.SumWX = float64(h.SumWY())
   719  	hh.Binning.Dist.Y.Stats.SumWX2 = float64(h.SumWY2())
   720  	hh.Binning.Dist.Stats.SumWXY = h.SumWXY()
   721  
   722  	for ix := 0; ix < nx; ix++ {
   723  		for iy := 0; iy < ny; iy++ {
   724  			var (
   725  				i    = iy*nx + ix
   726  				xmin = h.XBinLowEdge(ix + 1)
   727  				xmax = h.XBinWidth(ix+1) + xmin
   728  				ymin = h.YBinLowEdge(iy + 1)
   729  				ymax = h.YBinWidth(iy+1) + ymin
   730  				bin  = &hh.Binning.Bins[i]
   731  			)
   732  			bin.XRange.Min = xmin
   733  			bin.XRange.Max = xmax
   734  			bin.YRange.Min = ymin
   735  			bin.YRange.Max = ymax
   736  			bin.Dist = h.dist2D(ix+1, iy+1)
   737  		}
   738  	}
   739  
   740  	return hh
   741  }
   742  
   743  // MarshalYODA implements the YODAMarshaler interface.
   744  func (h *{{.Name}}) MarshalYODA() ([]byte, error) {
   745  	return h.AsH2D().MarshalYODA()
   746  }
   747  
   748  // UnmarshalYODA implements the YODAUnmarshaler interface.
   749  func (h *{{.Name}}) UnmarshalYODA(raw []byte) error {
   750  	var hh hbook.H2D
   751  	err := hh.UnmarshalYODA(raw)
   752  	if err != nil {
   753  		return err
   754  	}
   755  
   756  	*h = *New{{.Name}}From(&hh)
   757  	return nil
   758  }
   759  
   760  func (h *{{.Name}}) MarshalROOT(w *rbytes.WBuffer) (int, error) {
   761  	if w.Err() != nil {
   762  		return 0, w.Err()
   763  	}
   764  
   765  	hdr := w.WriteHeader(h.Class(), h.RVersion())
   766  	w.WriteObject(&h.th2)
   767  	w.WriteObject(&h.arr)
   768  
   769  	return w.SetHeader(hdr)
   770  }
   771  
   772  func (h *{{.Name}}) UnmarshalROOT(r *rbytes.RBuffer) error {
   773  	if r.Err() != nil {
   774  		return r.Err()
   775  	}
   776  
   777  	hdr := r.ReadHeader(h.Class(), h.RVersion())
   778  	if hdr.Vers < 1 {
   779  		return fmt.Errorf("rhist: T{{.Name}} version too old (%d<1)", hdr.Vers)
   780  	}
   781  
   782  	r.ReadObject(&h.th2)
   783  	r.ReadObject(&h.arr)
   784  
   785  	r.CheckHeader(hdr)
   786  	return r.Err()
   787  }
   788  
   789  func (h *{{.Name}}) RMembers() (mbrs []rbytes.Member) {
   790  	mbrs = append(mbrs, h.th2.RMembers()...)
   791  	mbrs = append(mbrs, rbytes.Member{
   792  		Name: "fArray", Value: &h.arr.Data,
   793  	})
   794  	return mbrs
   795  }
   796  
   797  func init() {
   798  	f := func() reflect.Value {
   799  		o := new{{.Name}}()
   800  		return reflect.ValueOf(o)
   801  	}
   802  	rtypes.Factory.Add("T{{.Name}}", f)
   803  }
   804  
   805  var (
   806  	_ root.Object        = (*{{.Name}})(nil)
   807  	_ root.Named         = (*{{.Name}})(nil)
   808  	_ H2                 = (*{{.Name}})(nil)
   809  	_ rbytes.Marshaler   = (*{{.Name}})(nil)
   810  	_ rbytes.Unmarshaler = (*{{.Name}})(nil)
   811  	_ rbytes.RSlicer     = (*{{.Name}})(nil)
   812  )
   813  `