go-hep.org/x/hep@v0.38.1/fwk/hbooksvc/hsvc.go (about) 1 // Copyright ©2017 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 hbooksvc // import "go-hep.org/x/hep/fwk/hbooksvc" 6 7 import ( 8 "fmt" 9 "os" 10 "reflect" 11 "strings" 12 "sync" 13 14 "go-hep.org/x/hep/fwk" 15 "go-hep.org/x/hep/fwk/fsm" 16 "go-hep.org/x/hep/hbook" 17 "go-hep.org/x/hep/rio" 18 ) 19 20 type h1d struct { 21 fwk.H1D 22 mu sync.RWMutex 23 } 24 25 type h2d struct { 26 fwk.H2D 27 mu sync.RWMutex 28 } 29 30 type p1d struct { 31 fwk.P1D 32 mu sync.RWMutex 33 } 34 35 type s2d struct { 36 fwk.S2D 37 mu sync.RWMutex 38 } 39 40 type hsvc struct { 41 fwk.SvcBase 42 43 h1ds map[fwk.HID]*h1d 44 h2ds map[fwk.HID]*h2d 45 p1ds map[fwk.HID]*p1d 46 s2ds map[fwk.HID]*s2d 47 48 streams map[string]Stream 49 w map[string]ostream 50 r map[string]istream 51 } 52 53 func (svc *hsvc) Configure(ctx fwk.Context) error { 54 var err error 55 56 return err 57 } 58 59 func (svc *hsvc) StartSvc(ctx fwk.Context) error { 60 var err error 61 62 for name, stream := range svc.streams { 63 switch stream.Mode { 64 case Read: 65 _, dup := svc.r[name] 66 if dup { 67 return fmt.Errorf("%s: duplicate read-stream %q", svc.Name(), name) 68 } 69 // FIXME(sbinet): handle remote/local files + protocols 70 f, err := os.Open(stream.Name) 71 if err != nil { 72 return fmt.Errorf("error opening file [%s]: %w", stream.Name, err) 73 } 74 r, err := rio.NewReader(f) 75 if err != nil { 76 return fmt.Errorf("error opening rio-stream [%s]: %w", stream.Name, err) 77 } 78 79 svc.r[name] = istream{ 80 name: name, 81 fname: stream.Name, 82 f: f, 83 r: r, 84 } 85 86 case Write: 87 _, dup := svc.w[name] 88 if dup { 89 return fmt.Errorf("%s: duplicate write-stream %q", svc.Name(), name) 90 } 91 // FIXME(sbinet): handle remote/local files + protocols 92 f, err := os.Create(stream.Name) 93 if err != nil { 94 return fmt.Errorf("error creating file [%s]: %w", stream.Name, err) 95 } 96 w, err := rio.NewWriter(f) 97 if err != nil { 98 return fmt.Errorf("error creating rio-stream [%s]: %w", stream.Name, err) 99 } 100 101 svc.w[name] = ostream{ 102 name: name, 103 fname: stream.Name, 104 f: f, 105 w: w, 106 } 107 108 default: 109 return fmt.Errorf("%s: invalid stream mode (%d)", svc.Name(), stream.Mode) 110 } 111 } 112 return err 113 } 114 115 func (svc *hsvc) StopSvc(ctx fwk.Context) error { 116 var err error 117 118 errs := make([]error, 0, len(svc.r)+len(svc.w)) 119 120 // closing write-streams 121 for n, w := range svc.w { 122 123 werr := w.write() 124 if werr != nil { 125 errs = append(errs, fmt.Errorf("error flushing %q: %w", n, werr)) 126 } 127 128 werr = w.close() 129 if werr != nil { 130 errs = append(errs, fmt.Errorf("error closing %q: %w", n, werr)) 131 } 132 } 133 134 // closing read-streams 135 for n, r := range svc.r { 136 137 rerr := r.close() 138 if rerr != nil { 139 errs = append(errs, fmt.Errorf("error closing %q: %w", n, rerr)) 140 } 141 } 142 143 if len(errs) > 0 { 144 // FIXME(sbinet): return the complete list instead of the first one. 145 // use an errlist.Error ? 146 return errs[0] 147 } 148 return err 149 } 150 151 func (svc *hsvc) BookH1D(name string, nbins int, low, high float64) (fwk.H1D, error) { 152 var err error 153 var h fwk.H1D 154 155 if !(fsm.Configured < svc.FSMState() && svc.FSMState() < fsm.Running) { 156 return h, fmt.Errorf("fwk: can not book histograms during FSM-state %v", svc.FSMState()) 157 } 158 159 stream, hid := svc.split(name) 160 h = fwk.H1D{ 161 ID: fwk.HID(hid), 162 Hist: hbook.NewH1D(nbins, low, high), 163 } 164 h.Hist.Annotation()["name"] = svc.fullname(stream, hid) 165 166 switch stream { 167 case "": 168 // ok, temporary histo. 169 default: 170 sname := "/" + stream 171 str, ok := svc.streams[sname] 172 if !ok { 173 return h, fmt.Errorf("fwk: no stream [%s] declared", sname) 174 } 175 switch str.Mode { 176 case Read: 177 r, ok := svc.r[sname] 178 if !ok { 179 return h, fmt.Errorf("fwk: no read-stream [%s] declared", sname) 180 } 181 err = r.read(hid, h.Hist) 182 if err != nil { 183 return h, err 184 } 185 186 r.objs = append(r.objs, h) 187 svc.r[sname] = r 188 189 case Write: 190 w, ok := svc.w[sname] 191 if !ok { 192 return h, fmt.Errorf("fwk: no write-stream [%s] declared: %v", sname, svc.w) 193 } 194 w.objs = append(w.objs, h) 195 svc.w[sname] = w 196 default: 197 return h, fmt.Errorf("%s: invalid stream mode (%d)", svc.Name(), str.Mode) 198 } 199 } 200 201 hh := &h1d{H1D: h} 202 svc.h1ds[h.ID] = hh 203 return hh.H1D, err 204 } 205 206 func (svc *hsvc) BookH2D(name string, nx int, xmin, xmax float64, ny int, ymin, ymax float64) (fwk.H2D, error) { 207 var err error 208 var h fwk.H2D 209 210 if !(fsm.Configured < svc.FSMState() && svc.FSMState() < fsm.Running) { 211 return h, fmt.Errorf("fwk: can not book histograms during FSM-state %v", svc.FSMState()) 212 } 213 214 stream, hid := svc.split(name) 215 h = fwk.H2D{ 216 ID: fwk.HID(hid), 217 Hist: hbook.NewH2D(nx, xmin, xmax, ny, ymin, ymax), 218 } 219 h.Hist.Annotation()["name"] = svc.fullname(stream, hid) 220 221 switch stream { 222 case "": 223 // ok, temporary histo. 224 default: 225 sname := "/" + stream 226 str, ok := svc.streams[sname] 227 if !ok { 228 return h, fmt.Errorf("fwk: no stream [%s] declared", sname) 229 } 230 switch str.Mode { 231 case Read: 232 r, ok := svc.r[sname] 233 if !ok { 234 return h, fmt.Errorf("fwk: no read-stream [%s] declared", sname) 235 } 236 err = r.read(hid, h.Hist) 237 if err != nil { 238 return h, err 239 } 240 241 r.objs = append(r.objs, h) 242 svc.r[sname] = r 243 244 case Write: 245 w, ok := svc.w[sname] 246 if !ok { 247 return h, fmt.Errorf("fwk: no write-stream [%s] declared: %v", sname, svc.w) 248 } 249 w.objs = append(w.objs, h) 250 svc.w[sname] = w 251 default: 252 return h, fmt.Errorf("%s: invalid stream mode (%d)", svc.Name(), str.Mode) 253 } 254 } 255 256 hh := &h2d{H2D: h} 257 svc.h2ds[h.ID] = hh 258 return hh.H2D, err 259 } 260 261 func (svc *hsvc) BookP1D(name string, nbins int, low, high float64) (fwk.P1D, error) { 262 var err error 263 var h fwk.P1D 264 265 if !(fsm.Configured < svc.FSMState() && svc.FSMState() < fsm.Running) { 266 return h, fmt.Errorf("fwk: can not book histograms during FSM-state %v", svc.FSMState()) 267 } 268 269 stream, hid := svc.split(name) 270 h = fwk.P1D{ 271 ID: fwk.HID(hid), 272 Profile: hbook.NewP1D(nbins, low, high), 273 } 274 h.Profile.Annotation()["name"] = svc.fullname(stream, hid) 275 276 switch stream { 277 case "": 278 // ok, temporary histo. 279 default: 280 sname := "/" + stream 281 str, ok := svc.streams[sname] 282 if !ok { 283 return h, fmt.Errorf("fwk: no stream [%s] declared", sname) 284 } 285 switch str.Mode { 286 case Read: 287 r, ok := svc.r[sname] 288 if !ok { 289 return h, fmt.Errorf("fwk: no read-stream [%s] declared", sname) 290 } 291 err = r.read(hid, h.Profile) 292 if err != nil { 293 return h, err 294 } 295 296 r.objs = append(r.objs, h) 297 svc.r[sname] = r 298 299 case Write: 300 w, ok := svc.w[sname] 301 if !ok { 302 return h, fmt.Errorf("fwk: no write-stream [%s] declared: %v", sname, svc.w) 303 } 304 w.objs = append(w.objs, h) 305 svc.w[sname] = w 306 default: 307 return h, fmt.Errorf("%s: invalid stream mode (%d)", svc.Name(), str.Mode) 308 } 309 } 310 311 hh := &p1d{P1D: h} 312 svc.p1ds[h.ID] = hh 313 return hh.P1D, err 314 } 315 316 func (svc *hsvc) BookS2D(name string) (fwk.S2D, error) { 317 var err error 318 var h fwk.S2D 319 320 if !(fsm.Configured < svc.FSMState() && svc.FSMState() < fsm.Running) { 321 return h, fmt.Errorf("fwk: can not book histograms during FSM-state %v", svc.FSMState()) 322 } 323 324 stream, hid := svc.split(name) 325 h = fwk.S2D{ 326 ID: fwk.HID(hid), 327 Scatter: hbook.NewS2D(), 328 } 329 h.Scatter.Annotation()["name"] = svc.fullname(stream, hid) 330 331 switch stream { 332 case "": 333 // ok, temporary histo. 334 default: 335 sname := "/" + stream 336 str, ok := svc.streams[sname] 337 if !ok { 338 return h, fmt.Errorf("fwk: no stream [%s] declared", sname) 339 } 340 switch str.Mode { 341 case Read: 342 r, ok := svc.r[sname] 343 if !ok { 344 return h, fmt.Errorf("fwk: no read-stream [%s] declared", sname) 345 } 346 err = r.read(hid, h.Scatter) 347 if err != nil { 348 return h, err 349 } 350 351 r.objs = append(r.objs, h) 352 svc.r[sname] = r 353 354 case Write: 355 w, ok := svc.w[sname] 356 if !ok { 357 return h, fmt.Errorf("fwk: no write-stream [%s] declared: %v", sname, svc.w) 358 } 359 w.objs = append(w.objs, h) 360 svc.w[sname] = w 361 default: 362 return h, fmt.Errorf("%s: invalid stream mode (%d)", svc.Name(), str.Mode) 363 } 364 } 365 366 hh := &s2d{S2D: h} 367 svc.s2ds[h.ID] = hh 368 return hh.S2D, err 369 } 370 371 func (svc *hsvc) fullname(stream, hid string) string { 372 if stream == "" { 373 return hid 374 } 375 return stream + "/" + hid 376 } 377 378 // split splits a booking histo name into (stream-name, histo-name). 379 // 380 // eg: "/my-stream/histo" -> ("my-stream", "histo") 381 // 382 // "my-stream/histo" -> ("my-stream", "histo") 383 // "my-stream/histo/" -> ("my-stream", "histo") 384 // "/histo" -> ("", "histo") 385 // "histo" -> ("", "histo") 386 func (svc *hsvc) split(n string) (string, string) { 387 388 n = strings.TrimPrefix(n, "/") 389 n = strings.TrimSuffix(n, "/") 390 391 o := strings.Split(n, "/") 392 switch len(o) { 393 case 0: 394 panic("impossible") 395 case 1: 396 return "", o[0] 397 case 2: 398 return o[0], o[1] 399 default: 400 return o[0], strings.Join(o[1:], "/") 401 } 402 } 403 404 func (svc *hsvc) FillH1D(id fwk.HID, x, w float64) { 405 h := svc.h1ds[id] 406 h.mu.Lock() 407 h.Hist.Fill(x, w) 408 h.mu.Unlock() 409 } 410 411 func (svc *hsvc) FillH2D(id fwk.HID, x, y, w float64) { 412 h := svc.h2ds[id] 413 h.mu.Lock() 414 h.Hist.Fill(x, y, w) 415 h.mu.Unlock() 416 } 417 418 func (svc *hsvc) FillP1D(id fwk.HID, x, y, w float64) { 419 h := svc.p1ds[id] 420 h.mu.Lock() 421 h.Profile.Fill(x, y, w) 422 h.mu.Unlock() 423 } 424 425 func (svc *hsvc) FillS2D(id fwk.HID, x, y float64) { 426 h := svc.s2ds[id] 427 h.mu.Lock() 428 // FIXME(sbinet): weight? 429 h.Scatter.Fill(hbook.Point2D{X: x, Y: y}) 430 h.mu.Unlock() 431 } 432 433 func newhsvc(typ, name string, mgr fwk.App) (fwk.Component, error) { 434 var err error 435 svc := &hsvc{ 436 SvcBase: fwk.NewSvc(typ, name, mgr), 437 streams: map[string]Stream{}, 438 w: map[string]ostream{}, 439 r: map[string]istream{}, 440 h1ds: make(map[fwk.HID]*h1d), 441 h2ds: make(map[fwk.HID]*h2d), 442 p1ds: make(map[fwk.HID]*p1d), 443 s2ds: make(map[fwk.HID]*s2d), 444 } 445 446 err = svc.DeclProp("Streams", &svc.streams) 447 if err != nil { 448 return nil, err 449 } 450 return svc, err 451 } 452 453 func init() { 454 fwk.Register(reflect.TypeOf(hsvc{}), newhsvc) 455 } 456 457 var _ fwk.HistSvc = (*hsvc)(nil)