From 8901c621871074aed481fbb5048eeee2fee321e5 Mon Sep 17 00:00:00 2001 From: Juraj Smiesko Date: Wed, 9 Aug 2023 18:16:04 +0200 Subject: [PATCH 1/3] Adding arrows to visualize MC particles --- .../src/loaders/edm4hep-json-loader.ts | 62 +++++++++++ .../src/loaders/objects/phoenix-objects.ts | 100 +++++++++++++++++- .../src/loaders/phoenix-loader.ts | 26 +++++ 3 files changed, 186 insertions(+), 2 deletions(-) diff --git a/packages/phoenix-event-display/src/loaders/edm4hep-json-loader.ts b/packages/phoenix-event-display/src/loaders/edm4hep-json-loader.ts index 67722fb7..d4a058c2 100644 --- a/packages/phoenix-event-display/src/loaders/edm4hep-json-loader.ts +++ b/packages/phoenix-event-display/src/loaders/edm4hep-json-loader.ts @@ -29,6 +29,7 @@ export class Edm4hepJsonLoader extends PhoenixLoader { CaloClusters: {}, Jets: {}, MissingEnergy: {}, + MCParticles: {}, 'event number': this.getEventNumber(event), 'run number': this.getRunNumber(event), }; @@ -42,6 +43,7 @@ export class Edm4hepJsonLoader extends PhoenixLoader { oneEventData.CaloClusters = this.getCaloClusters(event); oneEventData.Jets = this.getJets(event); oneEventData.MissingEnergy = this.getMissingEnergy(event); + oneEventData.MCParticles = this.getMCParticles(event); this.eventData[eventName] = oneEventData; }); @@ -621,6 +623,66 @@ export class Edm4hepJsonLoader extends PhoenixLoader { return allMETs; } + /** Returns Monte Carlo particles */ + private getMCParticles(event: any) { + const allParticles: any[] = []; + + for (const collName in event) { + if (event[collName].constructor != Object) { + continue; + } + + const collDict = event[collName]; + + if (!('collType' in collDict)) { + continue; + } + + if (!collDict['collType'].includes('edm4hep::')) { + continue; + } + + if (!collDict['collType'].includes('MCParticleCollection')) { + continue; + } + + if (!('collection' in collDict)) { + continue; + } + + const rawParticles = collDict['collection']; + const particles: any[] = []; + + rawParticles.forEach((rawParticle: any) => { + const origin: number[] = []; + origin.push(rawParticle.vertex.x * 0.1); + origin.push(rawParticle.vertex.y * 0.1); + origin.push(rawParticle.vertex.z * 0.1); + + const momentum: number[] = []; + momentum.push(rawParticle.momentum.x); + momentum.push(rawParticle.momentum.y); + momentum.push(rawParticle.momentum.z); + + console.log('------------ Particle -----------'); + console.log(' - origin:', origin); + console.log(' - momentum:', momentum); + console.log(' - status:', rawParticle.generatorStatus); + + const particle = { + origin: origin, + momentum: momentum, + color: '#ffff00', + }; + particles.push(particle); + }); + + allParticles[collName] = particles; + } + + return allParticles; + } + /** Return a random colour */ private randomColor() { return Math.floor(Math.random() * 16777215) diff --git a/packages/phoenix-event-display/src/loaders/objects/phoenix-objects.ts b/packages/phoenix-event-display/src/loaders/objects/phoenix-objects.ts index 933dcf74..81626618 100644 --- a/packages/phoenix-event-display/src/loaders/objects/phoenix-objects.ts +++ b/packages/phoenix-event-display/src/loaders/objects/phoenix-objects.ts @@ -7,6 +7,7 @@ import { MeshToonMaterial, Mesh, BufferGeometry, + ConeGeometry, LineBasicMaterial, Line, Group, @@ -22,12 +23,13 @@ import { LineSegments, LineDashedMaterial, CanvasTexture, + ArrowHelper, } from 'three'; import { ConvexGeometry } from 'three/examples/jsm/geometries/ConvexGeometry.js'; import { EVENT_DATA_TYPE_COLORS } from '../../helpers/constants'; import { RKHelper } from '../../helpers/rk-helper'; import { CoordinateHelper } from '../../helpers/coordinate-helper'; -import { mergeBufferGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js'; +import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js'; import { TracksMaterial, TracksMesh } from './tracks'; import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils'; @@ -472,7 +474,7 @@ export class PhoenixObjects { boxGeometry.translate(pointPos[i], pointPos[i + 1], pointPos[i + 2]); geometries.push(boxGeometry); } - const geometry = mergeBufferGeometries(geometries); + const geometry = mergeGeometries(geometries); geometry.computeBoundingSphere(); // material const material = new MeshPhongMaterial({ @@ -901,4 +903,98 @@ export class PhoenixObjects { return cell; } + + /** + * Create and return a Monte Carlo particle arrow from the given parameters. + * @param mcParticleParams MCParticle parameters. + * @returns Calorimeter MCParticle object. + */ + public static getMCParticle(mcParticleParams: { + origin: number[]; + momentum: number[]; + status?: number; + color?: string; + uuid: string; + }): Object3D { + const defaultColor: string = '#ffff00'; + const defaultStatus = 0; + + const origin = new Vector3( + mcParticleParams.origin[0], + mcParticleParams.origin[1], + mcParticleParams.origin[2] + ); + + const direction = new Vector3( + mcParticleParams.momentum[0], + mcParticleParams.momentum[1], + mcParticleParams.momentum[2] + ); + const length = direction.length(); + direction.normalize(); + + const lineLength = 0.85 * length; + let lineWidth = Math.log(length * 100) / 10; + console.log(lineWidth); + if (lineWidth < 0) { + lineWidth = 0.00001; + } + if (lineWidth > 0.4) { + lineWidth = 0.4; + } + const coneLength = 0.15 * length; + const coneWidth = 2.5 * lineWidth; + + // const lineGeometry = new CylinderGeometry(2, 2, lineLength, 16, 2); + const lineGeometry = new CylinderGeometry( + lineWidth, + lineWidth, + lineLength, + 16 + ); + lineGeometry.rotateZ(Math.PI / 2); + lineGeometry.translate(lineLength / 2, 0, 0); + + // const coneGeometry = new ConeGeometry(2, coneLength, 16, 2); + const coneGeometry = new ConeGeometry(coneWidth, coneLength, 16); + coneGeometry.rotateZ(-Math.PI / 2); + coneGeometry.translate(length - coneLength / 2, 0, 0); + + const geometries = [lineGeometry, coneGeometry]; + const mergedGeometry = mergeGeometries(geometries, false); + + const buildDirection = new Vector3(1, 0, 0).normalize(); + + const quaternion = new Quaternion(); + quaternion.setFromUnitVectors(buildDirection, direction); + mergedGeometry.applyQuaternion(quaternion); + + mergedGeometry.translate(origin.x, origin.y, origin.z); + mergedGeometry.computeBoundingBox(); + + const material = new MeshPhongMaterial({ + color: mcParticleParams.color ?? defaultColor, + }); + + const arrowObject = new Mesh(mergedGeometry, material); + + // const arrowHelper = new ArrowHelper(direction, origin, length); + // arrowHelper.position.copy(origin); + // arrowHelper.setDirection(direction); + + // const arrowObject = new Group(); + // arrowObject.add(arrowHelper.line); + // arrowObject.add(arrowHelper.cone); + + // console.log(arrowHelper.line); + // console.log(arrowHelper.cone); + + mcParticleParams.uuid = arrowObject.uuid; + // mcParticleParams.uuid = arrowHelper.uuid; + + arrowObject.name = 'MCParticle'; + // arrowHelper.name = 'MCParticle'; + + return arrowObject; + } } diff --git a/packages/phoenix-event-display/src/loaders/phoenix-loader.ts b/packages/phoenix-event-display/src/loaders/phoenix-loader.ts index 77dba322..99086d78 100644 --- a/packages/phoenix-event-display/src/loaders/phoenix-loader.ts +++ b/packages/phoenix-event-display/src/loaders/phoenix-loader.ts @@ -433,6 +433,32 @@ export class PhoenixLoader implements EventDataLoader { addMETSizeOption, ); } + + if (eventData.MCParticles) { + const cuts = [ + // new Cut('status', 0, 200, 20, 29), + ]; + + const scaleMCParticles = (value: number) => { + this.graphicsLibrary + .getSceneManager() + .scaleChildObjects('MCParticles', value); + }; + const addMCParticlesOptions = this.addScaleOptions( + 'mcParticlesScale', + 'MCParticles Scale', + scaleMCParticles + ); + + this.addObjectType( + eventData.MCParticles, + PhoenixObjects.getMCParticle, + 'MCParticles', + false, + cuts, + addMCParticlesOptions + ); + } } /** From 77c46222783cf6a4a9f3f1cb8fb0a7c54371419e Mon Sep 17 00:00:00 2001 From: Juraj Smiesko Date: Thu, 10 Aug 2023 18:18:45 +0200 Subject: [PATCH 2/3] Adding names and color --- .../src/loaders/edm4hep-json-loader.ts | 56 ++++++- .../src/loaders/objects/phoenix-objects.ts | 144 +++++++++++++++--- .../src/loaders/phoenix-loader.ts | 41 +++-- 3 files changed, 198 insertions(+), 43 deletions(-) diff --git a/packages/phoenix-event-display/src/loaders/edm4hep-json-loader.ts b/packages/phoenix-event-display/src/loaders/edm4hep-json-loader.ts index d4a058c2..79625499 100644 --- a/packages/phoenix-event-display/src/loaders/edm4hep-json-loader.ts +++ b/packages/phoenix-event-display/src/loaders/edm4hep-json-loader.ts @@ -664,15 +664,12 @@ export class Edm4hepJsonLoader extends PhoenixLoader { momentum.push(rawParticle.momentum.y); momentum.push(rawParticle.momentum.z); - console.log('------------ Particle -----------'); - console.log(' - origin:', origin); - console.log(' - momentum:', momentum); - console.log(' - status:', rawParticle.generatorStatus); - const particle = { origin: origin, momentum: momentum, - color: '#ffff00', + pdgid: rawParticle.PDG, + status: rawParticle.generatorStatus, + color: this.mcParticleColor(rawParticle.PDG), }; particles.push(particle); }); @@ -691,6 +688,53 @@ export class Edm4hepJsonLoader extends PhoenixLoader { .toUpperCase(); } + /** Return a random colour */ + private mcParticleColor(mcParticlePDGid) { + switch (Math.abs(mcParticlePDGid)) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + return '#aa0000'; + case 11: + return '#00aa00'; + case 12: + return '#00aa00'; + case 13: + return '#00aa00'; + case 14: + return '#00aa00'; + case 15: + return '#00aa00'; + case 16: + return '#00aa00'; + case 21: + return '#0000aa'; + case 22: + return '#0000aa'; + case 23: + return '#0000aa'; + case 24: + return '#0000aa'; + case 25: + return '#00aaaa'; + case 111: + return '#aa00aa'; + case 211: + return '#aa00aa'; + case 221: + return '#aa00aa'; + case 311: + return '#aa00aa'; + case 321: + return '#aa00aa'; + default: + return '#aaaa00'; + } + } + /** Helper conversion of HSL to hexadecimal */ private convHSLtoHEX(h: number, s: number, l: number): string { l /= 100; diff --git a/packages/phoenix-event-display/src/loaders/objects/phoenix-objects.ts b/packages/phoenix-event-display/src/loaders/objects/phoenix-objects.ts index 81626618..58f687a8 100644 --- a/packages/phoenix-event-display/src/loaders/objects/phoenix-objects.ts +++ b/packages/phoenix-event-display/src/loaders/objects/phoenix-objects.ts @@ -23,9 +23,11 @@ import { LineSegments, LineDashedMaterial, CanvasTexture, - ArrowHelper, } from 'three'; import { ConvexGeometry } from 'three/examples/jsm/geometries/ConvexGeometry.js'; +import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry.js'; +import { Font } from 'three/examples/jsm/loaders/FontLoader.js'; +import HelvetikerFont from '../../managers/three-manager/fonts/helvetiker_regular.typeface.json'; import { EVENT_DATA_TYPE_COLORS } from '../../helpers/constants'; import { RKHelper } from '../../helpers/rk-helper'; import { CoordinateHelper } from '../../helpers/coordinate-helper'; @@ -912,12 +914,12 @@ export class PhoenixObjects { public static getMCParticle(mcParticleParams: { origin: number[]; momentum: number[]; + pdgid: number; status?: number; color?: string; uuid: string; }): Object3D { const defaultColor: string = '#ffff00'; - const defaultStatus = 0; const origin = new Vector3( mcParticleParams.origin[0], @@ -934,18 +936,16 @@ export class PhoenixObjects { direction.normalize(); const lineLength = 0.85 * length; - let lineWidth = Math.log(length * 100) / 10; - console.log(lineWidth); + let lineWidth = Math.log(length * 1000) / 100; if (lineWidth < 0) { lineWidth = 0.00001; } - if (lineWidth > 0.4) { - lineWidth = 0.4; + if (lineWidth > 0.1) { + lineWidth = 0.1; } const coneLength = 0.15 * length; const coneWidth = 2.5 * lineWidth; - // const lineGeometry = new CylinderGeometry(2, 2, lineLength, 16, 2); const lineGeometry = new CylinderGeometry( lineWidth, lineWidth, @@ -955,7 +955,6 @@ export class PhoenixObjects { lineGeometry.rotateZ(Math.PI / 2); lineGeometry.translate(lineLength / 2, 0, 0); - // const coneGeometry = new ConeGeometry(2, coneLength, 16, 2); const coneGeometry = new ConeGeometry(coneWidth, coneLength, 16); coneGeometry.rotateZ(-Math.PI / 2); coneGeometry.translate(length - coneLength / 2, 0, 0); @@ -969,32 +968,129 @@ export class PhoenixObjects { quaternion.setFromUnitVectors(buildDirection, direction); mergedGeometry.applyQuaternion(quaternion); - mergedGeometry.translate(origin.x, origin.y, origin.z); - mergedGeometry.computeBoundingBox(); - const material = new MeshPhongMaterial({ color: mcParticleParams.color ?? defaultColor, }); const arrowObject = new Mesh(mergedGeometry, material); - // const arrowHelper = new ArrowHelper(direction, origin, length); - // arrowHelper.position.copy(origin); - // arrowHelper.setDirection(direction); + const font = new Font(HelvetikerFont); + const labelGeometry = new TextGeometry( + PhoenixObjects.getMCParticleName(mcParticleParams.pdgid), + { + font: font, + size: 80, + height: 2, + curveSegments: 12, + bevelEnabled: true, + bevelThickness: 4, + bevelSize: 4, + bevelOffset: 0, + bevelSegments: 5, + } + ); + labelGeometry.scale(0.01, 0.01, 0.01); + + labelGeometry.rotateX(Math.PI / 2); + labelGeometry.translate(length, 0, 0); + + labelGeometry.applyQuaternion(quaternion); + + const labelObject = new Mesh(labelGeometry, material); - // const arrowObject = new Group(); - // arrowObject.add(arrowHelper.line); - // arrowObject.add(arrowHelper.cone); + const arrowContainer = new Group(); + arrowContainer.position.x = origin.x; + arrowContainer.position.y = origin.y; + arrowContainer.position.z = origin.z; - // console.log(arrowHelper.line); - // console.log(arrowHelper.cone); + arrowContainer.add(arrowObject); + arrowContainer.add(labelObject); - mcParticleParams.uuid = arrowObject.uuid; - // mcParticleParams.uuid = arrowHelper.uuid; + mcParticleParams.uuid = arrowContainer.uuid; + arrowContainer.userData = Object.assign({}, mcParticleParams); - arrowObject.name = 'MCParticle'; - // arrowHelper.name = 'MCParticle'; + arrowContainer.name = 'MCParticle'; - return arrowObject; + return arrowContainer; + } + + /** + * Return a Monte Carlo particle name from PDG ID. + * @param mcParticlePDGid PDG ID. + * @returns MCParticle name. + */ + public static getMCParticleName(mcParticlePDGid: number): string { + switch (mcParticlePDGid) { + case 1: + return 'd'; + case -1: + return '!d'; + case 2: + return 'u'; + case -2: + return '!u'; + case 3: + return 's'; + case -3: + return '!s'; + case 4: + return 'c'; + case -4: + return '!c'; + case 5: + return 'b'; + case -5: + return '!b'; + case 6: + return 't'; + case -6: + return '!t'; + case 11: + return 'e-'; + case -11: + return 'e+'; + case 12: + return 'νe'; + case 13: + return 'μ-'; + case -13: + return 'μ+'; + case 14: + return 'νμ'; + case 15: + return 'τ'; + case -15: + return 'τ-'; + case 16: + return 'ντ'; + case 21: + return 'g'; + case 22: + return 'γ'; + case 23: + return 'Z'; + case 24: + return 'W+'; + case -24: + return 'W-'; + case 25: + return 'H'; + case 111: + return 'π0'; + case 211: + return 'π+'; + case -211: + return 'π-'; + case 221: + return 'η'; + case 311: + return 'K0'; + case 321: + return 'K+'; + case -321: + return 'K-'; + default: + return mcParticlePDGid.toString(); + } } } diff --git a/packages/phoenix-event-display/src/loaders/phoenix-loader.ts b/packages/phoenix-event-display/src/loaders/phoenix-loader.ts index 99086d78..752b66dc 100644 --- a/packages/phoenix-event-display/src/loaders/phoenix-loader.ts +++ b/packages/phoenix-event-display/src/loaders/phoenix-loader.ts @@ -435,20 +435,35 @@ export class PhoenixLoader implements EventDataLoader { } if (eventData.MCParticles) { - const cuts = [ - // new Cut('status', 0, 200, 20, 29), - ]; + const cuts = [new Cut('status', 21, 29, 200)]; - const scaleMCParticles = (value: number) => { - this.graphicsLibrary - .getSceneManager() - .scaleChildObjects('MCParticles', value); + const addMCParticlesSizeOption = ( + typeFolder: GUI, + typeFolderPM: PhoenixMenuNode + ) => { + const scaleMCParticles = (value: number) => { + this.graphicsLibrary + .getSceneManager() + .scaleChildObjects('MCParticles', value / 100); + }; + if (typeFolder) { + const sizeMenu = typeFolder + .add({ particleScale: 100 }, 'particleScale', 1, 400) + .name('Size (%)'); + sizeMenu.onChange(scaleMCParticles); + } + // Phoenix menu + if (typeFolderPM) { + typeFolderPM.addConfig('slider', { + label: 'Size (%)', + value: 100, + min: 1, + max: 400, + allowCustomValue: true, + onChange: scaleMCParticles, + }); + } }; - const addMCParticlesOptions = this.addScaleOptions( - 'mcParticlesScale', - 'MCParticles Scale', - scaleMCParticles - ); this.addObjectType( eventData.MCParticles, @@ -456,7 +471,7 @@ export class PhoenixLoader implements EventDataLoader { 'MCParticles', false, cuts, - addMCParticlesOptions + addMCParticlesSizeOption ); } } From e5665a654a82a2ab0c4400ddaf88ee0cab137561 Mon Sep 17 00:00:00 2001 From: Juraj Smiesko Date: Wed, 16 Aug 2023 12:10:58 +0200 Subject: [PATCH 3/3] Adjusting font size/shape --- .../src/loaders/edm4hep-json-loader.ts | 16 ++-------------- .../src/loaders/objects/phoenix-objects.ts | 18 ++++++------------ .../src/loaders/phoenix-loader.ts | 4 ++-- 3 files changed, 10 insertions(+), 28 deletions(-) diff --git a/packages/phoenix-event-display/src/loaders/edm4hep-json-loader.ts b/packages/phoenix-event-display/src/loaders/edm4hep-json-loader.ts index 79625499..296536c9 100644 --- a/packages/phoenix-event-display/src/loaders/edm4hep-json-loader.ts +++ b/packages/phoenix-event-display/src/loaders/edm4hep-json-loader.ts @@ -680,7 +680,7 @@ export class Edm4hepJsonLoader extends PhoenixLoader { return allParticles; } - /** Return a random colour */ + /** Return a random color */ private randomColor() { return Math.floor(Math.random() * 16777215) .toString(16) @@ -688,7 +688,7 @@ export class Edm4hepJsonLoader extends PhoenixLoader { .toUpperCase(); } - /** Return a random colour */ + /** Return color depending on the particle type */ private mcParticleColor(mcParticlePDGid) { switch (Math.abs(mcParticlePDGid)) { case 1: @@ -699,35 +699,23 @@ export class Edm4hepJsonLoader extends PhoenixLoader { case 6: return '#aa0000'; case 11: - return '#00aa00'; case 12: - return '#00aa00'; case 13: - return '#00aa00'; case 14: - return '#00aa00'; case 15: - return '#00aa00'; case 16: return '#00aa00'; case 21: - return '#0000aa'; case 22: - return '#0000aa'; case 23: - return '#0000aa'; case 24: return '#0000aa'; case 25: return '#00aaaa'; case 111: - return '#aa00aa'; case 211: - return '#aa00aa'; case 221: - return '#aa00aa'; case 311: - return '#aa00aa'; case 321: return '#aa00aa'; default: diff --git a/packages/phoenix-event-display/src/loaders/objects/phoenix-objects.ts b/packages/phoenix-event-display/src/loaders/objects/phoenix-objects.ts index 58f687a8..c591c729 100644 --- a/packages/phoenix-event-display/src/loaders/objects/phoenix-objects.ts +++ b/packages/phoenix-event-display/src/loaders/objects/phoenix-objects.ts @@ -924,13 +924,13 @@ export class PhoenixObjects { const origin = new Vector3( mcParticleParams.origin[0], mcParticleParams.origin[1], - mcParticleParams.origin[2] + mcParticleParams.origin[2], ); const direction = new Vector3( mcParticleParams.momentum[0], mcParticleParams.momentum[1], - mcParticleParams.momentum[2] + mcParticleParams.momentum[2], ); const length = direction.length(); direction.normalize(); @@ -950,7 +950,7 @@ export class PhoenixObjects { lineWidth, lineWidth, lineLength, - 16 + 16, ); lineGeometry.rotateZ(Math.PI / 2); lineGeometry.translate(lineLength / 2, 0, 0); @@ -979,15 +979,9 @@ export class PhoenixObjects { PhoenixObjects.getMCParticleName(mcParticleParams.pdgid), { font: font, - size: 80, - height: 2, - curveSegments: 12, - bevelEnabled: true, - bevelThickness: 4, - bevelSize: 4, - bevelOffset: 0, - bevelSegments: 5, - } + size: 100, + height: 15, + }, ); labelGeometry.scale(0.01, 0.01, 0.01); diff --git a/packages/phoenix-event-display/src/loaders/phoenix-loader.ts b/packages/phoenix-event-display/src/loaders/phoenix-loader.ts index 752b66dc..57de5700 100644 --- a/packages/phoenix-event-display/src/loaders/phoenix-loader.ts +++ b/packages/phoenix-event-display/src/loaders/phoenix-loader.ts @@ -439,7 +439,7 @@ export class PhoenixLoader implements EventDataLoader { const addMCParticlesSizeOption = ( typeFolder: GUI, - typeFolderPM: PhoenixMenuNode + typeFolderPM: PhoenixMenuNode, ) => { const scaleMCParticles = (value: number) => { this.graphicsLibrary @@ -471,7 +471,7 @@ export class PhoenixLoader implements EventDataLoader { 'MCParticles', false, cuts, - addMCParticlesSizeOption + addMCParticlesSizeOption, ); } }