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

     1  // Copyright ©2022 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  package rhist
     6  
     7  import (
     8  	"fmt"
     9  	"reflect"
    10  	"strings"
    11  
    12  	"go-hep.org/x/hep/groot/rbase"
    13  	"go-hep.org/x/hep/groot/rbytes"
    14  	"go-hep.org/x/hep/groot/root"
    15  	"go-hep.org/x/hep/groot/rtypes"
    16  	"go-hep.org/x/hep/groot/rvers"
    17  )
    18  
    19  // F1 is a ROOT 1-dim function.
    20  type F1 struct {
    21  	named   rbase.Named
    22  	attline rbase.AttLine
    23  	attfill rbase.AttFill
    24  	attmark rbase.AttMarker
    25  
    26  	xmin   float64 // Lower bounds for the range
    27  	xmax   float64 // Upper bounds for the range
    28  	npar   int32   // Number of parameters
    29  	ndim   int32   // Function dimension
    30  	npx    int32   // Number of points used for the graphical representation
    31  	typ    int32
    32  	npfits int32   // Number of points used in the fit
    33  	ndf    int32   // Number of degrees of freedom in the fit
    34  	chi2   float64 // Function fit chisquare
    35  	fmin   float64 // Minimum value for plotting
    36  	fmax   float64 // Maximum value for plotting
    37  
    38  	parErrs []float64 // Array of errors of the fNpar parameters
    39  	parMin  []float64 // Array of lower limits of the fNpar parameters
    40  	parMax  []float64 // Array of upper limits of the fNpar parameters
    41  	save    []float64 // Array of fNsave function values
    42  
    43  	normalized   bool    // Normalization option (false by default)
    44  	normIntegral float64 // Integral of the function before being normalized
    45  
    46  	formula *Formula // Pointer to TFormula in case when user define formula
    47  
    48  	params *F1Parameters // Pointer to Function parameters object (exists only for not-formula functions)
    49  	compos F1Composition // saved pointer (unique_ptr is transient)
    50  
    51  }
    52  
    53  func newF1() *F1 {
    54  	return &F1{
    55  		named:   *rbase.NewNamed("", ""),
    56  		attline: *rbase.NewAttLine(),
    57  		attfill: *rbase.NewAttFill(),
    58  		attmark: *rbase.NewAttMarker(),
    59  	}
    60  }
    61  
    62  func (*F1) RVersion() int16 {
    63  	return rvers.F1
    64  }
    65  
    66  func (*F1) Class() string {
    67  	return "TF1"
    68  }
    69  
    70  // Name returns the name of the instance
    71  func (f *F1) Name() string {
    72  	return f.named.Name()
    73  }
    74  
    75  // Title returns the title of the instance
    76  func (f *F1) Title() string {
    77  	return f.named.Title()
    78  }
    79  
    80  // MarshalROOT implements rbytes.Marshaler
    81  func (f *F1) MarshalROOT(w *rbytes.WBuffer) (int, error) {
    82  	if w.Err() != nil {
    83  		return 0, w.Err()
    84  	}
    85  
    86  	hdr := w.WriteHeader(f.Class(), f.RVersion())
    87  	w.WriteObject(&f.named)
    88  	w.WriteObject(&f.attline)
    89  	w.WriteObject(&f.attfill)
    90  	w.WriteObject(&f.attmark)
    91  
    92  	w.WriteF64(f.xmin)
    93  	w.WriteF64(f.xmax)
    94  	w.WriteI32(f.npar)
    95  	w.WriteI32(f.ndim)
    96  	w.WriteI32(f.npx)
    97  	w.WriteI32(f.typ)
    98  	w.WriteI32(f.npfits)
    99  	w.WriteI32(f.ndf)
   100  	w.WriteF64(f.chi2)
   101  	w.WriteF64(f.fmin)
   102  	w.WriteF64(f.fmax)
   103  
   104  	w.WriteStdVectorF64(f.parErrs)
   105  	w.WriteStdVectorF64(f.parMin)
   106  	w.WriteStdVectorF64(f.parMax)
   107  	w.WriteStdVectorF64(f.save)
   108  
   109  	w.WriteBool(f.normalized)
   110  	w.WriteF64(f.normIntegral)
   111  
   112  	w.WriteObjectAny(f.formula)
   113  	w.WriteObjectAny(f.params)
   114  	w.WriteObjectAny(f.compos)
   115  
   116  	return w.SetHeader(hdr)
   117  }
   118  
   119  func (f *F1) UnmarshalROOT(r *rbytes.RBuffer) error {
   120  	if r.Err() != nil {
   121  		return r.Err()
   122  	}
   123  
   124  	hdr := r.ReadHeader(f.Class(), f.RVersion())
   125  
   126  	if hdr.Vers < 10 {
   127  		// tested with v10.
   128  		panic(fmt.Errorf("rhist: invalid TF1 version=%d < 10", hdr.Vers))
   129  	}
   130  
   131  	r.ReadObject(&f.named)
   132  	r.ReadObject(&f.attline)
   133  	r.ReadObject(&f.attfill)
   134  	r.ReadObject(&f.attmark)
   135  
   136  	f.xmin = r.ReadF64()
   137  	f.xmax = r.ReadF64()
   138  	f.npar = r.ReadI32()
   139  	f.ndim = r.ReadI32()
   140  	f.npx = r.ReadI32()
   141  	f.typ = r.ReadI32()
   142  	f.npfits = r.ReadI32()
   143  	f.ndf = r.ReadI32()
   144  	f.chi2 = r.ReadF64()
   145  	f.fmin = r.ReadF64()
   146  	f.fmax = r.ReadF64()
   147  
   148  	r.ReadStdVectorF64(&f.parErrs)
   149  	r.ReadStdVectorF64(&f.parMin)
   150  	r.ReadStdVectorF64(&f.parMax)
   151  	r.ReadStdVectorF64(&f.save)
   152  
   153  	f.normalized = r.ReadBool()
   154  	f.normIntegral = r.ReadF64()
   155  
   156  	if obj := r.ReadObjectAny(); obj != nil {
   157  		f.formula = obj.(*Formula)
   158  	}
   159  
   160  	if obj := r.ReadObjectAny(); obj != nil {
   161  		f.params = obj.(*F1Parameters)
   162  	}
   163  
   164  	if obj := r.ReadObjectAny(); obj != nil {
   165  		f.compos = obj.(F1Composition)
   166  	}
   167  
   168  	r.CheckHeader(hdr)
   169  	return r.Err()
   170  }
   171  
   172  func (f *F1) String() string {
   173  	switch {
   174  	case f.formula != nil:
   175  		return fmt.Sprintf("TF1{Formula: %v}", f.formula)
   176  	case f.params != nil:
   177  		return fmt.Sprintf("TF1{Params: %v}", f.params)
   178  	default:
   179  		return "TF1{...}"
   180  	}
   181  }
   182  
   183  type F1Parameters struct {
   184  	params []float64
   185  	names  []string
   186  }
   187  
   188  func (*F1Parameters) RVersion() int16 {
   189  	return rvers.F1Parameters
   190  }
   191  
   192  func (*F1Parameters) Class() string {
   193  	return "TF1Parameters"
   194  }
   195  
   196  func (f *F1Parameters) UnmarshalROOT(r *rbytes.RBuffer) error {
   197  	if r.Err() != nil {
   198  		return r.Err()
   199  	}
   200  
   201  	hdr := r.ReadHeader(f.Class(), f.RVersion())
   202  
   203  	if hdr.Vers < 1 {
   204  		// tested with v1.
   205  		panic(fmt.Errorf("rhist: invalid TF1Parameters version=%d < 1", hdr.Vers))
   206  	}
   207  
   208  	r.ReadStdVectorF64(&f.params)
   209  	r.ReadStdVectorStrs(&f.names)
   210  
   211  	r.CheckHeader(hdr)
   212  	return r.Err()
   213  }
   214  
   215  func (f *F1Parameters) String() string {
   216  	return fmt.Sprintf(
   217  		"TF1Parameters{Values: %v, Names: %v}",
   218  		f.params,
   219  		f.names,
   220  	)
   221  }
   222  
   223  type f1Composition struct {
   224  	base rbase.Object
   225  }
   226  
   227  func (*f1Composition) RVersion() int16 {
   228  	return rvers.F1AbsComposition
   229  }
   230  
   231  func (*f1Composition) Class() string {
   232  	return "TF1AbsComposition"
   233  }
   234  
   235  func (*f1Composition) isF1Composition() {}
   236  
   237  func (f *f1Composition) UnmarshalROOT(r *rbytes.RBuffer) error {
   238  	if r.Err() != nil {
   239  		return r.Err()
   240  	}
   241  
   242  	hdr := r.ReadHeader(f.Class(), f.RVersion())
   243  
   244  	if hdr.Vers < 1 {
   245  		// tested with v1.
   246  		panic(fmt.Errorf("rhist: invalid TF1AbsComposition version=%d < 1", hdr.Vers))
   247  	}
   248  
   249  	r.ReadObject(&f.base)
   250  
   251  	r.CheckHeader(hdr)
   252  	return r.Err()
   253  }
   254  
   255  // F1Convolution is a ROOT composition function describing a
   256  // convolution between two TF1 ROOT functions.
   257  type F1Convolution struct {
   258  	base f1Composition
   259  
   260  	func1 F1 // First function to be convolved
   261  	func2 F1 // Second function to be convolved
   262  
   263  	params1  []float64
   264  	params2  []float64
   265  	parNames []string // Parameters' names
   266  
   267  	xmin     float64 // Minimal bound of the range of the convolution
   268  	xmax     float64 // Maximal bound of the range of the convolution
   269  	nParams1 int32
   270  	nParams2 int32
   271  	cstIndex int32 // Index of the constant parameter f the first function
   272  	nPoints  int32 // Number of point for FFT array
   273  	flagFFT  bool  // Choose FFT or numerical convolution
   274  }
   275  
   276  func (*F1Convolution) RVersion() int16 {
   277  	return rvers.F1Convolution
   278  }
   279  
   280  func (*F1Convolution) Class() string {
   281  	return "TF1Convolution"
   282  }
   283  
   284  func (*F1Convolution) isF1Composition() {}
   285  
   286  func (f *F1Convolution) UnmarshalROOT(r *rbytes.RBuffer) error {
   287  	if r.Err() != nil {
   288  		return r.Err()
   289  	}
   290  
   291  	hdr := r.ReadHeader(f.Class(), f.RVersion())
   292  
   293  	if hdr.Vers < 1 {
   294  		// tested with v1.
   295  		panic(fmt.Errorf("rhist: invalid TF1Convolution version=%d < 1", hdr.Vers))
   296  	}
   297  
   298  	r.ReadObject(&f.base)
   299  
   300  	for i, v := range []*F1{&f.func1, &f.func2} {
   301  		obj := r.ReadObjectAny()
   302  		if obj == nil {
   303  			r.SetErr(fmt.Errorf("rhist: could not read fFunction%d TF1 of TF1Convolution", i+1))
   304  			return r.Err()
   305  		}
   306  		*v = *(obj.(*F1))
   307  	}
   308  
   309  	r.ReadStdVectorF64(&f.params1)
   310  	r.ReadStdVectorF64(&f.params2)
   311  	r.ReadStdVectorStrs(&f.parNames)
   312  
   313  	f.xmin = r.ReadF64()
   314  	f.xmax = r.ReadF64()
   315  	f.nParams1 = r.ReadI32()
   316  	f.nParams2 = r.ReadI32()
   317  	f.cstIndex = r.ReadI32()
   318  	f.nPoints = r.ReadI32()
   319  	f.flagFFT = r.ReadBool()
   320  
   321  	r.CheckHeader(hdr)
   322  	return r.Err()
   323  }
   324  
   325  func (f *F1Convolution) String() string {
   326  	return fmt.Sprintf(
   327  		"TF1Convolution{Func1: %v, Func2: %v}",
   328  		f.func1.String(),
   329  		f.func2.String(),
   330  	)
   331  }
   332  
   333  // F1NormSum is a ROOT composition function describing the linear
   334  // combination of two TF1 ROOT functions.
   335  type F1NormSum struct {
   336  	base f1Composition
   337  
   338  	nFuncs uint32  // Number of functions to add
   339  	scale  float64 // Fixed Scale parameter to normalize function (e.g. bin width)
   340  	xmin   float64 // Minimal bound of range of NormSum
   341  	xmax   float64 // Maximal bound of range of NormSum
   342  
   343  	funcs      []*F1     // Vector of size fNOfFunctions containing TF1 functions
   344  	coeffs     []float64 // Vector of size fNOfFunctions containing coefficients in front of each function
   345  	cstIndices []int32   // Vector with size of fNOfFunctions containing the index of the constant parameter/ function (the removed ones)
   346  	parNames   []string  // Parameter names
   347  }
   348  
   349  func (*F1NormSum) RVersion() int16 {
   350  	return rvers.F1NormSum
   351  }
   352  
   353  func (*F1NormSum) Class() string {
   354  	return "TF1NormSum"
   355  }
   356  
   357  func (*F1NormSum) isF1Composition() {}
   358  
   359  func (f *F1NormSum) UnmarshalROOT(r *rbytes.RBuffer) error {
   360  	if r.Err() != nil {
   361  		return r.Err()
   362  	}
   363  
   364  	hdr := r.ReadHeader(f.Class(), f.RVersion())
   365  
   366  	if hdr.Vers < 1 {
   367  		// tested with v1.
   368  		panic(fmt.Errorf("rhist: invalid TF1NormSum version=%d < 1", hdr.Vers))
   369  	}
   370  
   371  	r.ReadObject(&f.base)
   372  
   373  	f.nFuncs = r.ReadU32()
   374  	f.scale = r.ReadF64()
   375  	f.xmin = r.ReadF64()
   376  	f.xmax = r.ReadF64()
   377  
   378  	readF1s(r, &f.funcs)
   379  	r.ReadStdVectorF64(&f.coeffs)
   380  	r.ReadStdVectorI32(&f.cstIndices)
   381  	r.ReadStdVectorStrs(&f.parNames)
   382  
   383  	r.CheckHeader(hdr)
   384  	return r.Err()
   385  }
   386  
   387  func (f *F1NormSum) String() string {
   388  	o := new(strings.Builder)
   389  	o.WriteString("TF1Convolution{Funcs: []{")
   390  	for i, fct := range f.funcs {
   391  		if i > 0 {
   392  			o.WriteString(", ")
   393  		}
   394  		o.WriteString(fct.String())
   395  	}
   396  	o.WriteString("}, Coeffs: ")
   397  	fmt.Fprintf(o, "%v", f.coeffs)
   398  	o.WriteString("}")
   399  	return o.String()
   400  }
   401  
   402  func readF1s(r *rbytes.RBuffer, sli *[]*F1) {
   403  	if r.Err() != nil {
   404  		return
   405  	}
   406  
   407  	hdr := r.ReadHeader("vector<TF1*>", rvers.StreamerBaseSTL)
   408  
   409  	n := int(r.ReadI32())
   410  	{
   411  		if m := cap(*sli); m < n {
   412  			*sli = (*sli)[:m]
   413  			*sli = append(*sli, make([]*F1, n-m)...)
   414  		}
   415  		*sli = (*sli)[:n]
   416  
   417  	}
   418  	for i := range *sli {
   419  		obj := r.ReadObjectAny()
   420  		if obj == nil {
   421  			(*sli)[i] = nil
   422  			continue
   423  		}
   424  		(*sli)[i] = obj.(*F1)
   425  	}
   426  
   427  	r.CheckHeader(hdr)
   428  }
   429  
   430  func init() {
   431  	{
   432  		f := func() reflect.Value {
   433  			o := newF1()
   434  			return reflect.ValueOf(o)
   435  		}
   436  		rtypes.Factory.Add("TF1", f)
   437  	}
   438  	{
   439  		f := func() reflect.Value {
   440  			o := new(F1Parameters)
   441  			return reflect.ValueOf(o)
   442  		}
   443  		rtypes.Factory.Add("TF1Parameters", f)
   444  	}
   445  	{
   446  		f := func() reflect.Value {
   447  			o := new(f1Composition)
   448  			return reflect.ValueOf(o)
   449  		}
   450  		rtypes.Factory.Add("TF1AbsComposition", f)
   451  	}
   452  	{
   453  		f := func() reflect.Value {
   454  			o := new(F1Convolution)
   455  			return reflect.ValueOf(o)
   456  		}
   457  		rtypes.Factory.Add("TF1Convolution", f)
   458  	}
   459  	{
   460  		f := func() reflect.Value {
   461  			o := new(F1NormSum)
   462  			return reflect.ValueOf(o)
   463  		}
   464  		rtypes.Factory.Add("TF1NormSum", f)
   465  	}
   466  }
   467  
   468  var (
   469  	_ root.Object        = (*F1)(nil)
   470  	_ root.Named         = (*F1)(nil)
   471  	_ rbytes.Marshaler   = (*F1)(nil)
   472  	_ rbytes.Unmarshaler = (*F1)(nil)
   473  
   474  	_ root.Object        = (*F1Parameters)(nil)
   475  	_ rbytes.Unmarshaler = (*F1Parameters)(nil)
   476  
   477  	_ root.Object        = (*f1Composition)(nil)
   478  	_ rbytes.Unmarshaler = (*f1Composition)(nil)
   479  	_ F1Composition      = (*f1Composition)(nil)
   480  
   481  	_ root.Object        = (*F1Convolution)(nil)
   482  	_ rbytes.Unmarshaler = (*F1Convolution)(nil)
   483  	_ F1Composition      = (*F1Convolution)(nil)
   484  
   485  	_ root.Object        = (*F1NormSum)(nil)
   486  	_ rbytes.Unmarshaler = (*F1NormSum)(nil)
   487  	_ F1Composition      = (*F1NormSum)(nil)
   488  )