Back to home page

EIC code displayed by LXR

 
 

    


Warning, /firebird/firebird-ng/src/app/phoenix-overload/eic-edm4hep-json-loader.ts is written in an unsupported language. File is not indexed.

0001 import {PhoenixLoader} from "phoenix-event-display";
0002 
0003 
0004 /**
0005  * Edm4hepJsonLoader for loading EDM4hep json dumps
0006  */
0007 export class EicEdm4hepJsonLoader extends PhoenixLoader {
0008   /**  Event data loaded from EDM4hep JSON file */
0009   private rawEventData: any;
0010 
0011   /** Create Edm4hepJsonLoader */
0012   constructor() {
0013     super();
0014     this.eventData = {};
0015   }
0016 
0017   /** Put raw EDM4hep JSON event data into the loader */
0018   setRawEventData(rawEventData: any) {
0019     this.rawEventData = rawEventData;
0020   }
0021 
0022   /** Process raw EDM4hep JSON event data into the Phoenix format */
0023   processEventData(): boolean {
0024     Object.entries(this.rawEventData).forEach(([eventName, event]) => {
0025       const oneEventData = {
0026         Vertices: {},
0027         Tracks: {},
0028         Hits: {},
0029         CaloCells: {},
0030         CaloClusters: {},
0031         Jets: {},
0032         MissingEnergy: {},
0033         'event number': this.getEventNumber(event),
0034         'run number': this.getRunNumber(event),
0035       };
0036 
0037       this.colorTracks(event);
0038 
0039       oneEventData.Vertices = this.getVertices(event);
0040       oneEventData.Tracks = this.getTracks(event);
0041       oneEventData.Hits = this.getHits(event);
0042       oneEventData.CaloCells = this.getCells(event);
0043       oneEventData.CaloClusters = this.getCaloClusters(event);
0044       oneEventData.Jets = this.getJets(event);
0045       oneEventData.MissingEnergy = this.getMissingEnergy(event);
0046 
0047       this.eventData[eventName] = oneEventData;
0048     });
0049 
0050     return true;
0051   }
0052 
0053   /** Output event data in Phoenix compatible format */
0054   getEventData(): any {
0055     return this.eventData;
0056   }
0057 
0058   /** Return number of events */
0059   private getNumEvents(): number {
0060     return Object.keys(this.rawEventData).length;
0061   }
0062 
0063   /** Return run number (or 0, if not defined) */
0064   private getRunNumber(event: any): number {
0065     if (!('EventHeader' in event)) {
0066       return 0;
0067     }
0068 
0069     const eventHeader = event['EventHeader']['collection'];
0070 
0071     if (!('runNumber' in eventHeader)) {
0072       return eventHeader[0]['runNumber'];
0073     }
0074 
0075     return 0;
0076   }
0077 
0078   /** Return event number (or 0, if not defined) */
0079   private getEventNumber(event: any): number {
0080     if (!('EventHeader' in event)) {
0081       return 0;
0082     }
0083 
0084     const eventHeader = event['EventHeader']['collection'];
0085 
0086     if (!('eventNumber' in eventHeader)) {
0087       return eventHeader[0]['eventNumber'];
0088     }
0089 
0090     return 0;
0091   }
0092 
0093   /** Assign default color to Tracks*/
0094   private colorTracks(event: any) {
0095     let recoParticles: any[];
0096     if ('ReconstructedParticles' in event) {
0097       recoParticles = event['ReconstructedParticles']['collection'];
0098     } else {
0099       return;
0100     }
0101 
0102     let mcParticles: any[];
0103     if ('Particle' in event) {
0104       mcParticles = event['Particle']['collection'];
0105     } else {
0106       return;
0107     }
0108 
0109     let mcRecoAssocs: any[];
0110     if ('MCRecoAssociations' in event) {
0111       mcRecoAssocs = event['MCRecoAssociations']['collection'];
0112     } else {
0113       return;
0114     }
0115 
0116     let tracks: any[];
0117     if ('EFlowTrack' in event) {
0118       tracks = event['EFlowTrack']['collection'];
0119     } else {
0120       return;
0121     }
0122 
0123     mcRecoAssocs.forEach((mcRecoAssoc: any) => {
0124       const recoIndex = mcRecoAssoc['rec']['index'];
0125       const mcIndex = mcRecoAssoc['sim']['index'];
0126 
0127       const pdgid = mcParticles[mcIndex]['PDG'];
0128       const trackRefs = recoParticles[recoIndex]['tracks'];
0129 
0130       trackRefs.forEach((trackRef: any) => {
0131         const track = tracks[trackRef['index']];
0132         if (Math.abs(pdgid) === 11) {
0133           track['color'] = '00ff00';
0134           track['pid'] = 'electron';
0135         } else if (Math.abs(pdgid) === 22) {
0136           track['color'] = 'ff0000';
0137           track['pid'] = 'photon';
0138         } else if (Math.abs(pdgid) === 211 || Math.abs(pdgid) === 111) {
0139           track['color'] = 'a52a2a';
0140           track['pid'] = 'pion';
0141         } else if (Math.abs(pdgid) === 2212) {
0142           track['color'] = '778899';
0143           track['pid'] = 'proton';
0144         } else if (Math.abs(pdgid) === 321) {
0145           track['color'] = '5f9ea0';
0146           track['pid'] = 'kaon';
0147         } else {
0148           track['color'] = '0000cd';
0149           track['pid'] = 'other';
0150         }
0151         track['pdgid'] = pdgid;
0152       });
0153     });
0154   }
0155 
0156   /** Return the vertices */
0157   private getVertices(event: any) {
0158     const allVertices: { [key: string]: any[] } = {};
0159 
0160     for (const collName in event) {
0161       if (event[collName].constructor != Object) {
0162         continue;
0163       }
0164 
0165       const collDict = event[collName];
0166 
0167       if (!('collType' in collDict)) {
0168         continue;
0169       }
0170 
0171       if (!('collection' in collDict)) {
0172         continue;
0173       }
0174 
0175       if (!(collDict['collType'] === 'edm4hep::VertexCollection')) {
0176         continue;
0177       }
0178 
0179       const vertices: any[] = [];
0180       const rawVertices = collDict['collection'];
0181       const vertexColor = this.randomColor();
0182 
0183       rawVertices.forEach((rawVertex: any) => {
0184         const position: any[] = [];
0185         if ('position' in rawVertex) {
0186           position.push(rawVertex['position']['x']);
0187           position.push(rawVertex['position']['y']);
0188           position.push(rawVertex['position']['z']);
0189         }
0190 
0191         const vertex = {
0192           pos: position,
0193           size: 3,
0194           color: '#' + vertexColor,
0195         };
0196         vertices.push(vertex);
0197       });
0198 
0199       allVertices[collName] = vertices;
0200     }
0201 
0202     return allVertices;
0203   }
0204 
0205   /** Return tracks */
0206   private getTracks(event: any) {
0207     const allTracks: { [key: string]: any[] } = {};
0208 
0209     for (const collName in event) {
0210       if (event[collName].constructor != Object) {
0211         continue;
0212       }
0213 
0214       const collDict = event[collName];
0215 
0216       if (!('collType' in collDict)) {
0217         continue;
0218       }
0219 
0220       if (!(collDict['collType'] === 'edm4hep::TrackCollection')) {
0221         continue;
0222       }
0223 
0224       if (!('collection' in collDict)) {
0225         continue;
0226       }
0227 
0228       const rawTracks = collDict['collection'];
0229       const electrons: any[] = [];
0230       const photons: any[] = [];
0231       const pions: any[] = [];
0232       const protons: any[] = [];
0233       const kaons: any[] = [];
0234       const other: any[] = [];
0235 
0236       rawTracks.forEach((rawTrack: any) => {
0237         const positions: any[] = [];
0238         if ('trackerHits' in rawTrack) {
0239           const trackerHitRefs = rawTrack['trackerHits'];
0240           trackerHitRefs.forEach((trackerHitRef: any) => {
0241             const trackerHits = this.getCollByID(
0242               event,
0243               trackerHitRef['collectionID'],
0244             );
0245             const trackerHit = trackerHits[trackerHitRef['index']];
0246             positions.push([
0247               trackerHit['position']['x'],
0248               trackerHit['position']['y'],
0249               trackerHit['position']['z'],
0250             ]);
0251           });
0252         }
0253         if ('trackStates' in rawTrack && positions.length === 0) {
0254           const trackStates = rawTrack['trackStates'];
0255           trackStates.forEach((trackState: any) => {
0256             if ('referencePoint' in trackState) {
0257               positions.push([
0258                 trackState['referencePoint']['x'],
0259                 trackState['referencePoint']['y'],
0260                 trackState['referencePoint']['z'],
0261               ]);
0262             }
0263           });
0264         }
0265 
0266         let trackColor = '0000cd';
0267         if ('color' in rawTrack) {
0268           trackColor = rawTrack['color'];
0269         }
0270 
0271         const track = {
0272           pos: positions,
0273           color: trackColor,
0274         };
0275 
0276         if ('pid' in rawTrack) {
0277           if (rawTrack['pid'] == 'electron') {
0278             electrons.push(track);
0279           } else if (rawTrack['pid'] == 'photon') {
0280             photons.push(track);
0281           } else if (rawTrack['pid'] == 'pion') {
0282             pions.push(track);
0283           } else if (rawTrack['pid'] == 'proton') {
0284             protons.push(track);
0285           } else if (rawTrack['pid'] == 'kaon') {
0286             kaons.push(track);
0287           } else {
0288             other.push(track);
0289           }
0290         } else {
0291           other.push(track);
0292         }
0293       });
0294 
0295       allTracks[collName + ' | Electrons'] = electrons;
0296       allTracks[`${collName} | Photons`] = photons;
0297       allTracks[collName + ' | Pions'] = pions;
0298       allTracks[collName + ' | Protons'] = protons;
0299       allTracks[collName + ' | Kaons'] = kaons;
0300       allTracks[collName + ' | Other'] = other;
0301     }
0302 
0303     return allTracks;
0304   }
0305 
0306   /** Not implemented */
0307   private getHits(event: any) {
0308     const allHits: { [key: string]: any[] } = {};
0309 
0310     for (const collName in event) {
0311       if (event[collName].constructor != Object) {
0312         continue;
0313       }
0314 
0315       const collDict = event[collName];
0316 
0317       if (!('collType' in collDict)) {
0318         continue;
0319       }
0320 
0321       if (!collDict['collType'].includes('edm4hep::')) {
0322         continue;
0323       }
0324 
0325       if (!collDict['collType'].includes('TrackerHitCollection')) {
0326         continue;
0327       }
0328 
0329       if (!('collection' in collDict)) {
0330         continue;
0331       }
0332 
0333       const rawHits = collDict['collection'];
0334       const hits: any[] = [];
0335       const hitColor = this.randomColor();
0336 
0337       rawHits.forEach((rawHit: any) => {
0338         const position: any[] = [];
0339         if ('position' in rawHit) {
0340           position.push(rawHit['position']['x']);
0341           position.push(rawHit['position']['y']);
0342           position.push(rawHit['position']['z']);
0343         }
0344 
0345         const hit = {
0346           type: 'CircularPoint',
0347           pos: position,
0348           color: '#' + hitColor,
0349           size: 20,
0350         };
0351         hits.push(hit);
0352       });
0353 
0354       allHits[collName] = hits;
0355     }
0356 
0357     return allHits;
0358   }
0359 
0360   /** Returns the cells */
0361   private getCells(event: any) {
0362     const allCells: { [key: string]: any[] } = {};
0363 
0364     for (const collName in event) {
0365       if (event[collName].constructor != Object) {
0366         continue;
0367       }
0368 
0369       const collDict = event[collName];
0370 
0371       if (!('collType' in collDict)) {
0372         continue;
0373       }
0374 
0375       if (!collDict['collType'].includes('edm4hep::')) {
0376         continue;
0377       }
0378 
0379       if (!collDict['collType'].includes('CalorimeterHitCollection')) {
0380         continue;
0381       }
0382 
0383       if (!('collection' in collDict)) {
0384         continue;
0385       }
0386 
0387       const rawCells = collDict['collection'];
0388       const cells: any[] = [];
0389 
0390       // Find smallest distance between cell centers and use it as cell size
0391       let drmin = 1e9;
0392       for (let i = 0; i < 1e4; ++i) {
0393         const j = Math.floor(Math.random() * rawCells.length);
0394         const k = Math.floor(Math.random() * rawCells.length);
0395         if (j === k) {
0396           continue;
0397         }
0398 
0399         const dx2 = Math.pow(
0400           rawCells[j].position.x - rawCells[k].position.x,
0401           2,
0402         );
0403         const dy2 = Math.pow(
0404           rawCells[j].position.y - rawCells[k].position.y,
0405           2,
0406         );
0407         const dz2 = Math.pow(
0408           rawCells[j].position.z - rawCells[k].position.z,
0409           2,
0410         );
0411         const dr = Math.sqrt(dx2 + dy2 + dz2);
0412 
0413         if (dr < drmin) {
0414           drmin = dr;
0415         }
0416       }
0417       const cellSide =
0418         Math.floor(drmin) * 0.1 > 1 ? Math.floor(drmin) * 0.1 : 1;
0419       const cellsHue = Math.floor(Math.random() * 358);
0420 
0421       rawCells.forEach((rawCell: any) => {
0422         const x = rawCell.position.x;
0423         const y = rawCell.position.y;
0424         const z = rawCell.position.z;
0425 
0426         const r = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2));
0427         const rho = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
0428         const eta = Math.asinh(z / rho);
0429         const phi = Math.acos(x / rho) * Math.sign(y);
0430         const cellLightness = this.valToLightness(rawCell.energy, 1e-3, 1);
0431         const cellOpacity = this.valToOpacity(rawCell.energy, 1e-3, 1);
0432 
0433         const cell = {
0434           eta: eta,
0435           phi: phi,
0436           energy: rawCell.energy,
0437           radius: r,
0438           side: cellSide,
0439           length: cellSide, // expecting cells in multiple layers
0440           color: '#' + this.convHSLtoHEX(cellsHue, 90, cellLightness),
0441           opacity: cellOpacity,
0442         };
0443         cells.push(cell);
0444       });
0445 
0446       allCells[collName] = cells;
0447     }
0448 
0449     return allCells;
0450   }
0451 
0452   /** Return Calo clusters */
0453   private getCaloClusters(event: any) {
0454     const allClusters: { [key: string]: any[] } = {};
0455 
0456     for (const collName in event) {
0457       if (event[collName].constructor != Object) {
0458         continue;
0459       }
0460 
0461       const collDict = event[collName];
0462 
0463       if (!('collType' in collDict)) {
0464         continue;
0465       }
0466 
0467       if (!(collDict['collType'] === 'edm4hep::ClusterCollection')) {
0468         continue;
0469       }
0470 
0471       if (!('collection' in collDict)) {
0472         continue;
0473       }
0474 
0475       const rawClusters = collDict['collection'];
0476       const clusters: any[] = [];
0477 
0478       rawClusters.forEach((rawCluster: any) => {
0479         const x = rawCluster.position.x;
0480         const y = rawCluster.position.y;
0481         const z = rawCluster.position.z;
0482 
0483         const r = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2));
0484         const rho = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
0485         const eta = Math.asinh(z / rho);
0486         const phi = Math.acos(x / rho) * Math.sign(y);
0487 
0488         const cluster = {
0489           eta: eta,
0490           phi: phi,
0491           energy: rawCluster.energy * 100,
0492           radius: r,
0493           side: 40,
0494         };
0495         clusters.push(cluster);
0496       });
0497 
0498       allClusters[collName] = clusters;
0499     }
0500 
0501     return allClusters;
0502   }
0503 
0504   /** Return jets */
0505   private getJets(event: any) {
0506     const allJets: { [key: string]: any[] } = {};
0507 
0508     for (const collName in event) {
0509       if (event[collName].constructor != Object) {
0510         continue;
0511       }
0512 
0513       const collDict = event[collName];
0514 
0515       if (!('collType' in collDict)) {
0516         continue;
0517       }
0518 
0519       if (
0520         !(collDict['collType'] === 'edm4hep::ReconstructedParticleCollection')
0521       ) {
0522         continue;
0523       }
0524 
0525       if (!(collName.includes('Jet') || collName.includes('jet'))) {
0526         continue;
0527       }
0528 
0529       if (!('collection' in collDict)) {
0530         continue;
0531       }
0532 
0533       const jets: any[] = [];
0534       const rawJets = collDict['collection'];
0535 
0536       rawJets.forEach((rawJet: any) => {
0537         if (!('momentum' in rawJet)) {
0538           return;
0539         }
0540         if (!('energy' in rawJet)) {
0541           return;
0542         }
0543         const px = rawJet['momentum']['x'];
0544         const py = rawJet['momentum']['y'];
0545         const pz = rawJet['momentum']['z'];
0546 
0547         const pt = Math.sqrt(Math.pow(px, 2) + Math.pow(py, 2));
0548         const eta = Math.asinh(pz / pt);
0549         const phi = Math.acos(px / pt) * Math.sign(py);
0550 
0551         const jet = {
0552           eta: eta,
0553           phi: phi,
0554           energy: 1000 * rawJet.energy,
0555         };
0556         jets.push(jet);
0557       });
0558       allJets[collName] = jets;
0559     }
0560 
0561     return allJets;
0562   }
0563 
0564   /** Return missing energy */
0565   private getMissingEnergy(event: any) {
0566     const allMETs: { [key: string]: any[] } = {};
0567 
0568     for (const collName in event) {
0569       if (event[collName].constructor != Object) {
0570         continue;
0571       }
0572 
0573       const collDict = event[collName];
0574 
0575       if (!('collType' in collDict)) {
0576         continue;
0577       }
0578 
0579       if (
0580         !(collDict['collType'] === 'edm4hep::ReconstructedParticleCollection')
0581       ) {
0582         continue;
0583       }
0584 
0585       if (!(collName.includes('Missing') || collName.includes('missing'))) {
0586         continue;
0587       }
0588 
0589       if (!('collection' in collDict)) {
0590         continue;
0591       }
0592 
0593       const METs: any[] = [];
0594       const rawMETs = collDict['collection'];
0595       const METColor = '#ff69b4';
0596 
0597       rawMETs.forEach((rawMET: any) => {
0598         if (!('momentum' in rawMET)) {
0599           return;
0600         }
0601         if (!('energy' in rawMET)) {
0602           return;
0603         }
0604         const px = rawMET['momentum']['x'];
0605         const py = rawMET['momentum']['y'];
0606         const pz = rawMET['momentum']['z'];
0607 
0608         const p = Math.sqrt(
0609           Math.pow(px, 2) + Math.pow(py, 2) + Math.pow(pz, 2),
0610         );
0611         const etx = (rawMET['energy'] * px) / p;
0612         const ety = (rawMET['energy'] * py) / p;
0613 
0614         const MET = {
0615           etx: etx * 100,
0616           ety: ety * 100,
0617           color: '#ff69b4',
0618         };
0619         METs.push(MET);
0620       });
0621       allMETs[collName] = METs;
0622     }
0623 
0624     return allMETs;
0625   }
0626 
0627   /** Return a random colour */
0628   private randomColor() {
0629     return Math.floor(Math.random() * 16777215)
0630       .toString(16)
0631       .padStart(6, '0')
0632       .toUpperCase();
0633   }
0634 
0635   /** Helper conversion of HSL to hexadecimal */
0636   private convHSLtoHEX(h: number, s: number, l: number): string {
0637     l /= 100;
0638     const a = (s * Math.min(l, 1 - l)) / 100;
0639     const f = (n: number) => {
0640       const k = (n + h / 30) % 12;
0641       const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
0642       return Math.round(255 * color)
0643         .toString(16)
0644         .padStart(2, '0');
0645     };
0646 
0647     return `${f(0)}${f(8)}${f(4)}`;
0648   }
0649 
0650   /** Return a lightness value from the passed number and range */
0651   private valToLightness(v: number, min: number, max: number): number {
0652     let lightness = 80 - ((v - min) * 65) / (max - min);
0653     if (lightness < 20) {
0654       lightness = 20;
0655     }
0656     if (lightness > 85) {
0657       lightness = 85;
0658     }
0659 
0660     return lightness;
0661   }
0662 
0663   /** Return a opacity value from the passed number and range */
0664   private valToOpacity(v: number, min: number, max: number): number {
0665     let opacity = 0.5 + ((v - min) * 0.65) / (max - min);
0666     if (opacity < 0.5) {
0667       opacity = 0.5;
0668     }
0669     if (opacity > 1) {
0670       opacity = 1;
0671     }
0672 
0673     return opacity;
0674   }
0675 
0676   /** Get the required collection */
0677   private getCollByID(event: any, id: number) {
0678     for (const collName in event) {
0679       if (event[collName].constructor != Object) {
0680         continue;
0681       }
0682 
0683       const collDict = event[collName];
0684 
0685       if (!('collID' in collDict)) {
0686         continue;
0687       }
0688 
0689       if (collDict['collID'] === id) {
0690         return collDict['collection'];
0691       }
0692     }
0693   }
0694 }