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 )