File indexing completed on 2026-04-09 07:48:48
0001
0002 """
0003 GNodeLib.py
0004 =============
0005
0006 ::
0007
0008 ipython -i -- GNodeLib.py --ulv --detail
0009
0010
0011 * see also ggeo.py which provides "triplet" indexing (repeat_idx, instance_index, prim_index)
0012
0013 Geocache nodelib to load is controlled by OPTICKS_KEYDIR envvar. Set that in ~/.opticks_config with::
0014
0015 export OPTICKS_KEY=OKX4Test.X4PhysicalVolume.World0xc15cfc00x40f7000_PV.50a18baaf29b18fae8c1642927003ee3 ## example key
0016
0017 ipython -i GNodeLib.py::
0018
0019 nlib.pv
0020 nlib.lv
0021 nlib.tr
0022 nlib.id
0023 nlib.ce
0024 nlib.bb
0025
0026
0027 Info for a node identified by flat index::
0028
0029 epsilon:~ blyth$ GNodeLib.py 3154
0030 TR
0031 array([[ 0.543, -0.84 , 0. , 0. ],
0032 [ 0.84 , 0.543, 0. , 0. ],
0033 [ 0. , 0. , 1. , 0. ],
0034 [ -18079.453, -799699.44 , -7100. , 1. ]], dtype=float32)
0035
0036 BB
0037 array([[ -20576.252, -802196.25 , -9600. , 1. ],
0038 [ -15582.654, -797202.6 , -4600. , 1. ]], dtype=float32)
0039
0040 ID
0041 array([3154, 94, 18, 0], dtype=uint32)
0042
0043 CE
0044 array([ -18079.453, -799699.44 , -7100. , 2500. ], dtype=float32)
0045
0046 PV
0047 '/dd/Geometry/AD/lvADE#pvSST0xc128d900x3ef9100'
0048
0049 LV
0050 '/dd/Geometry/AD/lvSST0xc234cd00x3f0b5e0'
0051
0052
0053
0054 Can also identify nodes using LV names or PV names and control
0055 output with slice specification::
0056
0057 GNodeLib.py --lv HamamatsuR12860_PMT_20inch_body_log --sli 0:2
0058
0059 Dump a list of unique LV names with::
0060
0061 GNodeLib.py --ulv
0062
0063
0064
0065 """
0066 import os, json, numpy as np, argparse, logging
0067 log = logging.getLogger(__name__)
0068
0069 from opticks.ana.key import key_
0070
0071 class Txt(list):
0072 def __init__(self, *args, **kwa):
0073 list.__init__(self, *args, **kwa)
0074 def __repr__(self):
0075 return "Txt:%d" % len(self)
0076
0077 txt_load = lambda _:Txt(map(str.strip, open(_).readlines()))
0078
0079
0080
0081 class Node(object):
0082 def __init__(self, nlib, idx):
0083 self.nlib = nlib
0084 self.idx = idx
0085 def __repr__(self):
0086 return "### Node idx:%d " % self.idx
0087 def __str__(self):
0088 return "\n".join([repr(self),""]+list(map(lambda k:"%2s\n%r\n" % (k, getattr(self.nlib,k.lower())[idx]), self.nlib.k2name.keys())))
0089
0090
0091 class GNodeLib(object):
0092 KEY = key_(os.environ["OPTICKS_KEY"])
0093 KEYDIR = KEY.keydir
0094 RELDIR = "GNodeLib"
0095 k2name = {
0096 "TR":"all_volume_transforms.npy",
0097 "BB":"all_volume_bbox.npy",
0098 "ID":"all_volume_identity.npy",
0099 "NI":"all_volume_nodeinfo.npy",
0100 "CE":"all_volume_center_extent.npy",
0101 "PV":"all_volume_PVNames.txt",
0102 "LV":"all_volume_LVNames.txt",
0103 }
0104
0105 @classmethod
0106 def Path(cls, k):
0107 keydir = cls.KEYDIR
0108 reldir = cls.RELDIR
0109 name = cls.k2name[k]
0110 return os.path.expandvars("{keydir}/{reldir}/{name}".format(**locals()))
0111
0112 @classmethod
0113 def Load(cls, k):
0114 path = cls.Path(k)
0115 return np.load(path) if path[-4:] == ".npy" else np.loadtxt(path, dtype="|S100" )
0116
0117 def pvfind(self, pvname_start, encoding='utf-8'):
0118 """
0119 :param pvname_start: string start of PV name
0120 :return indices: array of matching indices in pv name array (all nodes)
0121 """
0122 return np.flatnonzero(np.char.startswith(self.pv, pvname_start.encode(encoding)))
0123
0124 def lvfind(self, lvname_start, encoding='utf-8'):
0125 """
0126 :param lvname_start: string start of LV name
0127 :return indices: array of matching indices in lv name array (all nodes: so will be many repeats)
0128 """
0129 return np.flatnonzero(np.char.startswith(self.lv, lvname_start.encode(encoding)))
0130
0131 def __init__(self):
0132 for k in self.k2name.keys():
0133 setattr( self, k.lower(), self.Load(k) )
0134 pass
0135 self.lvidx = (( self.id[:,2] >> 16) & 0xffff )
0136 self.bnidx = (( self.id[:,2] >> 0) & 0xffff )
0137
0138 def __str__(self):
0139 return "\n".join(map(lambda k:"%2s\n%r\n" % (k, getattr(self,k.lower())), self.k2name.keys()))
0140
0141 def __getitem__(self, idx):
0142 return Node(self, idx)
0143
0144
0145 def slice_(sli):
0146 elem = []
0147 for s in sli.split(":"):
0148 try:
0149 elem.append(int(s))
0150 except ValueError:
0151 elem.append(None)
0152 pass
0153 return slice(*elem)
0154
0155
0156 def parse_args(doc, **kwa):
0157 np.set_printoptions(suppress=True, precision=3, linewidth=200)
0158 parser = argparse.ArgumentParser(doc)
0159 parser.add_argument( "idx", type=int, nargs="*", help="Node index to dump.")
0160 parser.add_argument( "--level", default="info", help="logging level" )
0161 parser.add_argument( "--pv", default=None, help="PV name to search for" )
0162 parser.add_argument( "--lv", default=None, help="LV name to search for" )
0163 parser.add_argument( "--ulv", default=False, action="store_true", help="Dump unique LV names" )
0164 parser.add_argument( "--sli", default="0:10:1", help="Array slice to control output, 0:None for all" )
0165 parser.add_argument( "--ce", default=False, action="store_true", help="Dump just center_extent" )
0166 parser.add_argument( "--detail", default=False, action="store_true", help="Dump extra details" )
0167 parser.add_argument( "-d","--dump", action="store_true", help="Dump lib repr" )
0168 args = parser.parse_args()
0169 fmt = '[%(asctime)s] p%(process)s {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s'
0170 logging.basicConfig(level=getattr(logging,args.level.upper()), format=fmt)
0171 args.slice = slice_(args.sli)
0172 return args
0173
0174 if __name__ == '__main__':
0175 args = parse_args(__doc__)
0176 print(repr(GNodeLib.KEY))
0177 nlib = GNodeLib()
0178 if args.dump:
0179 print(nlib)
0180 pass
0181 for idx in args.idx:
0182 nd = nlib[idx]
0183 print(nd)
0184 pass
0185
0186 idxs = []
0187 if args.pv:
0188 idxs = nlib.pvfind(args.pv)
0189 print("args.pv:%s matched %d nodes " % (args.pv, len(idxs)))
0190 elif args.lv:
0191 idxs = nlib.lvfind(args.lv)
0192 print("args.lv:%s matched %d nodes " % (args.lv, len(idxs)))
0193 elif args.ulv:
0194 ulv, ulv_count = np.unique(nlib.lv, return_counts=True)
0195 print("args.ulv found %d unique LV names" % (len(ulv)))
0196 print("\n".join(list(map(lambda _:_.decode('utf-8'),ulv[args.slice]))))
0197 print("unique lv in descending count order, with names of first few corresponding pv ")
0198 for i in sorted(range(len(ulv)),key=lambda i:ulv_count[i], reverse=True):
0199 detail = ""
0200 if args.detail:
0201 w = np.where( nlib.lv == ulv[i] )
0202 pv = nlib.pv[w][:3]
0203 detail = " ".join(list(map(lambda _:_.decode("utf-8"), pv )))
0204 pass
0205 print("%10d : %50s : %s " % (ulv_count[i], ulv[i].decode("utf-8"), detail ))
0206 pass
0207 pass
0208
0209 print("slice %s " % args.sli)
0210
0211 print(idxs[args.slice])
0212 for idx in idxs[args.slice]:
0213 if args.ce:
0214 print(nlib.ce[idx])
0215 else:
0216 nd = nlib[idx]
0217 print(nd)
0218 pass
0219 pass
0220
0221