File indexing completed on 2026-04-09 07:48:46
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 """
0022
0023 """
0024 from __future__ import print_function
0025 import os, sys, logging, numpy as np
0026 from collections import OrderedDict as odict
0027
0028 from opticks.ana.ctx import Ctx
0029 from opticks.ana.cfh import CFH
0030 from opticks.ana.base import json_save_
0031 from opticks.ana.nbase import chi2, chi2one, vnorm
0032 from opticks.ana.nload import np_load
0033 from opticks.ana.decompression import decompression_bins
0034 from opticks.ana.histype import HisType
0035 from opticks.ana.mattype import MatType
0036 from opticks.ana.evt import Evt
0037 from opticks.ana.evt import nb_
0038 from opticks.ana.abstat import ABStat
0039
0040 from opticks.ana.qdv import QDV, QDVTab
0041 from opticks.ana.make_rst_table import recarray_as_rst
0042 from opticks.ana.metadata import CompareMetadata
0043 from opticks.ana.abprofile import ABProfile
0044 from opticks.ana.absmry import ABSmry
0045 from opticks.ana.level import Level
0046
0047 log = logging.getLogger(__name__)
0048
0049 lmap = lambda *args:list(map(*args))
0050
0051 ratio_ = lambda num,den:float(num)/float(den) if den != 0 else -1
0052
0053
0054 class Maligned(object):
0055 def __init__(self, ab):
0056 self.ab = ab
0057
0058 tot = len(ab.a.seqhis)
0059 self.tot = tot
0060 self.maligned = ab.maligned
0061 self.aligned = ab.aligned
0062 self.nmal = len(ab.maligned)
0063 self.nmut = len(ab.misutailed)
0064
0065 self.fmaligned = ratio_(self.nmal, tot)
0066 self.faligned = ratio_(len(ab.aligned), tot)
0067 self.sli = slice(0,25)
0068
0069 self.migs = self.count_migtab()
0070
0071 def __getitem__(self, sli):
0072 self.sli = sli
0073 return self
0074
0075 def lines(self):
0076 return ["aligned %7d/%7d : %.4f : %s " % ( len(self.aligned), self.tot, self.faligned, ",".join(map(lambda _:"%d"%_, self.aligned[self.sli])) ),
0077 "maligned %7d/%7d : %.4f : %s " % ( len(self.maligned), self.tot, self.fmaligned, ",".join(map(lambda _:"%d"%_, self.maligned[self.sli])) ) ]
0078
0079 def label(self, q ):
0080 return "%16x %30s " % ( q, self.ab.histype.label(q) )
0081
0082 def count_migtab(self, dump=False):
0083 """
0084 Count occurrences of different history migration pairs
0085 """
0086 ab = self.ab
0087 mal = ab.maligned
0088 a = ab.a
0089 b = ab.b
0090 d = odict()
0091 for i,m in enumerate(mal):
0092 k = (a.seqhis[m],b.seqhis[m])
0093 if not k in d: d[k]=0
0094 d[k] += 1
0095 if dump:
0096 print( " %4d : %s %s " % (i, self.label(a.seqhis[m]), self.label(b.seqhis[m])) )
0097 pass
0098 pass
0099 return d
0100
0101 def migtab(self):
0102 sitems = sorted(self.migs.items(), key=lambda kv:kv[1], reverse=True)
0103 sitems = sitems[self.sli]
0104 tab = "\n".join([" %4d %s %s " % ( kv[1], self.label(kv[0][0]), self.label(kv[0][1]) ) for kv in sitems])
0105 return tab
0106
0107
0108
0109
0110
0111 def __repr__(self):
0112 return "\n".join( ["ab.mal"] + self.lines() + [repr(self.sli)]
0113 + lmap(lambda iq:self.ab.recline(iq), enumerate(self.maligned[self.sli])) + ["ab.mal.migtab"]
0114 + [self.migtab(), "."]
0115 )
0116
0117
0118
0119 class RC(object):
0120 offset = { "rpost_dv":0, "rpol_dv":1 , "ox_dv":2 }
0121
0122 def __init__(self, ab):
0123 rc = {}
0124 log.debug("[ rpost_dv ")
0125 rc["rpost_dv"] = ab.rpost_dv.RC
0126 log.debug("]")
0127
0128 log.debug("[ rpol_dv ")
0129 rc["rpol_dv"] = ab.rpol_dv.RC
0130 log.debug("]")
0131
0132 log.debug("[ ox_dv ")
0133 rc["ox_dv"] = ab.ox_dv.RC
0134 log.debug("]")
0135
0136
0137 assert max(rc.values()) <= 1
0138 irc = rc["rpost_dv"] << self.offset["rpost_dv"] | rc["rpol_dv"] << self.offset["rpol_dv"] | rc["ox_dv"] << self.offset["ox_dv"]
0139 self.rc = irc
0140
0141 levels = list(map(lambda _:_.level, list(filter(None, [ab.rpost_dv.maxlevel,ab.ox_dv.maxlevel,ab.ox_dv.maxlevel]))))
0142 level = max(levels) if len(levels) > 0 else None
0143
0144 if level is None:
0145 level = Level.MISSING
0146 pass
0147 self.level = level
0148
0149 def __repr__(self):
0150 return "RC 0x%.2x" % self.rc
0151
0152
0153
0154
0155 class AB(object):
0156 """
0157 AB : Event Pair comparison
0158 =============================
0159
0160 Selection examples::
0161
0162 ab.sel = ".6ccd"
0163 ab.sel = "TO BT BT SC .." # wildcard selection same as above
0164 ab.sel = None # back to default no selection
0165
0166 ab.aselhis = "TO BT BT SA" # with align-ment enabled
0167 # (used for non-indep photon samples, such as from emitconfig)
0168
0169 Subsequently check tables with::
0170
0171 ab.his
0172 ab.flg
0173 ab.mat
0174
0175 Histo persisting, provides random access to histos for debugging::
0176
0177 ab.sel = slice(0,1)
0178 ab.qwn = "Z"
0179 ab.irec = 5
0180
0181 h = ab.h # qwn and irec used in creation of histogram, which is persisted
0182
0183 For example, checking a hi chi2 contributor::
0184
0185 In [12]: h = ab.h
0186 [2016-11-14 12:21:43,098] p12883 {/Users/blyth/opticks/ana/ab.py:473} INFO - AB.rhist qwn T irec 5
0187 [2016-11-14 12:21:43,098] p12883 {/Users/blyth/opticks/ana/cfh.py:344} INFO - CFH.load from /tmp/blyth/opticks/CFH/concentric/1/TO_BT_BT_BT_BT_AB/5/T
0188
0189 In [13]: h.lhabc
0190 Out[13]:
0191 array([[ 2.9649, 6.9934, 0. , 0. , 0. ],
0192 [ 6.9934, 11.0218, 0. , 0. , 0. ],
0193 [ 11.0218, 15.0503, 0. , 0. , 0. ],
0194 [ 15.0503, 19.0787, 0. , 0. , 0. ],
0195 [ 19.0787, 23.1072, 14159. , 13454. , 17.9997],
0196 [ 23.1072, 27.1356, 14796. , 15195. , 5.3083],
0197 [ 27.1356, 31.164 , 0. , 0. , 0. ],
0198 [ 31.164 , 35.1925, 0. , 0. , 0. ],
0199 [ 35.1925, 39.2209, 0. , 0. , 0. ],
0200 [ 39.2209, 43.2494, 0. , 0. , 0. ]], dtype=float32)
0201
0202 """
0203 C2CUT = 30
0204 STREAM = sys.stderr
0205
0206 @classmethod
0207 def print_(cls, obj):
0208 print(str(obj), file=cls.STREAM)
0209
0210 def _get_maligned(self):
0211 return np.where(self.a.seqhis != self.b.seqhis)[0]
0212 maligned = property(_get_maligned)
0213
0214 def _get_aligned(self):
0215 return np.where(self.a.seqhis == self.b.seqhis)[0]
0216 aligned = property(_get_aligned)
0217
0218 def _get_misutailed(self):
0219 return np.where(self.a.utail != self.b.utail)[0]
0220 misutailed = property(_get_misutailed)
0221
0222 def _get_utailed(self):
0223 return np.where(self.a.utail == self.b.utail)[0]
0224 utailed = property(_get_utailed)
0225
0226
0227 def recline(self, iq, u=False):
0228 """
0229 :param iq: i,q 2-tuple of i:enumeration index 0,1,2,... and q:photon index
0230 :return line: comparing a and b seqhis labels
0231 """
0232 i, q = iq
0233 al = self.histype.label(self.a.seqhis[q])
0234 bl = self.histype.label(self.b.seqhis[q])
0235 mk = " " if al == bl else "*"
0236 head = " %6d %6d : %s : %50s %50s " % ( i, q, mk, al, bl )
0237 if u==True:
0238 u = self.u
0239 uu = u[q].ravel()
0240 ua = self.a.utail[q]
0241 ub = self.b.utail[q]
0242 wa = np.where( uu == ua )[0][0]
0243 wb = -1 if ub == 0 else np.where( uu == ub )[0][0]
0244 wd = 0 if wb == -1 else wb - wa
0245 tail = " ua %6.4f ub %6.4f wa %2d wb %2d wd %2d " % ( ua, ub, wa, wb, wd )
0246 else:
0247 tail = None
0248 pass
0249 return " ".join(filter(None, [head, tail]))
0250
0251 def dumpline(self, wh, u=False):
0252 if type(wh) is slice:
0253 start = wh.start if wh.start is not None else 0
0254 stop = wh.stop if wh.stop is not None else 1
0255 step = wh.step if wh.step is not None else 1
0256 wh = range(start,stop, step)
0257 pass
0258 self.print_( "\n".join( map(lambda iq:self.recline(iq, u=u), enumerate(wh))))
0259
0260
0261 def check_utaildebug(self):
0262 """
0263 notes/issues/ts-box-utaildebug-decouple-maligned-from-deviant.rst
0264
0265 Looking at utail mismatches that do not correspond to seqhis mismatches.
0266
0267 Hmm can use this approach to examine the random consumption of each photon
0268
0269
0270 Hmm for analysis of events created with a mask active the q will not
0271 correspond.
0272 """
0273
0274 if self.cfm.utaildebug == 0:
0275 log.debug("requires both A and B to have been run with --utaildebug option")
0276 return
0277 pass
0278
0279 mask = self.ok.mask
0280 if not mask is None:
0281 qmask = map(int, mask.split(","))
0282 assert len(qmask) == len(self.a.seqhis)
0283 else:
0284 qmask = None
0285 pass
0286
0287 u = self.u
0288 w = np.where(np.logical_and( self.a.utail != self.b.utail, self.a.seqhis == self.b.seqhis ))[0]
0289 log.debug("utail mismatch but seqhis matched u.shape:%r w.shape: %r " % (u.shape, w.shape) )
0290 for i,q in enumerate(w):
0291 q_ = q if qmask is None else qmask[q]
0292 uu = u[q_].ravel()
0293 ua = self.a.utail[q]
0294 ub = self.b.utail[q]
0295 wa = np.where( uu == ua )[0][0]
0296 wb = -1 if ub == 0 else np.where( uu == ub )[0][0]
0297 wd = 0 if wb == -1 else wb - wa
0298 print(" i %5d q_ %7d ua %10.4f ub %10.4f wa %3d wb %3d wd %3d : %s " % (i, q_, ua, ub, wa, wb, wd, self.recline((i,q)) ))
0299 pass
0300
0301
0302
0303 def dump(self):
0304 log.debug("[")
0305 if self.is_comparable:
0306 if not self.pro.missing:
0307 self.print_(self.pro)
0308 pass
0309 self.print_("#ab.cfm")
0310 self.print_(self.cfm)
0311 self.print_("#ab.mal")
0312 self.print_(self.mal)
0313 self.print_("#ab")
0314 self.print_(self)
0315 self.print_("#ab.cfm")
0316 self.print_(self.cfm)
0317 self.print_("#ab.brief")
0318 self.print_(self.brief)
0319 self.print_("#ab.rpost_dv")
0320 self.print_(self.rpost_dv)
0321 self.print_("#ab.rpol_dv")
0322 self.print_(self.rpol_dv)
0323 self.print_("#ab.ox_dv")
0324 self.print_(self.ox_dv)
0325 self.print_("#ab.brief")
0326 self.print_(self.brief)
0327 self.print_("#ab.rc_")
0328 self.print_(self.rc_)
0329 self.print_("#ab.cfm")
0330 self.print_(self.cfm)
0331 pass
0332 log.debug("]")
0333
0334
0335 def __init__(self, ok, overridetag="0"):
0336 """
0337 :param ok: arguments instance from opticks_main
0338 :param overridetag: when not "0" overrides the tags of events to be loaded NOT YET IMPLEMENTED
0339 """
0340 log.debug("[")
0341 self.ok = ok
0342 self.overridetag = overridetag
0343 self.histype = HisType()
0344 self.tabs = []
0345 self.dvtabs = []
0346 self.stream = sys.stderr
0347 self._sel = None
0348 self.dshape = None
0349
0350 self.load()
0351 self.load_u()
0352
0353 self.is_comparable = self.valid and not self.a.ph.missing and not self.b.ph.missing
0354 log.debug("[ABProfile")
0355 self.pro = ABProfile(self.a.tagdir, self.b.tagdir)
0356 log.debug("]ABProfile")
0357
0358 if self.is_comparable and ok.compare:
0359 self.cfm = self.compare_meta()
0360 self.mal = self.check_alignment()
0361 self.compare_shapes()
0362 self.compare_domains()
0363 self.compare()
0364 self.init_point()
0365
0366 log.debug("ABSmry.Make self.level : %s " % self.level)
0367
0368 self.smry = ABSmry.Make(self)
0369 self.smry.save()
0370 pass
0371 log.debug("]")
0372
0373 def load(self):
0374 """
0375 It takes aound 4s on Precision Workstation to load 1M full AB evt pair.
0376 So avoid needing to duplicate that.
0377 """
0378 pyver = "{major}.{minor}.{micro}".format(major=sys.version_info.major,minor=sys.version_info.minor,micro=sys.version_info.micro)
0379 log.debug("[ smry:%s np.__version__ %s py%s" % (self.ok.smry, np.__version__, pyver) )
0380 args = self.ok
0381
0382 if self.overridetag != "0":
0383 atag = "%s" % self.overridetag
0384 btag = "-%s" % self.overridetag
0385 elif args.utag is None:
0386 assert len(args.utags) == 2, ( "expecting 2 utags ", args.utags )
0387 atag = "%s" % args.utags[0]
0388 btag = "%s" % args.utags[1]
0389 else:
0390 atag = "%s" % args.utag
0391 btag = "-%s" % args.utag
0392 pass
0393
0394
0395 log.debug( "overridetag %s atag %s btag %s " % (self.overridetag, atag, btag) )
0396
0397 a = Evt(tag=atag, src=args.src, det=args.det, pfx=args.pfx, args=args, nom="A" )
0398 b = Evt(tag=btag, src=args.src, det=args.det, pfx=args.pfx, args=args, nom="B" )
0399
0400 pass
0401 self.a = a
0402 self.b = b
0403
0404 valid = a.valid and b.valid
0405 if not valid:
0406 log.fatal("invalid loads : a.valid:%s b.valid:%s " % (a.valid, b.valid))
0407 pass
0408 self.valid = valid
0409
0410 self.align = None
0411 self._dirty = False
0412
0413
0414 if valid:
0415 self.sel = None
0416 self.irec = 0
0417 self.qwn = "X"
0418 pass
0419 log.debug("] ")
0420
0421
0422 def _get_brief(self):
0423 abn = "AB(%s,%s,%s) %s %s %s " % (self.ok.tag, self.ok.src, self.ok.det, self.sel, self.irec, self.dshape )
0424 return abn
0425 brief = property(_get_brief)
0426
0427 def __repr__(self):
0428 abn = self.brief
0429 abr = "A %s " % self.a.brief
0430 bbr = "B %s " % self.b.brief
0431
0432 amd = ",".join(self.a.metadata.csgbnd)
0433 acsgp = self.a.metadata.TestCSGPath
0434
0435 if self.b.valid:
0436 bmd = ",".join(self.b.metadata.csgbnd)
0437 bcsgp = self.b.metadata.TestCSGPath
0438 assert amd == bmd
0439 assert acsgp == bcsgp
0440 else:
0441 pass
0442 pass
0443 return "\n".join(filter(None,["ab", abn, abr,bbr, amd, acsgp,"." ]))
0444
0445 def __str__(self):
0446 lmx = self.ok.lmx
0447 if len(self.his.lines) > lmx:
0448 self.his.sli = slice(0,lmx)
0449 if len(self.mat.lines) > lmx:
0450 self.mat.sli = slice(0,lmx)
0451 pass
0452 return "\n".join([repr(self),"#ab.ahis",repr(self.ahis),"#ab.flg",repr(self.flg),"#ab.mat",repr(self.mat)])
0453
0454
0455 def load_u(self):
0456 """
0457 This array of randoms is used by below check_utaildebug.
0458
0459 Default u array is (100k,16,16) containing doubles.
0460 To generate an extra large array (1M,16,16)::
0461
0462 TRngBuf_NI=1000000 TRngBufTest
0463
0464 Which creates a 2GB file::
0465
0466 In [6]: 16*16*1000000*8/1e9
0467 Out[6]: 2.048
0468
0469 [blyth@localhost sysrap]$ ls -l "$TMP/TRngBufTest_0_1000000.npy"
0470 -rw-rw-r--. 1 blyth blyth 2048000096 Jul 28 12:02 /home/blyth/local/opticks/tmp/TRngBufTest_0_1000000.npy
0471
0472 """
0473 log.debug("[")
0474 upath0 = "$TMP/TRngBufTest_0.npy"
0475 upath1 = "$TMP/TRngBufTest_0_1000000.npy"
0476
0477 if os.path.exists(os.path.expandvars(upath1)):
0478 upath = upath1
0479 log.debug("using the extra large random array %s " % upath )
0480 else:
0481 upath = upath0
0482 pass
0483 u,u_paths = np_load(upath)
0484 log.info("\n".join(u_paths))
0485
0486 u = None if u is None else u.astype(np.float32)
0487 self.u = u
0488 log.debug("]")
0489
0490
0491 def compare_domains(self):
0492 assert np.all( self.a.fdom == self.b.fdom )
0493 self.fdom = self.a.fdom
0494
0495 isli = slice(2,None)
0496 assert np.all( self.a.idom[isli] == self.b.idom[isli] )
0497 self.idom = self.a.idom
0498
0499 def compare_shapes(self):
0500 assert self.a.dshape == self.b.dshape, (self.a.dshape, self.b.dshape)
0501 self.dshape = self.a.dshape
0502
0503
0504 assert self.a.dsli == self.b.dsli, ( self.a.dsli, self.b.dsli )
0505 self.dsli = self.a.dsli
0506
0507
0508
0509 def compare_meta(self):
0510 cfm = CompareMetadata(self.a.metadata, self.b.metadata)
0511
0512 non_aligned_skips = "SC AB RE"
0513
0514
0515 self.dvskips = "" if cfm.align == 1 else non_aligned_skips
0516
0517 return cfm
0518
0519 def check_alignment(self):
0520 log.debug("[")
0521 mal = Maligned(self)
0522 log.debug("]")
0523 return mal
0524
0525 def compare(self):
0526 """
0527 * Taking around 5s for 1M events, all in RC
0528 * prohis and promat are progressively masked tables, not enabled by default
0529 """
0530 log.debug("[")
0531
0532 self.ahis = self._get_cf("all_seqhis_ana", "ab.ahis")
0533 self.amat = self._get_cf("all_seqmat_ana", "ab.amat")
0534
0535 if self.ok.prohis:self.prohis()
0536 if self.ok.promat:self.promat()
0537
0538 self.rc_ = RC(self)
0539
0540 log.debug("]")
0541
0542 def _get_RC(self):
0543 return self.rc_.rc if self.is_comparable else 255
0544 RC = property(_get_RC)
0545
0546 def _get_level(self):
0547 return self.rc_.level if self.is_comparable else 255
0548 level = property(_get_level)
0549
0550
0551 numPhotons = property(lambda self:self.cfm.numPhotons)
0552
0553
0554 def init_point(self):
0555 log.debug("[")
0556 self.point = self.make_point()
0557 log.debug("]")
0558
0559 def point_dtype(self):
0560 dtype=[
0561 ('irl', int),
0562 ('isel', int),
0563 ('irec', int),
0564 ('nrec', int),
0565 ('reclab', "|S64")
0566 ]
0567 return dtype
0568
0569 def _get_recpoint(self):
0570 """
0571 Returns None when single line selection is not active
0572 otherwise returns selected recpoint
0573
0574 ::
0575
0576 In [2]: ab.sel = "TO BT BT RE BT BT [SA]"
0577
0578 In [3]: ab.recpoint
0579 Out[3]: (85, 12, 6, 7, 'TO BT BT RE BT BT [SA]')
0580
0581 In [4]: ab.recpoint.isel
0582 Out[4]: 12
0583
0584 In [5]: ab.recpoint.nrec
0585 Out[5]: 7
0586
0587 In [6]: ab.recpoint.irec
0588 Out[6]: 6
0589
0590 """
0591 rl = self.reclab
0592 if rl is None:
0593 return None
0594 pass
0595 rp = self.point[self.point.reclab == rl]
0596 assert len(rp) == 1, rp
0597 return rp[0]
0598 recpoint = property(_get_recpoint)
0599
0600 def make_point(self):
0601 """
0602 :return point: recarray for holding point level metadata
0603
0604 ::
0605
0606 In [5]: print "\n".join(map(repr, ab.point[:8]))
0607 (0, 0, 0, '[TO] BT BT BT BT SA')
0608 (1, 0, 1, 'TO [BT] BT BT BT SA')
0609 (2, 0, 2, 'TO BT [BT] BT BT SA')
0610 (3, 0, 3, 'TO BT BT [BT] BT SA')
0611 (4, 0, 4, 'TO BT BT BT [BT] SA')
0612 (5, 0, 5, 'TO BT BT BT BT [SA]')
0613 (6, 1, 0, '[TO] AB')
0614 (7, 1, 1, 'TO [AB]')
0615
0616 In [6]: print "\n".join(map(repr, ab.point[-8:]))
0617 (64257, 4847, 8, 'TO RE RE RE RE BT BT BT [SC] BR BR BR BR BR BR BR')
0618 (64258, 4847, 9, 'TO RE RE RE RE BT BT BT SC [BR] BR BR BR BR BR BR')
0619 (64259, 4847, 10, 'TO RE RE RE RE BT BT BT SC BR [BR] BR BR BR BR BR')
0620 (64260, 4847, 11, 'TO RE RE RE RE BT BT BT SC BR BR [BR] BR BR BR BR')
0621 (64261, 4847, 12, 'TO RE RE RE RE BT BT BT SC BR BR BR [BR] BR BR BR')
0622 (64262, 4847, 13, 'TO RE RE RE RE BT BT BT SC BR BR BR BR [BR] BR BR')
0623 (64263, 4847, 14, 'TO RE RE RE RE BT BT BT SC BR BR BR BR BR [BR] BR')
0624 (64264, 4847, 15, 'TO RE RE RE RE BT BT BT SC BR BR BR BR BR BR [BR]')
0625
0626 """
0627 rls = self.reclabs(0,None)
0628 nrls = len(rls)
0629
0630 point = np.recarray((nrls,), dtype=self.point_dtype())
0631 point.reclab = rls
0632 point.irl = np.arange(0, nrls)
0633
0634 offset = 0
0635 for isel,clab in enumerate(self.clabels[0:None]):
0636 sls = Ctx.reclabs_(clab)
0637 nsls = len(list(sls))
0638 point.isel[offset:offset+nsls] = np.repeat( isel, nsls)
0639 point.irec[offset:offset+nsls] = np.arange( 0 , nsls)
0640 point.nrec[offset:offset+nsls] = np.repeat( nsls, nsls)
0641 offset += nsls
0642 pass
0643 return point
0644
0645
0646
0647 def prohis(self, rng=range(1,8)):
0648 log.debug("[")
0649 for imsk in rng:
0650 setattr(self, "his_%d" % imsk, self.cf("seqhis_ana_%d" % imsk))
0651 pass
0652 log.debug("]")
0653 def promat(self, rng=range(1,8)):
0654 log.debug("[")
0655 for imsk in rng:
0656 setattr(self, "mat_%d" % imsk, self.cf("seqmat_ana_%d" % imsk))
0657 pass
0658 log.debug("]")
0659
0660 def tabname(self, ana):
0661 if ana.endswith("_dv"):
0662 tn = ana + "tab"
0663 else:
0664 tn = ana.replace("_ana", "_tab")
0665 pass
0666 return tn
0667
0668 def _make_cf(self, ana, shortname):
0669 """
0670 all_ tables have no selection applied so they are not dirtied by changing selection
0671 """
0672 ordering = self.ok.cfordering
0673 assert ordering in self.ok.allowed_cfordering
0674
0675 c_tab = Evt.compare_ana( self.a, self.b, ana, lmx=self.ok.lmx, cmx=self.ok.cmx, c2max=None, cf=True, ordering=ordering, shortname=shortname )
0676 if not ana[0:3] == "all":
0677 self.tabs.append(c_tab)
0678 pass
0679 tabname = self.tabname(ana)
0680 setattr(self, tabname, c_tab)
0681 return c_tab
0682
0683
0684
0685
0686
0687
0688
0689 def _make_dv(self, ana):
0690 """
0691 :param ana: ox_dv, rpost_dv, rpol_dv
0692 """
0693 log.debug("[ %s " % ana )
0694 we = self.warn_empty
0695 self.warn_empty = False
0696 seqtab = self.ahis
0697
0698
0699
0700 use_utaildebug = self.cfm.utaildebug
0701 log.debug("_make_dv ana %s use_utaildebug %s " % (ana, use_utaildebug))
0702 dv_tab = QDVTab(ana, self, use_utaildebug=use_utaildebug )
0703 self.dvtabs.append(dv_tab)
0704
0705 self.warn_empty = we
0706 log.debug("] %s " % ana )
0707 return dv_tab
0708
0709 def _get_dv(self, ana):
0710 log.debug("[ %s " % ana )
0711 tabname = self.tabname(ana)
0712 dv_tab = getattr(self, tabname, None)
0713 if dv_tab is None:
0714 dv_tab = self._make_dv(ana)
0715 elif dv_tab.dirty:
0716 dv_tab = self._make_dv(ana)
0717 else:
0718 pass
0719 pass
0720 setattr(self, tabname, dv_tab)
0721 log.debug("] %s " % ana )
0722 return dv_tab
0723
0724
0725 def _get_ox_dv(self):
0726 return self._get_dv("ox_dv")
0727 ox_dv = property(_get_ox_dv)
0728
0729 def _get_rpost_dv(self):
0730 return self._get_dv("rpost_dv")
0731 rpost_dv = property(_get_rpost_dv)
0732
0733 def _get_rpol_dv(self):
0734 return self._get_dv("rpol_dv")
0735 rpol_dv = property(_get_rpol_dv)
0736
0737
0738 def _set_dirty(self, dirty):
0739 for tab in self.tabs:
0740 tab.dirty = dirty
0741 pass
0742 def _get_dirty(self):
0743 dtabs = filter(lambda tab:tab.dirty, self.tabs)
0744 return len(dtabs) > 0
0745 dirty = property(_get_dirty, _set_dirty)
0746
0747
0748
0749
0750 mxs = property(lambda self:dict(map(lambda _:[_.name,_.maxdvmax], self.dvtabs )))
0751 mxs_max = property(lambda self:max(self.mxs.values()))
0752
0753 rmxs = property(lambda self:dict(map(lambda _:[_.name,_.maxdvmax], filter(lambda _:_.name[0] == 'r',self.dvtabs ))))
0754 rmxs_max = property(lambda self:max(self.rmxs.values()))
0755
0756 pmxs = property(lambda self:dict(map(lambda _:[_.name,_.maxdvmax], filter(lambda _:_.name[0] != 'r',self.dvtabs ))))
0757 pmxs_max = property(lambda self:max(self.pmxs.values()))
0758
0759
0760
0761 fds = property(lambda self:dict(map(lambda _:[_.name,_.fdiscmax], self.dvtabs )))
0762 fds_max = property(lambda self:max(self.fds.values()))
0763
0764
0765 c2p = property(lambda self:dict(map(lambda _:[_.title,_.c2p], self.tabs )))
0766 c2p_max = property(lambda self:max(self.c2p.values()))
0767
0768
0769 def _get_cf(self, ana, shortname):
0770 """
0771 Changing *sel* property invokes _set_sel
0772 resulting in a change to the SeqAna in the A B Evt,
0773 thus all AB comparison tables are marked dirty, causing
0774 them to be recreated at next access.
0775 """
0776 log.debug("[ %s " % shortname )
0777 tabname = self.tabname(ana)
0778 tab = getattr(self, tabname, None)
0779 if tab is None:
0780 tab = self._make_cf(ana, shortname)
0781 elif tab.dirty:
0782 tab = self._make_cf(ana, shortname)
0783 else:
0784 pass
0785 log.debug("] %s " % shortname )
0786 return tab
0787
0788 def _get_his(self):
0789 return self._get_cf("seqhis_ana", "ab.his")
0790 def _get_mat(self):
0791 return self._get_cf("seqmat_ana", "ab.mat")
0792 def _get_flg(self):
0793 return self._get_cf("pflags_ana", "ab.flg")
0794
0795 his = property(_get_his)
0796 mat = property(_get_mat)
0797 flg = property(_get_flg)
0798
0799
0800
0801
0802 def _get_sel(self):
0803 return self._sel
0804 def _set_sel(self, sel, nom="sel"):
0805 """
0806 NB slice selection at AB level must be
0807 converted into seq string selection at evt level
0808 as the labels can diverge, expecially out in the tail
0809
0810 slice selection forces into seqhis selection
0811
0812
0813 Have observed that slice selection only works for
0814 single element slices, eg::
0815
0816 ab.sel = slice(10,11)
0817
0818 ## TODO: if that is the intent, might as well allow: ab.sel = 10
0819
0820 ::
0821
0822 ab.sel = "[TO] BT BT BT BT SA"
0823 hh = ab.hh
0824
0825 """
0826 log.debug("[ %s " % repr(sel))
0827
0828 if type(sel) is slice:
0829 clabels = self.clabels
0830 seqs = clabels[sel]
0831 assert len(seqs) == 1, seqs
0832 log.debug("AB._set_set convert slice selection %r into common label seq selection %s " % (sel, seqs[0]))
0833 sel = seqs[0]
0834 self.flv = "seqhis"
0835 pass
0836
0837 if nom == "sel":
0838 self.align = None
0839 self.a.sel = sel
0840 self.b.sel = sel
0841 elif nom == "selhis":
0842 self.align = None
0843 self.a.selhis = sel
0844 self.b.selhis = sel
0845 elif nom == "aselhis":
0846 self.align = "seqhis"
0847 self.a.selhis = sel
0848 self.b.selhis = sel
0849 elif nom == "selmat":
0850 self.align = None
0851 self.a.selmat = sel
0852 self.b.selmat = sel
0853 elif nom == "selflg":
0854 self.align = None
0855 self.a.selflg = sel
0856 self.b.selflg = sel
0857 else:
0858 assert 0, nom
0859 pass
0860
0861 self._sel = sel
0862 self.dirty = True
0863 log.debug("] %s " % repr(sel))
0864
0865 sel = property(_get_sel, _set_sel)
0866
0867 def _set_selmat(self, sel):
0868 self._set_sel( sel, nom="selmat")
0869 def _set_selhis(self, sel):
0870 self._set_sel( sel, nom="selhis")
0871 def _set_aselhis(self, sel):
0872 self._set_sel( sel, nom="aselhis")
0873 def _set_selflg(self, sel):
0874 self._set_sel( sel, nom="selflg")
0875
0876 selmat = property(_get_sel, _set_selmat)
0877 selhis = property(_get_sel, _set_selhis)
0878 selflg = property(_get_sel, _set_selflg)
0879 aselhis = property(_get_sel, _set_aselhis)
0880
0881
0882
0883
0884 def _get_align(self):
0885 return self._align
0886 def _set_align(self, align):
0887 """
0888 CAUTION: currently need to set sel after align for it to have an effect
0889 unless use aselhis
0890 """
0891 if align is None:
0892 _align = None
0893 elif type(align) is str:
0894 if align == "seqhis":
0895 _align = self.a.seqhis == self.b.seqhis
0896 else:
0897 assert False, (align, "not implemented" )
0898 else:
0899 _align = align
0900 pass
0901
0902 self._align = _align
0903 self.a.align = _align
0904 self.b.align = _align
0905 self.dirty = True
0906
0907 align = property(_get_align, _set_align)
0908
0909
0910
0911 def _set_flv(self, flv):
0912 self.a.flv = flv
0913 self.b.flv = flv
0914 def _get_flv(self):
0915 a_flv = self.a.flv
0916 b_flv = self.b.flv
0917 assert a_flv == b_flv
0918 return a_flv
0919 flv = property(_get_flv, _set_flv)
0920
0921 def _set_irec(self, irec):
0922 self.a.irec = irec
0923 self.b.irec = irec
0924 def _get_irec(self):
0925 a_irec = self.a.irec
0926 b_irec = self.b.irec
0927 assert a_irec == b_irec
0928 return a_irec
0929 irec = property(_get_irec, _set_irec)
0930
0931 def _get_reclab(self):
0932 a_reclab = self.a.reclab
0933 b_reclab = self.b.reclab
0934 assert a_reclab == b_reclab
0935 return a_reclab
0936 reclab = property(_get_reclab)
0937
0938 def _get_label0(self):
0939 a_label0 = self.a.label0
0940 b_label0 = self.b.label0
0941 assert a_label0 == b_label0
0942 return a_label0
0943 label0 = property(_get_label0)
0944
0945 def _get_seq0(self):
0946 lab0 = self.label0
0947 if lab0 is None:
0948 return None
0949 return lab0.replace(" ","_")
0950 seq0 = property(_get_seq0)
0951
0952 def count(self, line=0, col=1):
0953 """standard selects have only one sequence line"""
0954 cu = self.seq.cu
0955 if cu is None:
0956 return None
0957 pass
0958 return cu[line,col]
0959
0960 def _get_aseq(self):
0961 """
0962 aseq is not changed by the current selection
0963 """
0964 flv = self.flv
0965 if flv == "seqhis":
0966 return self.ahis
0967 elif flv == "seqmat":
0968 return self.amat
0969 else:
0970 pass
0971 return None
0972 aseq = property(_get_aseq)
0973
0974 def _get_seq(self):
0975 """
0976 seq is changed by current selection
0977 """
0978 flv = self.flv
0979 if flv == "seqhis":
0980 return self.his
0981 elif flv == "seqmat":
0982 return self.mat
0983 else:
0984 pass
0985 return None
0986 seq = property(_get_seq)
0987
0988 def _get_achi2(self):
0989 aseq = self.aseq
0990 assert not aseq is None
0991 return aseq.c2
0992 achi2 = property(_get_achi2)
0993
0994 def a_count(self, line=0):
0995 return self.count(line,1)
0996
0997 def b_count(self, line=0):
0998 return self.count(line,2)
0999
1000 def ab_count(self, line=0):
1001 ac = self.a_count(line)
1002 bc = self.b_count(line)
1003 return "%d/%d" % (ac,bc)
1004
1005 def _get_suptitle(self):
1006 abc = self.ab_count()
1007 title = "%s/%s/%s : %s : %s " % (self.ok.tag, self.ok.det, self.ok.src, abc, self.reclab )
1008 return title
1009 suptitle = property(_get_suptitle)
1010
1011 def _get_ctx(self):
1012 """
1013 hmm at some point seq0 lost its underscores
1014 """
1015 return Ctx({'det':self.ok.det, 'tag':self.ok.tag, 'src':self.ok.src, 'seq0':self.label0, 'lab':self.reclab, 'irec':self.irec, 'qwn':self.qwn })
1016 ctx = property(_get_ctx)
1017
1018 pctx = property(lambda self:self.ctx.pctx)
1019 qctx = property(lambda self:self.ctx.qctx)
1020
1021
1022 def _get_nrec(self):
1023 """
1024 :return: number of record points, when a single seq selection is active
1025 """
1026 a_nr = self.a.nrec
1027 b_nr = self.b.nrec
1028 assert a_nr == b_nr, (a_nr, b_nr, "A and B should have same nrec ?")
1029 if a_nr == b_nr and a_nr != -1:
1030 nr = a_nr
1031 else:
1032 nr = -1
1033 pass
1034 log.debug(" a_nr:%d b_nr:%d nr:%d " % (a_nr, b_nr, nr) )
1035 return nr
1036 nrec = property(_get_nrec)
1037
1038
1039 def iflg(self, flg):
1040 """
1041 :param flg: eg "SC"
1042 :return: number of record points, when a single seq selection is active
1043 """
1044 a_ifl = self.a.iflg(flg)
1045 b_ifl = self.b.iflg(flg)
1046 assert a_ifl == b_ifl, (a_ifl, b_ifl, "A and B should have same iflg ?")
1047 if a_ifl == b_ifl and a_ifl != None:
1048 ifl = a_ifl
1049 else:
1050 ifl = None
1051 pass
1052 log.debug(" a_ifl:%s b_ifl:%s ifl:%s " % (a_ifl, b_ifl, ifl) )
1053 return ifl
1054
1055 def nrecs(self, start=0, stop=None, step=1):
1056 """
1057 """
1058 sli = slice(start, stop, step)
1059 labels = self.clabels[sli]
1060 nrs = np.zeros(len(labels), dtype=np.int32)
1061 for ilab, lab in enumerate(labels):
1062 nrs[ilab] = len(lab.split())
1063 pass
1064 return nrs
1065
1066 def stats_dtype(self, qwns=None):
1067 if qwns is None:
1068 qwns = self.ok.qwns
1069 pass
1070 dtype = [(i,np.int32) for i in "iv is na nb".split()]
1071 dtype += [(s,"|S64") for s in "reclab".split()]
1072 dtype += [(q,np.float32) for q in list(qwns.replace(",",""))]
1073 dtype += [(q,np.float32) for q in "seqc2 distc2".split()]
1074 return dtype
1075
1076
1077 def reclabs(self, start=0, stop=5):
1078 """
1079 :param start: common label slice starting index
1080 :param stop: common label slice stop index, can be None
1081 :return rls: list of reclabels
1082
1083 Full reclabs is very large list::
1084
1085 In [5]: rl = ab.reclabs(0,None)
1086
1087 In [6]: len(rl)
1088 Out[6]: 64265
1089
1090 In [7]: len(ab.clabels)
1091 Out[7]: 4848
1092
1093 In [8]: 64265./4848. ## average seq0 length is 13 points
1094 Out[8]: 13.255981848184819
1095
1096 In [9]: rl[:5]
1097 Out[9]:
1098 ['[TO] BT BT BT BT SA',
1099 'TO [BT] BT BT BT SA',
1100 'TO BT [BT] BT BT SA',
1101 'TO BT BT [BT] BT SA',
1102 'TO BT BT BT [BT] SA']
1103
1104 """
1105 l = []
1106 for clab in self.clabels[start:stop]:
1107 l.extend(Ctx.reclabs_(clab))
1108 pass
1109 return l
1110
1111
1112 def stats_(self, reclabs, qwns=None, rehist=False, c2shape=True):
1113 """
1114 ::
1115
1116 st = ab.stats_(ab.point.reclab[:10])
1117
1118 """
1119 if qwns is None:
1120 qwns = self.ok.qwns
1121 pass
1122
1123 nrl = len(reclabs)
1124 stat = np.recarray((nrl,), dtype=self.stats_dtype(qwns))
1125
1126 for ival, rl in enumerate(reclabs):
1127
1128 self.sel = rl
1129
1130 rp = self.recpoint
1131
1132 isel = rp.isel
1133
1134
1135 od = odict()
1136 od["iv"] = rp.irl
1137 od["is"] = isel
1138 od["na"] = self.aseq.cu[isel,1]
1139 od["nb"] = self.aseq.cu[isel,2]
1140 od["reclab"] = rl
1141
1142 hh = self.rhist(rehist=rehist, c2shape=c2shape)
1143 qd = odict(map(lambda h:(h.qwn,h.c2p), hh))
1144 od.update(qd)
1145
1146 od["seqc2"] = self.seq.c2[0]
1147 od["distc2"] = CFH.c2per_(hh)
1148
1149 stat[ival] = tuple(od.values())
1150 pass
1151
1152 st = ABStat(stat)
1153 st.save()
1154 return st
1155
1156
1157 def stats(self, start=0, stop=5, qwns=None, rehist=False, c2shape=True):
1158 """
1159 slice selection in AB has to be converted into common seq selection
1160 in the evt
1161 """
1162 if qwns is None:
1163 qwns = self.ok.qwns
1164 pass
1165 qwns = qwns.replace(",","")
1166
1167 dtype = self.stats_dtype(qwns)
1168
1169 nrs = self.nrecs(start, stop)
1170 trs = nrs.sum()
1171
1172 log.debug("AB.stats : %s : trs %d nrs %s " % ( qwns, trs, repr(nrs)) )
1173
1174 stat = np.recarray((trs,), dtype=dtype)
1175 ival = 0
1176 for i,isel in enumerate(range(start, stop)):
1177
1178 self.sel = slice(isel, isel+1)
1179
1180 nr = self.nrec
1181 assert nrs[i] == nr, (i, nrs[i], nr )
1182
1183 for irec in range(nr):
1184
1185 self.irec = irec
1186
1187 self.qwn = qwns
1188
1189 qctx = self.qctx
1190
1191 key = self.suptitle
1192
1193 log.debug("stats irec %d nrec %d ival %d key %s qctx %s " % (irec, nr, ival, key, qctx))
1194
1195
1196
1197 od = odict()
1198 od["iv"] = ival
1199 od["is"] = isel
1200 od["na"] = self.a_count(0)
1201 od["nb"] = self.b_count(0)
1202 od["reclab"] = self.reclab
1203
1204 hh = self.rhist(qwns, irec, rehist=rehist, c2shape=c2shape)
1205 qd = odict(map(lambda h:(h.qwn,h.c2p), hh))
1206 od.update(qd)
1207
1208 od["seqc2"] = self.seq.c2[0]
1209 od["distc2"] = CFH.c2per_(hh)
1210
1211 stat[ival] = tuple(od.values())
1212 ival += 1
1213 pass
1214 pass
1215 log.debug("AB.stats histogramming done")
1216 assert ival == trs, (ival, trs )
1217
1218 st = ABStat(self.ok, stat)
1219 st.save()
1220 return st
1221
1222 def totrec(self, start=0, stop=None, step=1):
1223 """
1224 :param sli:
1225
1226 ::
1227
1228 In [2]: ab.totrec() # union of labels brings in a lot more of them
1229 Out[2]: 64265
1230
1231 In [3]: ab.a.totrec()
1232 Out[3]: 43177
1233
1234 In [4]: ab.b.totrec()
1235 Out[4]: 43085
1236
1237 """
1238 nrs = self.nrecs(start, stop, step)
1239 return int(nrs.sum())
1240
1241 def _get_clabels(self):
1242 """
1243 :return clabels: all labels of current flv
1244 """
1245 flv = self.flv
1246 if flv == "seqhis":
1247 clabels = self.ahis.labels
1248 elif flv == "seqmat":
1249 clabels = self.amat.labels
1250 else:
1251 clabels = []
1252 pass
1253 return clabels
1254 clabels = property(_get_clabels)
1255
1256 def _get_rposta_dv(self):
1257 """
1258 absolute a.rposta - b.rposta covering entire record array
1259 """
1260 return np.abs( self.a.rposta - self.b.rposta )
1261 rposta_dv = property(_get_rposta_dv)
1262
1263 def rpost(self):
1264 """
1265 Sliced decompression within a selection
1266 works via the rx replacement with rx[psel]
1267 done in Evt.init_selection.
1268 """
1269 self.checkrec()
1270 av = self.a.rpost()
1271 bv = self.b.rpost()
1272 return av, bv
1273
1274 def rpost_dv_max(self):
1275 """
1276 :return max a-b item deviations:
1277
1278 The np.amax with axis=(1,2) tuple of ints argument
1279 acts to collapse those dimensions in the aggregation
1280 """
1281 av = self.a.rpost()
1282 bv = self.b.rpost()
1283 dv = np.abs( av - bv )
1284 return dv.max(axis=(1,2))
1285
1286 def rpost_dv_where(self, cut):
1287 """
1288 :return photon indices with item deviations exceeding the cut:
1289 """
1290 av = self.a.rpost()
1291 bv = self.b.rpost()
1292 dv = np.abs( av - bv )
1293 return self.a.where[np.where(dv.max(axis=(1,2)) > cut) ]
1294
1295
1296 def rpol_dv_max(self):
1297 """
1298 :return max a-b item deviations:
1299 """
1300 av = self.a.rpol()
1301 bv = self.b.rpol()
1302 dv = np.abs( av - bv )
1303 return dv.max(axis=(1,2))
1304
1305
1306 def rpol_dv_where_(self, cut):
1307 """
1308 :return photon indices with item deviations exceeding the cut:
1309 """
1310 av = self.a.rpol()
1311 bv = self.b.rpol()
1312 dv = np.abs( av - bv )
1313 return np.where(dv.max(axis=(1,2)) > cut)
1314
1315 def rpol_dv_where(self, cut):
1316 """
1317 :return photon indices with item deviations exceeding the cut:
1318 """
1319 av = self.a.rpol()
1320 bv = self.b.rpol()
1321 dv = np.abs( av - bv )
1322 return self.a.where[np.where(dv.max(axis=(1,2)) > cut) ]
1323
1324
1325 def _set_warn_empty(self, we):
1326 self.a.warn_empty = we
1327 self.b.warn_empty = we
1328 def _get_warn_empty(self):
1329 a_we = self.a.warn_empty
1330 b_we = self.b.warn_empty
1331 assert a_we == b_we
1332 return a_we
1333 warn_empty = property(_get_warn_empty, _set_warn_empty)
1334
1335
1336 def checkrec(self,fr=0,to=0):
1337 nr = self.nrec
1338 if nr > -1 and fr < nr and to < nr:
1339 return True
1340 pass
1341 log.fatal("checkrec requires a single label selection nr %d fr %d to %d" % (nr,fr,to))
1342 return False
1343
1344 def rdir(self, fr=0, to=1):
1345 if not self.checkrec(fr,to):
1346 return None
1347 aval = self.a.rdir(fr,to)
1348 bval = self.b.rdir(fr,to)
1349 return aval, bval
1350
1351 def rpol_(self, fr):
1352 if not self.checkrec(fr):
1353 return None
1354 aval = self.a.rpol_(fr)
1355 bval = self.b.rpol_(fr)
1356 return aval, bval
1357
1358 def rpol(self):
1359 if not self.checkrec():
1360 return None
1361 aval = self.a.rpol()
1362 bval = self.b.rpol()
1363 return aval, bval
1364
1365 def rw(self):
1366 if not self.checkrec():
1367 return None
1368 aval = self.a.rw()
1369 bval = self.b.rw()
1370 return aval, bval
1371
1372
1373 @classmethod
1374 def rrandhist(cls):
1375 bn = np.linspace(-4,4,200)
1376 av = np.random.standard_normal(8000)
1377 bv = np.random.standard_normal(8000)
1378 la = ["A rand", "B rand"]
1379
1380 ctx = {}
1381 ctx["det"] = "dummy"
1382 ctx["tag"] = "1"
1383 ctx["seq"] = "dummy"
1384 ctx["qwn"] = "U"
1385 ctx["irec"] = "0"
1386
1387 cfh = CFH(ctx)
1388 cfh(bn,av,bv,la,c2cut=cls.C2CUT)
1389 return cfh
1390
1391 def _set_qwn(self, qwn):
1392 self._qwn = qwn
1393 def _get_qwn(self):
1394 return self._qwn
1395 qwn = property(_get_qwn, _set_qwn)
1396
1397 def _get_h(self):
1398 hh = self.rhist( self.qwn, self.irec)
1399 assert len(hh) == 1
1400 return hh[0]
1401 h = property(_get_h)
1402
1403 def _get_hh(self):
1404 hh = self.rhist()
1405 return hh
1406 hh = property(_get_hh)
1407
1408
1409 def rhist_(self, ctxs, rehist=False, c2shape=False):
1410 """
1411 :param ctxs: list of Ctx
1412 :param rehist: bool, when True recreate histograms, otherwise pre-persisted histos are loaded
1413
1414 Collects unique seq0 and then interactes
1415
1416 """
1417 seq0s = list(set(map(lambda ctx:ctx.seq0,ctxs)))
1418 hh = []
1419 for seq0 in seq0s:
1420 sel = seq0.replace("_", " ")
1421 log.debug("AB.rhist_ setting sel to \"%s\" rehist %d " % (sel, rehist) )
1422
1423 self.sel = sel
1424
1425 for ctx in filter(lambda ctx:ctx.seq0 == seq0, ctxs):
1426 hs = self.rhist(qwn=ctx["qwn"], irec=int(ctx["irec"]), rehist=rehist, c2shape=c2shape)
1427 assert len(hs) == 1
1428 hh.append(hs[0])
1429 pass
1430 pass
1431 return hh
1432
1433 def rhist(self, qwn=None, irec=None, rehist=False, log_=False, c2shape=True ):
1434 """
1435 :param qwn: eg "XYZT"
1436 :param irec: int
1437 :param rehist:
1438 :param log_:
1439 :param c2shape:
1440 :return hh: list of CFH persisted comparison histograms
1441 """
1442 if qwn is None:
1443 qwn = self.ok.qwns
1444 assert type(qwn) is str
1445
1446 if irec is None:
1447 irec = self.irec
1448 assert type(irec) is int
1449
1450 hh = []
1451
1452 srec = CFH.srec_(irec)
1453
1454 log.debug("AB.rhist qwn %s irec %s srec %s " % (qwn, irec, srec))
1455
1456 for ir in CFH.irec_(srec):
1457
1458 log.debug(" ir %s ir 0x%x " % (ir,ir))
1459
1460 self.irec = ir
1461
1462 for q in str(qwn):
1463
1464 self.qwn = q
1465
1466 ctx=self.ctx
1467
1468 h = CFH(ctx)
1469
1470 h.log = log_
1471
1472 if h.exists() and not rehist:
1473 h.load()
1474 else:
1475 bn, av, bv, la = self.rqwn(q, ir)
1476
1477 h(bn,av,bv,la, c2cut=self.C2CUT, c2shape=c2shape )
1478
1479 h.save()
1480 pass
1481 hh.append(h)
1482 pass
1483 pass
1484 return hh
1485
1486
1487
1488
1489
1490 def rqwn(self, qwn, irec):
1491 """
1492 :param qwn: X,Y,Z,W,T,A,B,C or R
1493 :param irec: step index 0,1,...
1494 :return binx, aval, bval, labels
1495
1496 ::
1497
1498 bi,a,b,l = cf.rqwn("T",4)
1499
1500 """
1501 a = self.a
1502 b = self.b
1503 lval = "%s[%s]" % (qwn.lower(), irec)
1504 labels = ["Op : %s" % lval, "G4 : %s" % lval]
1505
1506 if qwn == "R":
1507 apost = a.rpost_(irec)
1508 bpost = b.rpost_(irec)
1509 aval = vnorm(apost[:,:2])
1510 bval = vnorm(bpost[:,:2])
1511 cbins = a.pbins()
1512 elif qwn == "W":
1513 aval = a.recwavelength(irec)
1514 bval = b.recwavelength(irec)
1515 cbins = a.wbins()
1516 elif qwn in Evt.RPOST:
1517 q = Evt.RPOST[qwn]
1518 aval = a.rpost_(irec)[:,q]
1519 bval = b.rpost_(irec)[:,q]
1520 if qwn == "T":
1521 cbins = a.tbins()
1522 else:
1523 cbins = a.pbins()
1524 pass
1525 elif qwn in Evt.RPOL:
1526 q = Evt.RPOL[qwn]
1527 aval = a.rpol_(irec)[:,q]
1528 bval = b.rpol_(irec)[:,q]
1529 cbins = a.rpol_bins()
1530 else:
1531 assert 0, "qwn %s unknown " % qwn
1532 pass
1533
1534 binscale = Evt.RQWN_BINSCALE[qwn]
1535 bins = cbins[::binscale]
1536
1537
1538
1539
1540
1541
1542 if len(bins) == 0:
1543 raise Exception("no bins")
1544
1545 return bins, aval, bval, labels
1546
1547 def seqhis_counts(self, slot=1, labs="AB RE SC BT"):
1548 ab = self
1549 a = self.a
1550 b = self.b
1551 ac = a.seqhis_counts(slot, labs)
1552 bc = b.seqhis_counts(slot, labs)
1553 assert ac.shape == bc.shape
1554 abc = np.zeros( (2,)+ac.shape , dtype=np.int32 )
1555 abc[0] = ac
1556 abc[1] = bc
1557 return abc
1558
1559 def seqhis_splits(self, slot=1):
1560
1561 ab = self
1562 a = self.a
1563 b = self.b
1564
1565 dump = False
1566 a_uss = a.seqhis_splits(slot, dump)
1567 b_uss = b.seqhis_splits(slot, dump)
1568
1569 codes = list(set( a_uss[0] )|set( b_uss[0] ))
1570
1571 a_total = a_uss[1].sum()
1572 b_total = b_uss[1].sum()
1573 assert a_total == b_total
1574 total = a_total
1575
1576 cols = ["cod", "la","a", "af", "b", "bf", "a-b", "(a-b)^2/(a+b)" ]
1577
1578 cols_fmt = " %3s %2s %6s %10s %6s %10s %6s %13s "
1579 line_fmt = " 0x%x %2s %6d %10.3f %6d %10.3f %6d %13.3f "
1580
1581 cols_hdr = cols_fmt % tuple(cols)
1582 print( cols_hdr + " slot %d (seqhis_splits) a.itag %d b.itag %d " % (slot, a.itag, b.itag) )
1583
1584
1585 for i in range(len(codes)):
1586 code = codes[i]
1587 label = self.histype.label(code)
1588
1589 a_codes = list(a_uss[0])
1590 b_codes = list(b_uss[0])
1591
1592 a_index = a_codes.index(code) if code in a_codes else -1
1593 b_index = b_codes.index(code) if code in b_codes else -1
1594
1595 a_count = a_uss[1][a_index] if a_index > -1 else 0
1596 b_count = b_uss[1][b_index] if b_index > -1 else 0
1597
1598 ab_count = a_count - b_count
1599 c2 = chi2one(a_count, b_count)
1600
1601 a_frac = float(a_count)/float(total)
1602 b_frac = float(b_count)/float(total)
1603
1604 print( line_fmt % ( code, label, a_count, a_frac, b_count, b_frac, ab_count, c2 ))
1605 pass
1606
1607
1608
1609
1610
1611 if __name__ == '__main__':
1612 from opticks.ana.main import opticks_main
1613 ok = opticks_main()
1614 ab = AB(ok)
1615
1616 a = ab.a
1617 b = ab.b
1618 print("a.valid:%s" % a.valid)
1619 print("b.valid:%s" % b.valid)
1620 print("ab.valid:%s" % ab.valid)
1621
1622 if ok.compare:
1623 ab.dump()
1624 pass
1625
1626 als = ab.a.make_seqhis_ls() if ab.a.valid else None
1627 bls = ab.b.make_seqhis_ls() if ab.b.valid else None
1628
1629 qq={}
1630 qq["a"]="als[:10]"
1631 qq["b"]="bls[:10]"
1632 for x in ["a","b"]:
1633 e = getattr(ab,x)
1634 if e.valid:
1635 for q in qq[x].split():
1636 print(q)
1637 print(eval(q))
1638 pass
1639 pass
1640 pass
1641
1642
1643
1644
1645