diff --git a/docs/assets/geometry/ATLAS/.SCT.obj.icloud b/docs/assets/geometry/ATLAS/.SCT.obj.icloud deleted file mode 100644 index df24bd637..000000000 Binary files a/docs/assets/geometry/ATLAS/.SCT.obj.icloud and /dev/null differ diff --git a/docs/assets/geometry/ATLAS/.toroids.obj.icloud b/docs/assets/geometry/ATLAS/.toroids.obj.icloud deleted file mode 100644 index 3a692d39d..000000000 Binary files a/docs/assets/geometry/ATLAS/.toroids.obj.icloud and /dev/null differ diff --git a/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/schema1.ts b/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/schema1.ts new file mode 100644 index 000000000..21cd586a7 --- /dev/null +++ b/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/schema1.ts @@ -0,0 +1,232 @@ +/* eslint-disable @typescript-eslint/no-namespace */ +import { Vector3f, Vector3d, Vector2i, ObjectID } from './utils'; + +export namespace Schema1 { + /** Vertex */ + export type Vertex = { + primary: number; // boolean flag, if vertex is the primary vertex of the event + chi2: number; // chi-squared of the vertex fit + probability: number; // probability of the vertex fit + position: Vector3f; // [mm] position of the vertex. + covMatrix: number[]; // covariance matrix of the position (stored as lower triangle matrix, i.e. cov(xx),cov(y,x),cov(z,x),cov(y,y),... ) + algorithmType: number; // type code for the algorithm that has been used to create the vertex - check/set the collection parameters AlgorithmName and AlgorithmType. + parameters: number[]; // additional parameters related to this vertex - check/set the collection parameter "VertexParameterNames" for the parameters meaning. + associatedParticle: ObjectID; // reconstructed particle associated to this vertex. + }; + + export type TrackState = { + location: number; // for use with At{Other|IP|FirstHit|LastHit|Calorimeter|Vertex}|LastLocation + D0: number; // transverse impact parameter + phi: number; // azimuthal angle + omega: number; // is the signed curvature of the track in [1/mm]. + Z0: number; // longitudinal impact parameter + tanLambda: number; // lambda is the dip angle of the track in r-z + time: number; // time of the track at this trackstate + referencePoint: Vector3f; // Reference point of the track parameters, e.g. the origin at the IP, or the position of the first/last hits or the entry point into the calorimeter. [mm] + covMatrix: number[]; // lower triangular covariance matrix of the track parameters. the order of parameters is d0, phi, omega, z0, tan(lambda), time. the array is a row-major flattening of the matrix. + }; + + /** Reconstructed track */ + export type Track = { + type: number; // flagword that defines the type of track.Bits 16-31 are used internally + chi2: number; // Chi^2 of the track fit + ndf: number; // number of degrees of freedom of the track fit + dEdx: number; // dEdx of the track. + dEdxError: number; // error of dEdx. + radiusOfInnermostHit: number; // radius of the innermost hit that has been used in the track fit + subdetectorHitNumbers: number[]; // number of hits in particular subdetectors.Check/set collection variable TrackSubdetectorNames for decoding the indices + trackStates: TrackState[]; // track states + dxQuantities: { + error: number; + type: number; + value: number; + }[]; // different measurements of dx quantities + trackerHits: ObjectID[]; // hits that have been used to create this track + tracks: ObjectID[]; // tracks (segments) that have been combined to create this track + }; + + /** Tracker hit */ + export type TrackerHit = { + cellID: bigint; // ID of the sensor that created this hit + type: number; // type of raw data hit, either one of edm4hep::RawTimeSeries, edm4hep::SIMTRACKERHIT - see collection parameters "TrackerHitTypeNames" and "TrackerHitTypeValues". + quality: number; // quality bit flag of the hit. + time: number; // time of the hit [ns]. + eDep: number; // energy deposited on the hit [GeV]. + eDepError: number; // error measured on EDep [GeV]. + position: Vector3d; // hit position in [mm]. + covMatrix: number[]; // covariance of the position (x,y,z), stored as lower triangle matrix. i.e. cov(x,x) , cov(y,x) , cov(y,y) , cov(z,x) , cov(z,y) , cov(z,z) + rawHits: ObjectID[]; // raw data hits. Check getType to get actual data type. + }; + + /** Simulated tracker hit */ + export type SimTrackerHit = { + cellID: bigint; // ID of the sensor that created this hit + EDep: number; // energy deposited in the hit [GeV]. + time: number; // proper time of the hit in the lab frame in [ns]. + pathLength: number; // path length of the particle in the sensitive material that resulted in this hit. + quality: number; // quality bit flag. + position: Vector3d; // the hit position in [mm]. + momentum: Vector3f; // the 3-momentum of the particle at the hits position in [GeV] + MCParticle: ObjectID; // MCParticle that caused the hit. + }; + + /** Calorimeter hit */ + export type CalorimeterHit = { + cellID: bigint; // detector specific (geometrical) cell id. + energy: number; // energy of the hit in [GeV]. + energyError: number; // error of the hit energy in [GeV]. + time: number; // time of the hit in [ns]. + position: Vector3f; // position of the hit in world coordinates in [mm]. + type: number; // type of hit. Mapping of integer types to names via collection parameters "CalorimeterHitTypeNames" and "CalorimeterHitTypeValues". + }; + + /** Simulated calorimeter hit */ + export type SimCalorimeterHit = { + cellID: bigint; // ID of the sensor that created this hit + energy: number; // energy of the hit in [GeV]. + position: Vector3f; // position of the hit in world coordinates in [mm]. + contributions: ObjectID[]; // Monte Carlo step contribution - parallel to particle + }; + + /** Calorimeter Hit Cluster */ + export type Cluster = { + type: number; // flagword that defines the type of cluster. Bits 16-31 are used internally. + energy: number; // energy of the cluster [GeV] + energyError: number; // error on the energy + position: Vector3f; // position of the cluster [mm] + positionError: number[]; // covariance matrix of the position (6 Parameters) + iTheta: number; // intrinsic direction of cluster at position Theta. Not to be confused with direction cluster is seen from IP. + phi: number; // intrinsic direction of cluster at position - Phi. Not to be confused with direction cluster is seen from IP. + directionError: Vector3f; // covariance matrix of the direction (3 Parameters) [mm^2] + shapeParameters: number[]; // shape parameters - check/set collection parameter ClusterShapeParameters for size and names of parameters. + subdetectorEnergies: number[]; // energy observed in a particular subdetector. Check/set collection parameter ClusterSubdetectorNames for decoding the indices of the array. + clusters: ObjectID[]; // clusters that have been combined to this cluster. + hits: ObjectID[]; // hits that have been combined to this cluster. + particleIDs: ObjectID[]; // particle IDs (sorted by their likelihood) + }; + + /** Reconstructed Particle */ + export type ReconstructedParticle = { + type: number; // type of reconstructed particle. Check/set collection parameters ReconstructedParticleTypeNames and ReconstructedParticleTypeValues. + energy: number; // [GeV] energy of the reconstructed particle. Four momentum state is not kept consistent internally. + momentum: Vector3f; // [GeV] particle momentum. Four momentum state is not kept consistent internally. + referencePoint: Vector3f; // [mm] reference, i.e. where the particle has been measured + charge: number; // charge of the reconstructed particle. + mass: number; // [GeV] mass of the reconstructed particle, set independently from four vector. Four momentum state is not kept consistent internally. + goodnessOfPID: number; // overall goodness of the PID on a scale of [0;1] + covMatrix: number[]; // cvariance matrix of the reconstructed particle 4vector (10 parameters). Stored as lower triangle matrix of the four momentum (px,py,pz,E), i.e. cov(px,px), cov(py,## + startVertex: ObjectID; // start vertex associated to this particle + particleIDUsed: ObjectID; // particle Id used for the kinematics of this particle + clusters: ObjectID[]; // clusters that have been used for this particle. + tracks: ObjectID[]; // tracks that have been used for this particle. + particles: ObjectID[]; // reconstructed particles that have been combined to this particle. + particleIDs: ObjectID[]; // particle Ids (not sorted by their likelihood) + }; + + /** Event Header. Additional parameters are assumed to go into the metadata tree. */ + export type EventHeader = { + eventNumber: number; // event number + runNumber: number; // run number + timeStamp: bigint; // time stamp + weight: number; // event weight + }; + + /** Used to keep track of the correspondence between MC and reconstructed particles */ + export type MCRecoParticleAssociation = { + weight: number; // weight of this association + rec: ObjectID; // reference to the reconstructed particle + sim: ObjectID; // reference to the Monte-Carlo particle + }; + + /** The Monte Carlo particle - based on the lcio::MCParticle. */ + export type MCParticle = { + PDG: number; // PDG code of the particle + generatorStatus: number; // status of the particle as defined by the generator + simulatorStatus: number; // status of the particle from the simulation program - use BIT constants below + charge: number; // particle charge + time: number; // creation time of the particle in [ns] wrt. the event, e.g. for preassigned decays or decays in flight from the simulator. + mass: number; // mass of the particle in [GeV] + vertex: Vector3d; // production vertex of the particle in [mm]. + endpoint: Vector3d; // endpoint of the particle in [mm] + momentum: Vector3f; // particle 3-momentum at the production vertex in [GeV] + momentumAtEndpoint: Vector3f; // particle 3-momentum at the endpoint in [GeV] + spin: Vector3f; // spin (helicity) vector of the particle. + colorFlow: Vector2i; // color flow as defined by the generator + parents: ObjectID[]; // The parents of this particle. + daughters: ObjectID[]; // The daughters this particle. + }; + + export type EventHeaderCollection = EventHeader[]; + export type VertexCollection = Vertex[]; + export type TrackCollection = Track[]; + export type TrackerHitCollection = TrackerHit[]; + export type SimTrackerHitCollection = SimTrackerHit[]; + export type CalorimeterHitCollection = CalorimeterHit[]; + export type SimCalorimeterHitCollection = SimCalorimeterHit[]; + export type ClusterCollection = Cluster[]; + export type ReconstructedParticleCollection = ReconstructedParticle[]; + export type MCRecoParticleAssociationCollection = MCRecoParticleAssociation[]; + export type MCParticleCollection = MCParticle[]; + + export type Coll = + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::EventHeaderCollection'; + collection: EventHeader[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::VertexCollection'; + collection: Vertex[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::TrackCollection'; + collection: Track[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::TrackerHitCollection'; + collection: TrackerHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::SimTrackerHitCollection'; + collection: SimTrackerHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::CalorimeterHitCollection'; + collection: CalorimeterHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::SimCalorimeterHitCollection'; + collection: SimCalorimeterHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::ClusterCollection'; + collection: Cluster[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::ReconstructedParticleCollection'; + collection: ReconstructedParticle[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::MCRecoParticleAssociation'; + collection: MCRecoParticleAssociation[]; + }; +} diff --git a/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/schema2.ts b/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/schema2.ts new file mode 100644 index 000000000..3cd457cbe --- /dev/null +++ b/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/schema2.ts @@ -0,0 +1,255 @@ +/* eslint-disable @typescript-eslint/no-namespace */ +import { + CovMatrix3f, + CovMatrix4f, + CovMatrix6f, + Vector2f, + Vector2i, + Vector3f, + Vector3d, + ObjectID, +} from './utils'; + +export namespace Schema2 { + /** Vertex */ + export type Vertex = { + type: number; // Flagword that defines the type of the vertex, see reserved bits for more information + chi2: number; // chi-squared of the vertex fit + ndf: number; // number of degrees of freedom of the vertex fit + position: Vector3f; // [mm] position of the vertex + covMatrix: CovMatrix3f; // covariance matrix of the position + algorithmType: number; // type code for the algorithm that has been used to create the vertex + parameters: number[]; // additional parameters related to this vertex + particles: ObjectID[]; // particles that have been used to form this vertex, aka the decay particles emerging from this vertex + }; + + /** Parametrized description of a particle track */ + export type TrackState = { + location: number; // for use with At{Other|IP|FirstHit|LastHit|Calorimeter|Vertex}|LastLocation + D0: number; // transverse impact parameter + phi: number; // azimuthal angle + omega: number; // [1/mm] is the signed curvature of the track + Z0: number; // longitudinal impact parameter + tanLambda: number; // lambda is the dip angle of the track in r-z + time: number; // [ns] time of the track at this trackstate + referencePoint: Vector3f; // [mm] Reference point of the track parameters, e.g. the origin at the IP, or the position of the first/last hits or the entry point into the calorimeter + covMatrix: CovMatrix6f; // covariance matrix of the track parameters. + }; + + /** Reconstructed track */ + export type Track = { + type: number; // flagword that defines the type of track + chi2: number; // Chi^2 of the track fit + ndf: number; // number of degrees of freedom of the track fit + Nholes: number; // number of holes on track + subdetectorHitNumbers: number[]; // number of hits in particular subdetectors + subdetectorHoleNumbers: number[]; // number of holes in particular subdetectors + trackStates: TrackState[]; // track states + trackerHits: ObjectID[]; // hits that have been used to create this track + tracks: ObjectID[]; // tracks (segments) that have been combined to create this track + }; + + /** Tracker hit interface class */ + // Types: TrackerHit3D, TrackerHitPlane + interface TrackerHit { + cellID: bigint; // ID of the sensor that created this hit + type: number; // type of the raw data hit + quality: number; // quality bit flag of the hit + time: number; // [ns] time of the hit + eDep: number; // [GeV] energy deposited on the hit + eDepError: number; // [GeV] error measured on eDep + position: Vector3d; // [mm] hit position + } + + /** Tracker hit */ + export interface TrackerHit3D extends TrackerHit { + cellID: bigint; // ID of the sensor that created this hit + type: number; // type of raw data hit + quality: number; // quality bit flag of the hit + time: number; // [ns] time of the hit + eDep: number; // [GeV] energy deposited on the hit + eDepError: number; // [GeV] error measured on EDep + position: Vector3d; // [mm] hit position + covMatrix: CovMatrix3f; // covariance matrix of the position (x,y,z) + } + + /** Tracker hit plane */ + export interface TrackerHitPlane extends TrackerHit { + cellID: bigint; // ID of the sensor that created this hit + type: number; // type of raw data hit + quality: number; // quality bit flag of the hit + time: number; // [ns] time of the hit + eDep: number; // [GeV] energy deposited on the hit + eDepError: number; // [GeV] error measured on EDep + u: Vector2f; // measurement direction vector, u lies in the x-y plane + v: Vector2f; // measurement direction vector, v is along z + du: number; // measurement error along the direction + dv: number; // measurement error along the direction + position: Vector3d; // [mm] hit position + covMatrix: CovMatrix3f; // covariance of the position (x,y,z) + } + + /** Simulated tracker hit */ + export type SimTrackerHit = { + cellID: bigint; // ID of the sensor that created this hit + eDep: number; // [GeV] energy deposited in the hit + time: number; // [ns] proper time of the hit in the lab frame + pathLength: number; // path length of the particle in the sensitive material that resulted in this hit + quality: number; // quality bit flag + position: Vector3d; // [mm] the hit position + momentum: Vector3f; // [GeV] the 3-momentum of the particle at the hits position + particle: ObjectID[]; // MCParticle that caused the hit + }; + + /** Calorimeter hit */ + export type CalorimeterHit = { + cellID: bigint; // detector specific (geometrical) cell id + energy: number; // [GeV] energy of the hit + energyError: number; // [GeV] error of the hit energy + time: number; // [ns] time of the hit + position: Vector3f; // [mm] position of the hit in world coordinates + type: number; // type of hit + }; + + /** Simulated calorimeter hit */ + export type SimCalorimeterHit = { + cellID: bigint; // ID of the sensor that created this hit + energy: number; // [GeV] energy of the hit + position: Vector3f; // [mm] position of the hit in world coordinates + contributions: ObjectID[]; // Monte Carlo step contributions + }; + + /** Calorimeter Hit Cluster */ + export type Cluster = { + type: number; // flagword that defines the type of cluster + energy: number; // [GeV] energy of the cluster + energyError: number; // [GeV] error on the energy + position: Vector3f; // [mm] position of the cluster + positionError: CovMatrix3f; // covariance matrix of the position + iTheta: number; // intrinsic direction of cluster at position Theta. Not to be confused with direction cluster is seen from IP + phi: number; // intrinsic direction of cluster at position - Phi. Not to be confused with direction cluster is seen from IP + directionError: Vector3f; // [mm**2] covariance matrix of the direction + shapeParameters: number[]; // shape parameters. This should be accompanied by a descriptive list of names in the shapeParameterNames collection level metadata, as a vector of strings with the same ordering + subdetectorEnergies: number[]; // energy observed in a particular subdetector + clusters: ObjectID[]; // clusters that have been combined to this cluster + hits: ObjectID[]; // hits that have been combined to this cluster + }; + + /** Reconstructed Particle */ + export type ReconstructedParticle = { + PDG: number; // PDG of the reconstructed particle. + energy: number; // [GeV] energy of the reconstructed particle. Four momentum state is not kept consistent internally + momentum: Vector3f; // [GeV] particle momentum. Four momentum state is not kept consistent internally + referencePoint: Vector3f; // [mm] reference, i.e. where the particle has been measured + charge: number; // charge of the reconstructed particle + mass: number; // [GeV] mass of the reconstructed particle, set independently from four vector. Four momentum state is not kept consistent internally + goodnessOfPID: number; // overall goodness of the PID on a scale of [0;1] + covMatrix: CovMatrix4f; // covariance matrix of the reconstructed particle 4vector + decayVertex: ObjectID; // decay vertex for the particle (if it is a composite particle) + clusters: ObjectID[]; // clusters that have been used for this particle + tracks: ObjectID[]; // tracks that have been used for this particle + particles: ObjectID[]; // reconstructed particles that have been combined to this particle + }; + + /** Event Header. Additional parameters are assumed to go into the metadata tree. */ + export type EventHeader = { + eventNumber: number; // event number + runNumber: number; // run number + timeStamp: bigint; // time stamp + weight: number; // event weight + weights: number[]; // event weights in case there are multiple. **NOTE that weights[0] might not be the same as weight!** Event weight names should be stored using the edm4hep::EventWeights name in the file level metadata + }; + + /** Link between a ReconstructedParticle and the corresponding MCParticle */ + export type RecoMCParticleLink = { + weight: number; // weight of this link + from: ObjectID; // reference to the reconstructed particle + to: ObjectID; // reference to the Monte-Carlo particle + }; + + /** The Monte Carlo particle - based on the lcio::MCParticle. */ + export type MCParticle = { + PDG: number; // PDG code of the particle + generatorStatus: number; // status of the particle as defined by the generator + simulatorStatus: number; // status of the particle from the simulation program - use BIT constants below + charge: number; // particle charge + time: number; // [ns] creation time of the particle in wrt. the event, e.g. for preassigned decays or decays in flight from the simulator + mass: number; // [GeV] mass of the particle + vertex: Vector3d; // [mm] production vertex of the particle + endpoint: Vector3d; // [mm] endpoint of the particle + momentum: Vector3d; // [GeV] particle 3-momentum at the production vertex + momentumAtEndpoint: Vector3d; // [GeV] particle 3-momentum at the endpoint + spin: Vector3f; // spin (helicity) vector of the particle + colorFlow: Vector2i; // color flow as defined by the generator + parents: ObjectID[]; // The parents of this particle + daughters: ObjectID[]; // The daughters this particle + }; + + export type Coll = + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::EventHeaderCollection'; + collection: EventHeader[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::VertexCollection'; + collection: Vertex[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::TrackCollection'; + collection: Track[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::TrackerHit3DCollection'; + collection: TrackerHit3D[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::TrackerHitPlaneCollection'; + collection: TrackerHitPlane[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::SimTrackerHitCollection'; + collection: SimTrackerHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::CalorimeterHitCollection'; + collection: CalorimeterHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::SimCalorimeterHitCollection'; + collection: SimCalorimeterHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::ClusterCollection'; + collection: Cluster[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::ReconstructedParticleCollection'; + collection: ReconstructedParticle[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::RecoMCParticleLink'; + collection: RecoMCParticleLink[]; + }; +} diff --git a/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/schema3.ts b/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/schema3.ts new file mode 100644 index 000000000..7b6d05403 --- /dev/null +++ b/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/schema3.ts @@ -0,0 +1,253 @@ +/* eslint-disable @typescript-eslint/no-namespace */ +import { + CovMatrix3f, + CovMatrix4f, + CovMatrix6f, + Vector2f, + Vector3f, + Vector3d, + ObjectID, +} from './utils'; + +export namespace Schema3 { + /** Vertex */ + export type Vertex = { + type: number; // flagword that defines the type of the vertex, see reserved bits for more information + chi2: number; // chi-squared of the vertex fit + ndf: number; // number of degrees of freedom of the vertex fit + position: Vector3f; // [mm] position of the vertex + covMatrix: CovMatrix3f; // [mm^2] covariance matrix of the position + algorithmType: number; // type code for the algorithm that has been used to create the vertex + parameters: number[]; // additional parameters related to this vertex + particles: ObjectID[]; // particles that have been used to form this vertex, aka the decay particles emerging from this vertex + }; + + /** Parametrized description of a particle track */ + export type TrackState = { + location: number; // for use with At{Other|IP|FirstHit|LastHit|Calorimeter|Vertex}|LastLocation + D0: number; // transverse impact parameter + phi: number; // [rad] azimuthal angle of the track at this location (i.e. not phi0) + omega: number; // [1/mm] is the signed curvature of the track + Z0: number; // longitudinal impact parameter + tanLambda: number; // lambda is the dip angle of the track in r-z + time: number; // [ns] time of the track at this trackstate + referencePoint: Vector3f; // [mm] Reference point of the track parameters, e.g. the origin at the IP, or the position of the first/last hits or the entry point into the calorimeter + covMatrix: CovMatrix6f; // covariance matrix of the track parameters. + }; + + /** Reconstructed track */ + export type Track = { + type: number; // flagword that defines the type of track + chi2: number; // chi-squared of the track fit + ndf: number; // number of degrees of freedom of the track fit + Nholes: number; // number of holes on track + subdetectorHitNumbers: number[]; // number of hits in particular subdetectors + subdetectorHoleNumbers: number[]; // number of holes in particular subdetectors + trackStates: TrackState[]; // track states + trackerHits: ObjectID[]; // hits that have been used to create this track + tracks: ObjectID[]; // tracks (segments) that have been combined to create this track + }; + + /** Tracker hit interface class */ + // Types: TrackerHit3D, TrackerHitPlane + interface TrackerHit { + cellID: bigint; // ID of the sensor that created this hit + type: number; // type of the raw data hit + quality: number; // quality bit flag of the hit + time: number; // [ns] time of the hit + eDep: number; // [GeV] energy deposited on the hit + eDepError: number; // [GeV] error measured on eDep + position: Vector3d; // [mm] hit position + } + + /** Tracker hit */ + export interface TrackerHit3D extends TrackerHit { + cellID: bigint; // ID of the sensor that created this hit + type: number; // type of raw data hit + quality: number; // quality bit flag of the hit + time: number; // [ns] time of the hit + eDep: number; // [GeV] energy deposited on the hit + eDepError: number; // [GeV] error measured on eDep + position: Vector3d; // [mm] hit position + covMatrix: CovMatrix3f; // [mm^2] covariance matrix of the position (x,y,z) + } + + /** Tracker hit plane */ + export interface TrackerHitPlane extends TrackerHit { + cellID: bigint; // ID of the sensor that created this hit + type: number; // type of raw data hit + quality: number; // quality bit flag of the hit + time: number; // [ns] time of the hit + eDep: number; // [GeV] energy deposited on the hit + eDepError: number; // [GeV] error measured on eDep + u: Vector2f; // measurement direction vector, u lies in the x-y plane + v: Vector2f; // measurement direction vector, v is along z + du: number; // measurement error along the direction + dv: number; // measurement error along the direction + position: Vector3d; // [mm] hit position + covMatrix: CovMatrix3f; // [mm^2] covariance of the position (x,y,z) + } + + /** Simulated tracker hit */ + export type SimTrackerHit = { + cellID: bigint; // ID of the sensor that created this hit + eDep: number; // [GeV] energy deposited in the hit + time: number; // [ns] proper time of the hit in the lab frame + pathLength: number; // path length of the particle in the sensitive material that resulted in this hit + quality: number; // quality bit flag + position: Vector3d; // [mm] the hit position + momentum: Vector3f; // [GeV] the 3-momentum of the particle at the hits position + particle: ObjectID[]; // MCParticle that caused the hit + }; + + /** Calorimeter hit */ + export type CalorimeterHit = { + cellID: bigint; // detector specific (geometrical) cell id + energy: number; // [GeV] energy of the hit + energyError: number; // [GeV] error of the hit energy + time: number; // [ns] time of the hit + position: Vector3f; // [mm] position of the hit in world coordinates + type: number; // type of hit + }; + + /** Simulated calorimeter hit */ + export type SimCalorimeterHit = { + cellID: bigint; // ID of the sensor that created this hit + energy: number; // [GeV] energy of the hit + position: Vector3f; // [mm] position of the hit in world coordinates + contributions: ObjectID[]; // Monte Carlo step contributions + }; + + /** Calorimeter Hit Cluster */ + export type Cluster = { + type: number; // flagword that defines the type of cluster + energy: number; // [GeV] energy of the cluster + energyError: number; // [GeV] error on the energy + position: Vector3f; // [mm] position of the cluster + positionError: CovMatrix3f; // [mm^2] covariance matrix of the position + iTheta: number; // [rad] Polar angle of the cluster's intrinsic direction (used e.g. for vertexing). Not to be confused with the cluster position seen from IP + phi: number; // [rad] Azimuthal angle of the cluster's intrinsic direction (used e.g. for vertexing). Not to be confused with the cluster position seen from IP + directionError: Vector3f; // [mm^2] covariance matrix of the direction + shapeParameters: number[]; // shape parameters. This should be accompanied by a descriptive list of names in the shapeParameterNames collection level metadata, as a vector of strings with the same ordering + subdetectorEnergies: number[]; // energy observed in a particular subdetector + clusters: ObjectID[]; // clusters that have been combined to this cluster + hits: ObjectID[]; // hits that have been combined to this cluster + }; + + /** Reconstructed Particle */ + export type ReconstructedParticle = { + PDG: number; // PDG of the reconstructed particle. + energy: number; // [GeV] energy of the reconstructed particle. Four momentum state is not kept consistent internally + momentum: Vector3f; // [GeV] particle momentum. Four momentum state is not kept consistent internally + referencePoint: Vector3f; // [mm] reference, i.e. where the particle has been measured + charge: number; // [e] charge of the reconstructed particle + mass: number; // [GeV] mass of the reconstructed particle, set independently from four vector. Four momentum state is not kept consistent internally + goodnessOfPID: number; // overall goodness of the PID on a scale of [0;1] + covMatrix: CovMatrix4f; // [GeV^2] covariance matrix of the reconstructed particle 4vector + decayVertex: ObjectID; // decay vertex for the particle (if it is a composite particle) + clusters: ObjectID[]; // clusters that have been used for this particle + tracks: ObjectID[]; // tracks that have been used for this particle + particles: ObjectID[]; // reconstructed particles that have been combined to this particle + }; + + /** Event Header. Additional parameters are assumed to go into the metadata tree. */ + export type EventHeader = { + eventNumber: bigint; // event number + runNumber: number; // run number + timeStamp: bigint; // time stamp + weight: number; // event weight + weights: number[]; // event weights in case there are multiple. **NOTE that weights[0] might not be the same as weight!** Event weight names should be stored using the edm4hep::EventWeights name in the file level metadata + }; + + /** Link between a ReconstructedParticle and an MCParticle */ + export type RecoMCParticleLink = { + weight: number; // weight of this link + from: ObjectID; // reference to the reconstructed particle + to: ObjectID; // reference to the Monte-Carlo particle + }; + + /** The Monte Carlo particle - based on the lcio::MCParticle. */ + export type MCParticle = { + PDG: number; // PDG code of the particle + generatorStatus: number; // status of the particle as defined by the generator + simulatorStatus: number; // status of the particle from the simulation program - use BIT constants below + charge: number; // [e] particle charge + time: number; // [ns] creation time of the particle in wrt. the event, e.g. for preassigned decays or decays in flight from the simulator + mass: number; // [GeV] mass of the particle + vertex: Vector3d; // [mm] production vertex of the particle + endpoint: Vector3d; // [mm] endpoint of the particle + momentum: Vector3d; // [GeV] particle 3-momentum at the production vertex + momentumAtEndpoint: Vector3d; // [GeV] particle 3-momentum at the endpoint + spin: Vector3f; // spin (helicity) vector of the particle + parents: ObjectID[]; // The parents of this particle + daughters: ObjectID[]; // The daughters this particle + }; + + export type Coll = + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::EventHeaderCollection'; + collection: EventHeader[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::VertexCollection'; + collection: Vertex[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::TrackCollection'; + collection: Track[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::TrackerHit3DCollection'; + collection: TrackerHit3D[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::TrackerHitPlaneCollection'; + collection: TrackerHitPlane[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::SimTrackerHitCollection'; + collection: SimTrackerHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::CalorimeterHitCollection'; + collection: CalorimeterHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::SimCalorimeterHitCollection'; + collection: SimCalorimeterHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::ClusterCollection'; + collection: Cluster[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::ReconstructedParticleCollection'; + collection: ReconstructedParticle[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'podio::LinkCollection'; + collection: RecoMCParticleLink[]; + }; +} diff --git a/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/schema4.ts b/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/schema4.ts new file mode 100644 index 000000000..002aafc1e --- /dev/null +++ b/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/schema4.ts @@ -0,0 +1,253 @@ +/* eslint-disable @typescript-eslint/no-namespace */ +import { + CovMatrix3f, + CovMatrix4f, + CovMatrix6f, + Vector2f, + Vector3f, + Vector3d, + ObjectID, +} from './utils'; + +export namespace Schema4 { + /** Vertex */ + export type Vertex = { + type: number; // flagword that defines the type of the vertex, see reserved bits for more information + chi2: number; // chi-squared of the vertex fit + ndf: number; // number of degrees of freedom of the vertex fit + position: Vector3f; // [mm] position of the vertex + covMatrix: CovMatrix3f; // [mm^2] covariance matrix of the position + algorithmType: number; // type code for the algorithm that has been used to create the vertex + parameters: number[]; // additional parameters related to this vertex + particles: ObjectID[]; // particles that have been used to form this vertex, aka the decay particles emerging from this vertex + }; + + /** Parametrized description of a particle track */ + export type TrackState = { + location: number; // for use with At{Other|IP|FirstHit|LastHit|Calorimeter|Vertex}|LastLocation + D0: number; // transverse impact parameter + phi: number; // [rad] azimuthal angle of the track at this location (i.e. not phi0) + omega: number; // [1/mm] is the signed curvature of the track + Z0: number; // longitudinal impact parameter + tanLambda: number; // lambda is the dip angle of the track in r-z + time: number; // [ns] time of the track at this trackstate + referencePoint: Vector3f; // [mm] Reference point of the track parameters, e.g. the origin at the IP, or the position of the first/last hits or the entry point into the calorimeter + covMatrix: CovMatrix6f; // covariance matrix of the track parameters. + }; + + /** Reconstructed track */ + export type Track = { + type: number; // flagword that defines the type of track + chi2: number; // chi-squared of the track fit + ndf: number; // number of degrees of freedom of the track fit + Nholes: number; // number of holes on track + subdetectorHitNumbers: number[]; // number of hits in particular subdetectors + subdetectorHoleNumbers: number[]; // number of holes in particular subdetectors + trackStates: TrackState[]; // track states + trackerHits: ObjectID[]; // hits that have been used to create this track + tracks: ObjectID[]; // tracks (segments) that have been combined to create this track + }; + + /** Tracker hit interface class */ + // Types: TrackerHit3D, TrackerHitPlane + interface TrackerHit { + cellID: bigint; // ID of the sensor that created this hit + type: number; // type of the raw data hit + quality: number; // quality bit flag of the hit + time: number; // [ns] time of the hit + eDep: number; // [GeV] energy deposited on the hit + eDepError: number; // [GeV] error measured on eDep + position: Vector3d; // [mm] hit position + } + + /** Tracker hit */ + export interface TrackerHit3D extends TrackerHit { + cellID: bigint; // ID of the sensor that created this hit + type: number; // type of raw data hit + quality: number; // quality bit flag of the hit + time: number; // [ns] time of the hit + eDep: number; // [GeV] energy deposited on the hit + eDepError: number; // [GeV] error measured on eDep + position: Vector3d; // [mm] hit position + covMatrix: CovMatrix3f; // [mm^2] covariance matrix of the position (x,y,z) + } + + /** Tracker hit plane */ + export interface TrackerHitPlane extends TrackerHit { + cellID: bigint; // ID of the sensor that created this hit + type: number; // type of raw data hit + quality: number; // quality bit flag of the hit + time: number; // [ns] time of the hit + eDep: number; // [GeV] energy deposited on the hit + eDepError: number; // [GeV] error measured on eDep + u: Vector2f; // measurement direction vector, u lies in the x-y plane + v: Vector2f; // measurement direction vector, v is along z + du: number; // measurement error along the direction + dv: number; // measurement error along the direction + position: Vector3d; // [mm] hit position + covMatrix: CovMatrix3f; // [mm^2] covariance of the position (x,y,z) + } + + /** Simulated tracker hit */ + export type SimTrackerHit = { + cellID: bigint; // ID of the sensor that created this hit + eDep: number; // [GeV] energy deposited in the hit + time: number; // [ns] proper time of the hit in the lab frame + pathLength: number; // path length of the particle in the sensitive material that resulted in this hit + quality: number; // quality bit flag + position: Vector3d; // [mm] the hit position + momentum: Vector3f; // [GeV] the 3-momentum of the particle at the hits position + particle: ObjectID[]; // MCParticle that caused the hit + }; + + /** Calorimeter hit */ + export type CalorimeterHit = { + cellID: bigint; // detector specific (geometrical) cell id + energy: number; // [GeV] energy of the hit + energyError: number; // [GeV] error of the hit energy + time: number; // [ns] time of the hit + position: Vector3f; // [mm] position of the hit in world coordinates + type: number; // type of hit + }; + + /** Simulated calorimeter hit */ + export type SimCalorimeterHit = { + cellID: bigint; // ID of the sensor that created this hit + energy: number; // [GeV] energy of the hit + position: Vector3f; // [mm] position of the hit in world coordinates + contributions: ObjectID[]; // Monte Carlo step contributions + }; + + /** Calorimeter Hit Cluster */ + export type Cluster = { + type: number; // flagword that defines the type of cluster + energy: number; // [GeV] energy of the cluster + energyError: number; // [GeV] error on the energy + position: Vector3f; // [mm] position of the cluster + positionError: CovMatrix3f; // [mm^2] covariance matrix of the position + iTheta: number; // [rad] Polar angle of the cluster's intrinsic direction (used e.g. for vertexing). Not to be confused with the cluster position seen from IP + phi: number; // [rad] Azimuthal angle of the cluster's intrinsic direction (used e.g. for vertexing). Not to be confused with the cluster position seen from IP + directionError: Vector3f; // [mm^2] covariance matrix of the direction + shapeParameters: number[]; // shape parameters. The corresponding names of the shape parameters should be stored in the collection named by edm4hep::labels::ShapeParameterNames in the file-level metadata, as a vector of strings in the same order as the parameters. + subdetectorEnergies: number[]; // energy observed in a particular subdetector + clusters: ObjectID[]; // clusters that have been combined to this cluster + hits: ObjectID[]; // hits that have been combined to this cluster + }; + + /** Reconstructed Particle */ + export type ReconstructedParticle = { + PDG: number; // PDG of the reconstructed particle. + energy: number; // [GeV] energy of the reconstructed particle. Four momentum state is not kept consistent internally + momentum: Vector3f; // [GeV] particle momentum. Four momentum state is not kept consistent internally + referencePoint: Vector3f; // [mm] reference, i.e. where the particle has been measured + charge: number; // [e] charge of the reconstructed particle + mass: number; // [GeV] mass of the reconstructed particle, set independently from four vector. Four momentum state is not kept consistent internally + goodnessOfPID: number; // overall goodness of the PID on a scale of [0;1] + covMatrix: CovMatrix4f; // [GeV^2] covariance matrix of the reconstructed particle 4vector + decayVertex: ObjectID; // decay vertex for the particle (if it is a composite particle) + clusters: ObjectID[]; // clusters that have been used for this particle + tracks: ObjectID[]; // tracks that have been used for this particle + particles: ObjectID[]; // reconstructed particles that have been combined to this particle + }; + + /** Event Header. Additional parameters are assumed to go into the metadata tree. */ + export type EventHeader = { + eventNumber: bigint; // event number + runNumber: number; // run number + timeStamp: bigint; // time stamp + weight: number; // event weight + weights: number[]; // event weights in case there are multiple. **NOTE that weights[0] might not be the same as weight!** The corresponding names of the event weights should be stored in the collection named by edm4hep::labels::EventWeightsNames in the file-level metadata. + }; + + /** Link between a ReconstructedParticle and an MCParticle */ + export type RecoMCParticleLink = { + weight: number; // weight of this link + from: ObjectID; // reference to the reconstructed particle + to: ObjectID; // reference to the Monte-Carlo particle + }; + + /** The Monte Carlo particle - based on the lcio::MCParticle. */ + export type MCParticle = { + PDG: number; // PDG code of the particle + generatorStatus: number; // status of the particle as defined by the generator + simulatorStatus: number; // status of the particle from the simulation program - use BIT constants below + charge: number; // [e] particle charge + time: number; // [ns] creation time of the particle in wrt. the event, e.g. for preassigned decays or decays in flight from the simulator + mass: number; // [GeV] mass of the particle + vertex: Vector3d; // [mm] production vertex of the particle + endpoint: Vector3d; // [mm] endpoint of the particle + momentum: Vector3d; // [GeV] particle 3-momentum at the production vertex + momentumAtEndpoint: Vector3d; // [GeV] particle 3-momentum at the endpoint + helicity: number; // particle helicity (9 if unset) + parents: ObjectID[]; // The parents of this particle + daughters: ObjectID[]; // The daughters this particle + }; + + export type Coll = + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::EventHeaderCollection'; + collection: EventHeader[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::VertexCollection'; + collection: Vertex[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::TrackCollection'; + collection: Track[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::TrackerHit3DCollection'; + collection: TrackerHit3D[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::TrackerHitPlaneCollection'; + collection: TrackerHitPlane[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::SimTrackerHitCollection'; + collection: SimTrackerHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::CalorimeterHitCollection'; + collection: CalorimeterHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::SimCalorimeterHitCollection'; + collection: SimCalorimeterHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::ClusterCollection'; + collection: Cluster[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::ReconstructedParticleCollection'; + collection: ReconstructedParticle[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'podio::LinkCollection'; + collection: RecoMCParticleLink[]; + }; +} diff --git a/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/schema5.ts b/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/schema5.ts new file mode 100644 index 000000000..7e39776b5 --- /dev/null +++ b/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/schema5.ts @@ -0,0 +1,290 @@ +/* eslint-disable @typescript-eslint/no-namespace */ +import { + CovMatrix3f, + CovMatrix4f, + CovMatrix6f, + Vector2f, + Vector3f, + Vector3d, + ObjectID, +} from './utils'; + +export namespace Schema5 { + /** Vertex */ + export type Vertex = { + type: number; // flagword that defines the type of the vertex, see reserved bits for more information + chi2: number; // chi-squared of the vertex fit + ndf: number; // number of degrees of freedom of the vertex fit + position: Vector3f; // [mm] position of the vertex + covMatrix: CovMatrix3f; // [mm^2] covariance matrix of the position + algorithmType: number; // type code for the algorithm that has been used to create the vertex + parameters: number[]; // additional parameters related to this vertex + particles: ObjectID[]; // particles that have been used to form this vertex, aka the decay particles emerging from this vertex + }; + + /** Parametrized description of a particle track */ + export type TrackState = { + location: number; // for use with At{Other|IP|FirstHit|LastHit|Calorimeter|Vertex}|LastLocation + D0: number; // transverse impact parameter + phi: number; // [rad] azimuthal angle of the track at this location (i.e. not phi0) + omega: number; // [1/mm] is the signed curvature of the track + Z0: number; // longitudinal impact parameter + tanLambda: number; // lambda is the dip angle of the track in r-z + time: number; // [ns] time of the track at this trackstate + referencePoint: Vector3f; // [mm] Reference point of the track parameters, e.g. the origin at the IP, or the position of the first/last hits or the entry point into the calorimeter + covMatrix: CovMatrix6f; // covariance matrix of the track parameters. + }; + + /** Reconstructed track */ + export type Track = { + type: number; // flagword that defines the type of track + chi2: number; // chi-squared of the track fit + ndf: number; // number of degrees of freedom of the track fit + Nholes: number; // number of holes on track + subdetectorHitNumbers: number[]; // number of hits in particular subdetectors + subdetectorHoleNumbers: number[]; // number of holes in particular subdetectors + trackStates: TrackState[]; // track states + trackerHits: ObjectID[]; // hits that have been used to create this track + tracks: ObjectID[]; // tracks (segments) that have been combined to create this track + }; + + /** Tracker hit interface class */ + // Types: TrackerHit3D, TrackerHitPlane, SenseWireHit + interface TrackerHit { + cellID: bigint; // ID of the sensor that created this hit + type: number; // type of the raw data hit + quality: number; // quality bit flag of the hit + time: number; // [ns] time of the hit + eDep: number; // [GeV] energy deposited on the hit + eDepError: number; // [GeV] error measured on eDep + position: Vector3d; // [mm] hit position as recorded by the sensor. The exact interpretation will depend on the currently held type of the interface + } + + /** Tracker hit */ + export interface TrackerHit3D extends TrackerHit { + cellID: bigint; // ID of the sensor that created this hit + type: number; // type of raw data hit + quality: number; // quality bit flag of the hit + time: number; // [ns] time of the hit + eDep: number; // [GeV] energy deposited on the hit + eDepError: number; // [GeV] error measured on eDep + position: Vector3d; // [mm] hit position + covMatrix: CovMatrix3f; // [mm^2] covariance matrix of the position (x,y,z) + } + + /** Tracker hit plane */ + export interface TrackerHitPlane extends TrackerHit { + cellID: bigint; // ID of the sensor that created this hit + type: number; // type of raw data hit + quality: number; // quality bit flag of the hit + time: number; // [ns] time of the hit + eDep: number; // [GeV] energy deposited on the hit + eDepError: number; // [GeV] error measured on eDep + u: Vector2f; // [rad] direction of the first measurement given as (theta, phi) in spherical coordinates + v: Vector2f; // [rad] direction of the second measurement given as (theta, phi) in spherical coordinates + du: number; // [mm] measurement error along the direction + dv: number; // [mm] measurement error along the direction + position: Vector3d; // [mm] hit position + covMatrix: CovMatrix3f; // [mm^2] covariance of the position (x,y,z) + } + + /** Sense wire hit, knowing only the distance to the wire. The circle representing possible positions is parametrized with its center, radius and normal vector (given by the wire direction). */ + export interface SenseWireHit extends TrackerHit { + cellID: bigint; // ID of the sensor that created this hit + type: number; // type of the raw data hit + quality: number; // quality bit flag of the hit + time: number; // [ns] time of the hit + eDep: number; // [GeV] energy deposited by the hit + eDepError: number; // [GeV] error on eDep + wireStereoAngle: number; // angle between the sense wire axis and the drift chamber axis (usually the z-axis) - use it together with wireAzimuthalAngle to get the wire direction + wireAzimuthalAngle: number; // azimuthal angle at the middle of the sense wire - use it together with wireStereoAngle to get the wire direction + position: Vector3d; // [mm] point on the sense wire which is closest to the hit (center of the circle) + positionAlongWireError: number; // [mm] error on the hit position along the wire direction + distanceToWire: number; // [mm] distance between the hit and the wire (radius of the circle) + distanceToWireError: number; // [mm] error on distanceToWire + nElectrons: number[]; // number of electrons for each cluster (number of clusters = vector size) + } + + /** Simulated tracker hit */ + export type SimTrackerHit = { + cellID: bigint; // ID of the sensor that created this hit + eDep: number; // [GeV] energy deposited in the hit + time: number; // [ns] proper time of the hit in the lab frame + pathLength: number; // path length of the particle in the sensitive material that resulted in this hit + quality: number; // quality bit flag + position: Vector3d; // [mm] the hit position + momentum: Vector3f; // [GeV] the 3-momentum of the particle at the hits position + particle: ObjectID[]; // MCParticle that caused the hit + }; + + /** Calorimeter hit */ + export type CalorimeterHit = { + cellID: bigint; // detector specific (geometrical) cell id + energy: number; // [GeV] energy of the hit + energyError: number; // [GeV] error of the hit energy + time: number; // [ns] time of the hit + position: Vector3f; // [mm] position of the hit in world coordinates + type: number; // type of hit + }; + + /** Simulated calorimeter hit */ + export type SimCalorimeterHit = { + cellID: bigint; // ID of the sensor that created this hit + energy: number; // [GeV] energy of the hit + position: Vector3f; // [mm] position of the hit in world coordinates + contributions: ObjectID[]; // Monte Carlo step contributions + }; + + /** Calorimeter Hit Cluster */ + export type Cluster = { + type: number; // flagword that defines the type of cluster + energy: number; // [GeV] energy of the cluster + energyError: number; // [GeV] error on the energy + position: Vector3f; // [mm] position of the cluster + positionError: CovMatrix3f; // [mm^2] covariance matrix of the position + iTheta: number; // [rad] Polar angle of the cluster's intrinsic direction (used e.g. for vertexing). Not to be confused with the cluster position seen from IP + phi: number; // [rad] Azimuthal angle of the cluster's intrinsic direction (used e.g. for vertexing). Not to be confused with the cluster position seen from IP + directionError: Vector3f; // [mm^2] covariance matrix of the direction + shapeParameters: number[]; // shape parameters. The corresponding names of the shape parameters should be stored in the collection named by edm4hep::labels::ShapeParameterNames in the file-level metadata, as a vector of strings in the same order as the parameters. + subdetectorEnergies: number[]; // energy observed in a particular subdetector + clusters: ObjectID[]; // clusters that have been combined to this cluster + hits: ObjectID[]; // hits that have been combined to this cluster + }; + + /** Reconstructed Particle */ + export type ReconstructedParticle = { + PDG: number; // PDG of the reconstructed particle. + energy: number; // [GeV] energy of the reconstructed particle. Four momentum state is not kept consistent internally + momentum: Vector3f; // [GeV] particle momentum. Four momentum state is not kept consistent internally + referencePoint: Vector3f; // [mm] reference, i.e. where the particle has been measured + charge: number; // [e] charge of the reconstructed particle + mass: number; // [GeV] mass of the reconstructed particle, set independently from four vector. Four momentum state is not kept consistent internally + goodnessOfPID: number; // overall goodness of the PID on a scale of [0;1] + covMatrix: CovMatrix4f; // [GeV^2] covariance matrix of the reconstructed particle 4vector + decayVertex: ObjectID; // decay vertex for the particle (if it is a composite particle) + clusters: ObjectID[]; // clusters that have been used for this particle + tracks: ObjectID[]; // tracks that have been used for this particle + particles: ObjectID[]; // reconstructed particles that have been combined to this particle + }; + + /** Event Header. Additional parameters are assumed to go into the metadata tree. */ + export type EventHeader = { + eventNumber: bigint; // event number + runNumber: number; // run number + timeStamp: bigint; // time stamp + weight: number; // event weight + weights: number[]; // event weights in case there are multiple. **NOTE that weights[0] might not be the same as weight!** The corresponding names of the event weights should be stored in the collection named by edm4hep::labels::EventWeightsNames in the file-level metadata. + }; + + /** Link between a ReconstructedParticle and an MCParticle */ + export type RecoMCParticleLink = { + weight: number; // weight of this link + from: ObjectID; // reference to the reconstructed particle + to: ObjectID; // reference to the Monte-Carlo particle + }; + + /** The Monte Carlo particle - based on the lcio::MCParticle. */ + export type MCParticle = { + PDG: number; // PDG code of the particle + generatorStatus: number; // status of the particle as defined by the generator + simulatorStatus: number; // status of the particle from the simulation program - use BIT constants below + charge: number; // [e] particle charge + time: number; // [ns] creation time of the particle in wrt. the event, e.g. for preassigned decays or decays in flight from the simulator + mass: number; // [GeV] mass of the particle + vertex: Vector3d; // [mm] production vertex of the particle + endpoint: Vector3d; // [mm] endpoint of the particle + momentum: Vector3d; // [GeV] particle 3-momentum at the production vertex + momentumAtEndpoint: Vector3d; // [GeV] particle 3-momentum at the endpoint + helicity: number; // particle helicity (9 if unset) + parents: ObjectID[]; // The parents of this particle + daughters: ObjectID[]; // The daughters this particle + }; + + export type EventHeaderCollection = EventHeader[]; + export type VertexCollection = Vertex[]; + export type TrackCollection = Track[]; + export type TrackerHit3DCollection = TrackerHit3D[]; + export type TrackerHitPlaneCollection = TrackerHitPlane[]; + export type SenseWireHitCollection = SenseWireHit[]; + export type SimTrackerHitCollection = SimTrackerHit[]; + export type CalorimeterHitCollection = CalorimeterHit[]; + export type SimCalorimeterHitCollection = SimCalorimeterHit[]; + export type ClusterCollection = Cluster[]; + export type ReconstructedParticleCollection = ReconstructedParticle[]; + export type RecoMCParticleLinkCollection = RecoMCParticleLink[]; + export type MCParticleCollection = MCParticle[]; + + export type Coll = + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::EventHeaderCollection'; + collection: EventHeader[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::VertexCollection'; + collection: Vertex[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::TrackCollection'; + collection: Track[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::TrackerHit3DCollection'; + collection: TrackerHit3D[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::TrackerHitPlaneCollection'; + collection: TrackerHitPlane[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::SenseWireHitCollection'; + collection: SenseWireHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::SimTrackerHitCollection'; + collection: SimTrackerHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::CalorimeterHitCollection'; + collection: CalorimeterHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::SimCalorimeterHitCollection'; + collection: SimCalorimeterHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::ClusterCollection'; + collection: Cluster[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::ReconstructedParticleCollection'; + collection: ReconstructedParticle[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'podio::LinkCollection'; + collection: RecoMCParticleLink[]; + }; +} diff --git a/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/schema6.ts b/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/schema6.ts new file mode 100644 index 000000000..dce8a808b --- /dev/null +++ b/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/schema6.ts @@ -0,0 +1,276 @@ +/* eslint-disable @typescript-eslint/no-namespace */ +import { + CovMatrix3f, + CovMatrix4f, + CovMatrix6f, + Vector2f, + Vector3f, + Vector3d, + ObjectID, +} from './utils'; + +export namespace Schema6 { + /** Vertex */ + export type Vertex = { + type: number; // flagword that defines the type of the vertex, see reserved bits for more information + chi2: number; // chi-squared of the vertex fit + ndf: number; // number of degrees of freedom of the vertex fit + position: Vector3f; // [mm] position of the vertex + covMatrix: CovMatrix3f; // [mm^2] covariance matrix of the position + algorithmType: number; // type code for the algorithm that has been used to create the vertex + parameters: number[]; // additional parameters related to this vertex + particles: ObjectID[]; // particles that have been used to form this vertex, aka the decay particles emerging from this vertex + }; + + /** Parametrized description of a particle track */ + export type TrackState = { + location: number; // for use with At{Other|IP|FirstHit|LastHit|Calorimeter|Vertex}|LastLocation + D0: number; // transverse impact parameter + phi: number; // [rad] azimuthal angle of the track at this location (i.e. not phi0) + omega: number; // [1/mm] is the signed curvature of the track + Z0: number; // longitudinal impact parameter + tanLambda: number; // lambda is the dip angle of the track in r-z + time: number; // [ns] time of the track at this trackstate + referencePoint: Vector3f; // [mm] Reference point of the track parameters, e.g. the origin at the IP, or the position of the first/last hits or the entry point into the calorimeter + covMatrix: CovMatrix6f; // covariance matrix of the track parameters. + }; + + /** Reconstructed track */ + export type Track = { + type: number; // flagword that defines the type of track + chi2: number; // chi-squared of the track fit + ndf: number; // number of degrees of freedom of the track fit + Nholes: number; // number of holes on track + subdetectorHitNumbers: number[]; // number of hits in particular subdetectors + subdetectorHoleNumbers: number[]; // number of holes in particular subdetectors + trackStates: TrackState[]; // track states + trackerHits: ObjectID[]; // hits that have been used to create this track + tracks: ObjectID[]; // tracks (segments) that have been combined to create this track + }; + + /** Tracker hit interface class */ + // Types: TrackerHit3D, TrackerHitPlane, SenseWireHit + interface TrackerHit { + cellID: bigint; // ID of the sensor that created this hit + type: number; // type of the raw data hit + quality: number; // quality bit flag of the hit + time: number; // [ns] time of the hit + eDep: number; // [GeV] energy deposited on the hit + eDepError: number; // [GeV] error measured on eDep + position: Vector3d; // [mm] hit position as recorded by the sensor. The exact interpretation will depend on the currently held type of the interface + } + + /** Tracker hit */ + export interface TrackerHit3D extends TrackerHit { + cellID: bigint; // ID of the sensor that created this hit + type: number; // type of raw data hit + quality: number; // quality bit flag of the hit + time: number; // [ns] time of the hit + eDep: number; // [GeV] energy deposited on the hit + eDepError: number; // [GeV] error measured on eDep + position: Vector3d; // [mm] hit position + covMatrix: CovMatrix3f; // [mm^2] covariance matrix of the position (x,y,z) + } + + /** Tracker hit plane */ + export interface TrackerHitPlane extends TrackerHit { + cellID: bigint; // ID of the sensor that created this hit + type: number; // type of raw data hit + quality: number; // quality bit flag of the hit + time: number; // [ns] time of the hit + eDep: number; // [GeV] energy deposited on the hit + eDepError: number; // [GeV] error measured on eDep + u: Vector2f; // [rad] direction of the first measurement given as (theta, phi) in spherical coordinates + v: Vector2f; // [rad] direction of the second measurement given as (theta, phi) in spherical coordinates + du: number; // [mm] measurement error along the direction + dv: number; // [mm] measurement error along the direction + position: Vector3d; // [mm] hit position + covMatrix: CovMatrix3f; // [mm^2] covariance of the position (x,y,z) + } + + /** Sense wire hit, knowing only the distance to the wire. The circle representing possible positions is parametrized with its center, radius and normal vector (given by the wire direction). */ + export interface SenseWireHit extends TrackerHit { + cellID: bigint; // ID of the sensor that created this hit + type: number; // type of the raw data hit + quality: number; // quality bit flag of the hit + time: number; // [ns] time of the hit + eDep: number; // [GeV] energy deposited by the hit + eDepError: number; // [GeV] error on eDep + wireStereoAngle: number; // angle between the sense wire axis and the drift chamber axis (usually the z-axis) - use it together with wireAzimuthalAngle to get the wire direction + wireAzimuthalAngle: number; // azimuthal angle at the middle of the sense wire - use it together with wireStereoAngle to get the wire direction + position: Vector3d; // [mm] point on the sense wire which is closest to the hit (center of the circle) + positionAlongWireError: number; // [mm] error on the hit position along the wire direction + distanceToWire: number; // [mm] distance between the hit and the wire (radius of the circle) + distanceToWireError: number; // [mm] error on distanceToWire + nElectrons: number[]; // number of electrons for each cluster (number of clusters = vector size) + } + + /** Simulated tracker hit */ + export type SimTrackerHit = { + cellID: bigint; // ID of the sensor that created this hit + eDep: number; // [GeV] energy deposited in the hit + time: number; // [ns] proper time of the hit in the lab frame + pathLength: number; // path length of the particle in the sensitive material that resulted in this hit + quality: number; // quality bit flag + position: Vector3d; // [mm] the hit position + momentum: Vector3f; // [GeV] the 3-momentum of the particle at the hits position + particle: ObjectID[]; // MCParticle that caused the hit + }; + + /** Calorimeter hit */ + export type CalorimeterHit = { + cellID: bigint; // detector specific (geometrical) cell id + energy: number; // [GeV] energy of the hit + energyError: number; // [GeV] error of the hit energy + time: number; // [ns] time of the hit + position: Vector3f; // [mm] position of the hit in world coordinates + type: number; // type of hit + }; + + /** Simulated calorimeter hit */ + export type SimCalorimeterHit = { + cellID: bigint; // ID of the sensor that created this hit + energy: number; // [GeV] energy of the hit + position: Vector3f; // [mm] position of the hit in world coordinates + contributions: ObjectID[]; // Monte Carlo step contributions + }; + + /** Calorimeter Hit Cluster */ + export type Cluster = { + type: number; // flagword that defines the type of cluster + energy: number; // [GeV] energy of the cluster + energyError: number; // [GeV] error on the energy + position: Vector3f; // [mm] position of the cluster + positionError: CovMatrix3f; // [mm^2] covariance matrix of the position + iTheta: number; // [rad] Polar angle of the cluster's intrinsic direction (used e.g. for vertexing). Not to be confused with the cluster position seen from IP + iPhi: number; // [rad] Azimuthal angle of the cluster's intrinsic direction (used e.g. for vertexing). Not to be confused with the cluster position seen from IP + directionError: Vector3f; // [mm^2] covariance matrix of the direction + shapeParameters: number[]; // shape parameters. The corresponding names of the shape parameters should be stored in the collection named by edm4hep::labels::ShapeParameterNames in the file-level metadata, as a vector of strings in the same order as the parameters. + subdetectorEnergies: number[]; // energy observed in a particular subdetector + clusters: ObjectID[]; // clusters that have been combined to this cluster + hits: ObjectID[]; // hits that have been combined to this cluster + }; + + /** Reconstructed Particle */ + export type ReconstructedParticle = { + PDG: number; // PDG of the reconstructed particle. + energy: number; // [GeV] energy of the reconstructed particle. Four momentum state is not kept consistent internally + momentum: Vector3f; // [GeV] particle momentum. Four momentum state is not kept consistent internally + referencePoint: Vector3f; // [mm] reference, i.e. where the particle has been measured + charge: number; // [e] charge of the reconstructed particle + mass: number; // [GeV] mass of the reconstructed particle, set independently from four vector. Four momentum state is not kept consistent internally + goodnessOfPID: number; // overall goodness of the PID on a scale of [0;1] + covMatrix: CovMatrix4f; // [GeV^2] covariance matrix of the reconstructed particle 4vector + decayVertex: ObjectID; // decay vertex for the particle (if it is a composite particle) + clusters: ObjectID[]; // clusters that have been used for this particle + tracks: ObjectID[]; // tracks that have been used for this particle + particles: ObjectID[]; // reconstructed particles that have been combined to this particle + }; + + /** Event Header. Additional parameters are assumed to go into the metadata tree. */ + export type EventHeader = { + eventNumber: bigint; // event number + runNumber: number; // run number + timeStamp: bigint; // time stamp + weight: number; // event weight + weights: number[]; // event weights in case there are multiple. **NOTE that weights[0] might not be the same as weight!** The corresponding names of the event weights should be stored in the collection named by edm4hep::labels::EventWeightsNames in the file-level metadata. + }; + + /** Link between a ReconstructedParticle and an MCParticle */ + export type RecoMCParticleLink = { + weight: number; // weight of this link + from: ObjectID; // reference to the reconstructed particle + to: ObjectID; // reference to the Monte-Carlo particle + }; + + /** The Monte Carlo particle - based on the lcio::MCParticle. */ + export type MCParticle = { + PDG: number; // PDG code of the particle + generatorStatus: number; // status of the particle as defined by the generator + simulatorStatus: number; // status of the particle from the simulation program - use BIT constants below + charge: number; // [e] particle charge + time: number; // [ns] creation time of the particle in wrt. the event, e.g. for preassigned decays or decays in flight from the simulator + mass: number; // [GeV] mass of the particle + vertex: Vector3d; // [mm] production vertex of the particle + endpoint: Vector3d; // [mm] endpoint of the particle + momentum: Vector3d; // [GeV] particle 3-momentum at the production vertex + momentumAtEndpoint: Vector3d; // [GeV] particle 3-momentum at the endpoint + helicity: number; // particle helicity (9 if unset) + parents: ObjectID[]; // The parents of this particle + daughters: ObjectID[]; // The daughters this particle + }; + + export type Coll = + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::EventHeaderCollection'; + collection: EventHeader[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::VertexCollection'; + collection: Vertex[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::TrackCollection'; + collection: Track[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::TrackerHit3DCollection'; + collection: TrackerHit3D[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::TrackerHitPlaneCollection'; + collection: TrackerHitPlane[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::SenseWireHitCollection'; + collection: SenseWireHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::SimTrackerHitCollection'; + collection: SimTrackerHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::CalorimeterHitCollection'; + collection: CalorimeterHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::SimCalorimeterHitCollection'; + collection: SimCalorimeterHit[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::ClusterCollection'; + collection: Cluster[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'edm4hep::ReconstructedParticleCollection'; + collection: ReconstructedParticle[]; + } + | { + collID: number; + collSchemaVersion: number; + collType: 'podio::LinkCollection'; + collection: RecoMCParticleLink[]; + }; +} diff --git a/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/utils.ts b/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/utils.ts new file mode 100644 index 000000000..850a0ced1 --- /dev/null +++ b/packages/phoenix-event-display/src/lib/types/edm4hep-schemas/utils.ts @@ -0,0 +1,41 @@ +/** A generic 3 dimensional covariance matrix with values stored in lower triangular form */ +export type CovMatrix3f = { + values: number[]; // the covariance matrix values +}; + +/** A generic 4 dimensional covariance matrix with values stored in lower triangular form */ +export type CovMatrix4f = { + values: number[]; // the covariance matrix values +}; + +/** A generic 6 dimensional covariance matrix with values stored in lower triangular form */ +export type CovMatrix6f = { + values: number[]; // the covariance matrix values +}; + +export type Vector2f = { + a: number; + b: number; +}; + +export type Vector2i = { + a: number; + b: number; +}; + +export type Vector3f = { + x: number; + y: number; + z: number; +}; + +export type Vector3d = { + x: number; + y: number; + z: number; +}; + +export type ObjectID = { + collectionID: number; + index: number; +}; diff --git a/packages/phoenix-event-display/src/lib/types/edm4hep.ts b/packages/phoenix-event-display/src/lib/types/edm4hep.ts new file mode 100644 index 000000000..9b8126b4b --- /dev/null +++ b/packages/phoenix-event-display/src/lib/types/edm4hep.ts @@ -0,0 +1,141 @@ +/* eslint-disable @typescript-eslint/no-namespace */ +import { Schema1 } from './edm4hep-schemas/schema1'; +import { Schema2 } from './edm4hep-schemas/schema2'; +import { Schema3 } from './edm4hep-schemas/schema3'; +import { Schema4 } from './edm4hep-schemas/schema4'; +import { Schema5 } from './edm4hep-schemas/schema5'; +import { Schema6 } from './edm4hep-schemas/schema6'; + +export namespace edm4hep { + export type Vertex = + | Schema1.Vertex + | Schema2.Vertex + | Schema3.Vertex + | Schema4.Vertex + | Schema5.Vertex + | Schema6.Vertex; + + export type TrackState = + | Schema1.TrackState + | Schema2.TrackState + | Schema3.TrackState + | Schema4.TrackState + | Schema5.TrackState + | Schema6.TrackState; + + export type Track = ( + | Schema1.Track + | Schema2.Track + | Schema3.Track + | Schema4.Track + | Schema5.Track + | Schema6.Track + ) & { + // MUTATED PROPERTIES + pid: string; + }; + + export type Hit = + | Schema1.TrackerHit + | Schema1.SimTrackerHit + | Schema2.TrackerHit3D + | Schema2.TrackerHitPlane + | Schema2.SimTrackerHit + | Schema3.TrackerHit3D + | Schema3.TrackerHitPlane + | Schema3.SimTrackerHit + | Schema4.TrackerHit3D + | Schema4.TrackerHitPlane + | Schema4.SimTrackerHit + | Schema5.TrackerHit3D + | Schema5.TrackerHitPlane + | Schema5.SenseWireHit + | Schema5.SimTrackerHit + | Schema6.TrackerHit3D + | Schema6.TrackerHitPlane + | Schema6.SenseWireHit + | Schema6.SimTrackerHit; + + export type CaloCell = + | Schema1.CalorimeterHit + | Schema1.SimCalorimeterHit + | Schema2.CalorimeterHit + | Schema2.SimCalorimeterHit + | Schema3.CalorimeterHit + | Schema3.SimCalorimeterHit + | Schema4.CalorimeterHit + | Schema4.SimCalorimeterHit + | Schema5.CalorimeterHit + | Schema5.SimCalorimeterHit + | Schema6.CalorimeterHit + | Schema6.SimCalorimeterHit; + + export type CaloCluster = + | Schema1.Cluster + | Schema2.Cluster + | Schema3.Cluster + | Schema4.Cluster + | Schema5.Cluster + | Schema6.Cluster; + + export type ReconstructedParticle = + | Schema1.ReconstructedParticle + | Schema2.ReconstructedParticle + | Schema3.ReconstructedParticle + | Schema4.ReconstructedParticle + | Schema5.ReconstructedParticle + | Schema6.ReconstructedParticle; + + export type EventHeader = + | Schema1.EventHeader + | Schema2.EventHeader + | Schema3.EventHeader + | Schema4.EventHeader + | Schema5.EventHeader + | Schema6.EventHeader; + + export type MCParticle = + | Schema1.MCParticle + | Schema2.MCParticle + | Schema3.MCParticle + | Schema4.MCParticle + | Schema5.MCParticle + | Schema6.MCParticle; + + export type Association = Schema1.MCRecoParticleAssociation; + + export type Link = + | Schema2.RecoMCParticleLink + | Schema3.RecoMCParticleLink + | Schema4.RecoMCParticleLink + | Schema5.RecoMCParticleLink + | Schema6.RecoMCParticleLink; + + export type Item = + | Schema1.Coll + | Schema2.Coll + | Schema3.Coll + | Schema4.Coll + | Schema5.Coll + | Schema6.Coll; + + export type Event = { + [name: string]: + | Schema1.Coll + | Schema2.Coll + | Schema3.Coll + | Schema4.Coll + | Schema5.Coll + | Schema6.Coll; + }; + + export enum ParticleType { + Electron = 'electron', + Muon = 'muon', + Photon = 'photon', + Pion = 'pion', + Proton = 'proton', + Kaon = 'kaon', + Other = 'other', + } +} 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 1a4ccfde7..93efd3b1f 100644 --- a/packages/phoenix-event-display/src/loaders/edm4hep-json-loader.ts +++ b/packages/phoenix-event-display/src/loaders/edm4hep-json-loader.ts @@ -1,9 +1,44 @@ import { PhoenixLoader } from './phoenix-loader'; +import { + PhoenixEventData, + VertexParams, + TrackParams, + HitParams, + CaloCellParams, + CaloClusterParams, + JetParams, + MissingEnergyParams, +} from 'src/lib/types/event-data'; +import { edm4hep } from 'src/lib/types/edm4hep'; +import { ObjectID } from 'src/lib/types/edm4hep-schemas/utils'; /** * Edm4hepJsonLoader for loading EDM4hep json dumps */ export class Edm4hepJsonLoader extends PhoenixLoader { + /** PDG ID to particle type name */ + private static readonly pidNames: Record = { + 11: edm4hep.ParticleType.Electron, + 13: edm4hep.ParticleType.Muon, + 22: edm4hep.ParticleType.Photon, + 111: edm4hep.ParticleType.Pion, + 211: edm4hep.ParticleType.Pion, + 2212: edm4hep.ParticleType.Proton, + 321: edm4hep.ParticleType.Kaon, + }; + + /** Colors per particle type, shared between tracks and hits + * Tracks receive hex color without '#' */ + private static readonly pidColors: Record = { + [edm4hep.ParticleType.Electron]: '00ff00', + [edm4hep.ParticleType.Muon]: 'ff00ff', + [edm4hep.ParticleType.Photon]: 'ff0000', + [edm4hep.ParticleType.Pion]: 'a52a2a', + [edm4hep.ParticleType.Proton]: '778899', + [edm4hep.ParticleType.Kaon]: '5f9ea0', + [edm4hep.ParticleType.Other]: '0000cd', + }; + /** Event data loaded from EDM4hep JSON file */ private rawEventData: any; @@ -20,32 +55,77 @@ export class Edm4hepJsonLoader extends PhoenixLoader { /** Process raw EDM4hep JSON event data into the Phoenix format */ processEventData(): boolean { - Object.entries(this.rawEventData).forEach(([eventName, event]) => { - const oneEventData = { - Vertices: {}, - Tracks: {}, - Hits: {}, - CaloCells: {}, - CaloClusters: {}, - Jets: {}, - MissingEnergy: {}, - 'event number': this.getEventNumber(event), - 'run number': this.getRunNumber(event), - }; - - this.colorTracks(event); - - oneEventData.Vertices = this.getVertices(event); - oneEventData.Tracks = this.getTracks(event); - oneEventData.Hits = this.getHits(event); - oneEventData.CaloCells = this.getCells(event); - oneEventData.CaloClusters = this.getCaloClusters(event); - oneEventData.Jets = this.getJets(event); - oneEventData.MissingEnergy = this.getMissingEnergy(event); - - this.eventData[eventName] = oneEventData; - }); + // Iterate over events + Object.entries(this.rawEventData).forEach( + ([eventName, rawEvent]: [string, edm4hep.Event]) => { + const newEvent: PhoenixEventData = { + 'event number': 0, + 'run number': 0, + Vertices: {}, + Tracks: {}, + Hits: {}, + CaloClusters: {}, + CaloCells: {}, + Jets: {}, + MissingEnergy: {}, + }; + this.assignPID(rawEvent); + + // Iterate over event collections + Object.entries(rawEvent).forEach( + ([collName, { collType, collection }]: [string, edm4hep.Item]) => { + switch (collType) { + case 'edm4hep::EventHeaderCollection': + newEvent['event number'] = Number( + collection[0].eventNumber ?? 0, + ); + newEvent['run number'] = Number(collection[0].runNumber ?? 0); + break; + case 'edm4hep::VertexCollection': + newEvent.Vertices[collName] = this.getVertices(collection); + break; + case 'edm4hep::TrackCollection': + this.getTracks(rawEvent, collection as edm4hep.Track[]).forEach( + ([label, arr]) => { + newEvent.Tracks[`${collName} | ${label}`] = arr; + }, + ); + break; + case 'edm4hep::TrackerHitCollection': + case 'edm4hep::TrackerHit3DCollection': + case 'edm4hep::SimTrackerHitCollection': + // case 'edm4hep::TrackerHitPlaneCollection': + // case 'edm4hep::SenseWireHitCollection': + + this.getHits(rawEvent, collection).forEach(([label, arr]) => { + newEvent.Hits[`${collName} | ${label}`] = arr; + }); + break; + case 'edm4hep::CalorimeterHitCollection': + case 'edm4hep::SimCalorimeterHitCollection': + newEvent.CaloCells[collName] = this.getCaloCells(collection); + break; + case 'edm4hep::ClusterCollection': + newEvent.CaloClusters[collName] = + this.getCaloClusters(collection); + break; + case 'edm4hep::ReconstructedParticleCollection': + if (collName === 'Jet') + newEvent.Jets[collName] = this.getJets(collection); + else if (collName.toLowerCase().includes('missing')) + newEvent.MissingEnergy[collName] = + this.getMissingEnergy(collection); + break; + } + }, + ); + + this.eventData[eventName] = newEvent; + + console.log(eventName, newEvent); + }, + ); return true; } @@ -59,742 +139,353 @@ export class Edm4hepJsonLoader extends PhoenixLoader { return Object.keys(this.rawEventData).length; } - /** Return run number (or 0, if not defined) */ - private getRunNumber(event: any): number { - if (!('EventHeader' in event)) { - return 0; - } - - const eventHeader = event['EventHeader']['collection']; - - if ('runNumber' in eventHeader[0]) { - return eventHeader[0]['runNumber']; - } - - return 0; - } - - /** Return event number (or 0, if not defined) */ - private getEventNumber(event: any): number { - if (!('EventHeader' in event)) { - return 0; - } - - const eventHeader = event['EventHeader']['collection']; - - if ('eventNumber' in eventHeader[0]) { - return eventHeader[0]['eventNumber']; - } - - return 0; - } - - /** Find PDG of the particle associated with the hit */ - private getPDG(event: any, collectionID: number, index: number) { - for (const collName in event) { - if (event[collName].constructor != Object) { - continue; - } - - const collDict = event[collName]; - - if (!('collID' in collDict)) { - continue; - } - - if (collDict['collID'] !== collectionID) { - continue; - } - - if (collDict['collection'].length <= index) { - continue; - } - - return collDict['collection'][index]['PDG']; - } - - return 0; - } - - /** Assign default color to Tracks */ - private colorTracks(event: any) { - let recoParticles: any[]; - if ('ReconstructedParticles' in event) { - recoParticles = event['ReconstructedParticles']['collection']; - } else { + /* Define particle PID based on link */ + private assignPID(rawEvent: any) { + // Link collection name and type vary by schema: + // - Schema 1: MCRecoAssociations + // - Schema 2: MCRecoAssociations or RecoMCLink + // - Schema 3: RecoMCLink + const linkCollection = (rawEvent.MCRecoAssociations ?? rawEvent.RecoMCLink) + ?.collection as + | edm4hep.Association[] // Schema 1 + | edm4hep.Link[]; // From Schema 2 Onwards + + const reconstructedParticleCollection = rawEvent.ReconstructedParticles + ?.collection as edm4hep.ReconstructedParticle[]; + + const mcParticleCollection = rawEvent.Particle + ?.collection as edm4hep.MCParticle[]; + + const eFlowTrackCollection = rawEvent.EFlowTrack + ?.collection as edm4hep.Track[]; + + if ( + !linkCollection || + !reconstructedParticleCollection || + !mcParticleCollection || + !eFlowTrackCollection + ) return; - } - let mcParticles: any[]; - if ('Particle' in event) { - mcParticles = event['Particle']['collection']; - } else { - return; - } + linkCollection.forEach((link: edm4hep.Association | edm4hep.Link) => { + const recIndex = 'rec' in link ? link.rec.index : link.from.index; + const simIndex = 'sim' in link ? link.sim.index : link.to.index; + const pdgid = Math.abs(mcParticleCollection[simIndex].PDG); - let mcRecoAssocs: any[]; - if ('MCRecoAssociations' in event) { - mcRecoAssocs = event['MCRecoAssociations']['collection']; - } else { - return; - } - - let tracks: any[]; - if ('EFlowTrack' in event) { - tracks = event['EFlowTrack']['collection']; - } else { - return; - } - - mcRecoAssocs.forEach((mcRecoAssoc: any) => { - const recoIndex = - typeof mcRecoAssoc['rec'] !== 'undefined' - ? mcRecoAssoc['rec']['index'] - : mcRecoAssoc['from']['index']; - const mcIndex = - typeof mcRecoAssoc['sim'] !== 'undefined' - ? mcRecoAssoc['sim']['index'] - : mcRecoAssoc['to']['index']; - - const pdgid = mcParticles[mcIndex]['PDG']; - const trackRefs = recoParticles[recoIndex]['tracks']; - - trackRefs.forEach((trackRef: any) => { - const track = tracks[trackRef['index']]; - if (Math.abs(pdgid) === 11) { - track['color'] = '00ff00'; - track['pid'] = 'electron'; - } else if (Math.abs(pdgid) === 22) { - track['color'] = 'ff0000'; - track['pid'] = 'photon'; - } else if (Math.abs(pdgid) === 211 || Math.abs(pdgid) === 111) { - track['color'] = 'a52a2a'; - track['pid'] = 'pion'; - } else if (Math.abs(pdgid) === 2212) { - track['color'] = '778899'; - track['pid'] = 'proton'; - } else if (Math.abs(pdgid) === 321) { - track['color'] = '5f9ea0'; - track['pid'] = 'kaon'; - } else { - track['color'] = '0000cd'; - track['pid'] = 'other'; - } - track['pdgid'] = pdgid; + reconstructedParticleCollection[recIndex].tracks.forEach(({ index }) => { + eFlowTrackCollection[index].pid = + Edm4hepJsonLoader.pidNames[pdgid] ?? edm4hep.ParticleType.Other; }); }); } - /** Return the vertices */ - private getVertices(event: any) { - const allVertices: { [key: string]: any[] } = {}; - - for (const collName in event) { - if (event[collName].constructor != Object) { - continue; - } - - const collDict = event[collName]; - - if (!('collType' in collDict)) { - continue; - } - - if (!('collection' in collDict)) { - continue; - } - - if (!(collDict['collType'] === 'edm4hep::VertexCollection')) { - continue; - } - - const vertices: any[] = []; - const rawVertices = collDict['collection']; - const vertexColor = this.randomColor(); - - rawVertices.forEach((rawVertex: any) => { - const position: any[] = []; - if ('position' in rawVertex) { - position.push(rawVertex['position']['x'] * 0.1); - position.push(rawVertex['position']['y'] * 0.1); - position.push(rawVertex['position']['z'] * 0.1); - } - - const vertex = { - pos: position, - size: 0.2, - color: '#' + vertexColor, - }; - vertices.push(vertex); - }); - - allVertices[collName] = vertices; - } - - return allVertices; + /** Return vertices */ + private getVertices(vertexCollection: edm4hep.Vertex[]): VertexParams[] { + const color = this.randomColor(); + + return vertexCollection.map((rawVertex: edm4hep.Vertex) => ({ + pos: [ + rawVertex.position.x * 0.1, + rawVertex.position.y * 0.1, + rawVertex.position.z * 0.1, + ], + size: 1, + vertexType: 'type' in rawVertex ? rawVertex.type : null, + color, + })); } /** Return tracks */ - private getTracks(event: any) { - const allTracks: { [key: string]: any[] } = {}; - - for (const collName in event) { - if (event[collName].constructor != Object) { - continue; - } - - const collDict = event[collName]; - - if (!('collType' in collDict)) { - continue; - } - - if (!(collDict['collType'] === 'edm4hep::TrackCollection')) { - continue; - } - - if (!('collection' in collDict)) { - continue; - } - - const rawTracks = collDict['collection']; - const electrons: any[] = []; - const photons: any[] = []; - const pions: any[] = []; - const protons: any[] = []; - const kaons: any[] = []; - const other: any[] = []; - - rawTracks.forEach((rawTrack: any) => { - const positions: any[] = []; - if ('trackerHits' in rawTrack) { - const trackerHitRefs = rawTrack['trackerHits']; - trackerHitRefs.forEach((trackerHitRef: any) => { - const trackerHits = this.getCollByID( - event, - trackerHitRef['collectionID'], - ); - const trackerHit = trackerHits[trackerHitRef['index']]; - positions.push([ - trackerHit['position']['x'] * 0.1, - trackerHit['position']['y'] * 0.1, - trackerHit['position']['z'] * 0.1, - ]); - }); - } - if ('trackStates' in rawTrack && positions.length === 0) { - const trackStates = rawTrack['trackStates']; - trackStates.forEach((trackState: any) => { - if ('referencePoint' in trackState) { - positions.push([ - trackState['referencePoint']['x'] * 0.1, - trackState['referencePoint']['y'] * 0.1, - trackState['referencePoint']['z'] * 0.1, - ]); - } - }); - } - - let trackColor = '0000cd'; - if ('color' in rawTrack) { - trackColor = rawTrack['color']; - } - - const track = { - pos: positions, - color: trackColor, - }; - - if ('pid' in rawTrack) { - if (rawTrack['pid'] == 'electron') { - electrons.push(track); - } else if (rawTrack['pid'] == 'photon') { - photons.push(track); - } else if (rawTrack['pid'] == 'pion') { - pions.push(track); - } else if (rawTrack['pid'] == 'proton') { - protons.push(track); - } else if (rawTrack['pid'] == 'kaon') { - kaons.push(track); - } else { - other.push(track); - } - } else { - other.push(track); - } + private getTracks( + rawEvent: any, + trackCollection: edm4hep.Track[], + ): [string, TrackParams[]][] { + const categories = Object.fromEntries( + Object.keys(Edm4hepJsonLoader.pidColors).map((type) => [ + type, + [] as TrackParams[], + ]), + ) as Record; + + trackCollection.forEach((rawTrack: edm4hep.Track) => { + const pos: number[][] = []; // An array of positions is needed to render the tracks as bars + + // @todo trackerhits might always exist + if ('trackerHits' in rawTrack && rawTrack.trackerHits.length > 0) { + rawTrack.trackerHits.forEach((trackerHitRef: ObjectID) => { + const trackerHits: edm4hep.Hit[] = this.getCollByID( + rawEvent, + trackerHitRef.collectionID, + ); + + pos.push([ + trackerHits[trackerHitRef.index].position.x * 0.1, + trackerHits[trackerHitRef.index].position.y * 0.1, + trackerHits[trackerHitRef.index].position.z * 0.1, + ]); + }); + } else { + rawTrack.trackStates.forEach((trackState: edm4hep.TrackState) => { + pos.push([ + trackState.referencePoint.x * 0.1, + trackState.referencePoint.y * 0.1, + trackState.referencePoint.z * 0.1, + ]); + }); + } + + const category = rawTrack.pid ?? 'other'; + + categories[category].push({ + pos, + // @todo dparams (helix parameters for Runge-Kutta extrapolation: qOverP requires the magnetic field) + // @todo phi (aimuthal angle) + // @todo eta (peudorapidity) + // @todo d0 (tansverse impact parameter) + // @todo z0 (lngitudinal impact parameter) + // @todo pt (transverse momentum requires the magnetic field) + chi2: rawTrack.chi2, // no use by phoenix-object.ts + dof: rawTrack.ndf, // no use by phoenix-object.ts + color: Edm4hepJsonLoader.pidColors[rawTrack.pid ?? 'other'], // tracks receive hex color without '#' + linewidth: 2, }); + }); - allTracks[collName + ' | Electrons'] = electrons; - allTracks[collName + ' | Photons'] = photons; - allTracks[collName + ' | Pions'] = pions; - allTracks[collName + ' | Protons'] = protons; - allTracks[collName + ' | Kaons'] = kaons; - allTracks[collName + ' | Other'] = other; - } - - return allTracks; + return Object.entries(categories).filter(([, arr]) => arr.length !== 0) as [ + string, + TrackParams[], + ][]; } /** Return tracker hits */ - private getHits(event: any) { - const allHits: { [key: string]: any[] } = {}; - - for (const collName in event) { - if (event[collName].constructor != Object) { - continue; - } - - const collDict = event[collName]; - // console.log(collDict); - - if (!('collType' in collDict)) { - continue; - } - - if (!collDict['collType'].includes('edm4hep::')) { - continue; - } - - if (!collDict['collType'].includes('TrackerHitCollection')) { - continue; - } - - if (!('collection' in collDict)) { - continue; - } - - const rawHits = collDict['collection']; - const hits: any[] = []; - const hitsOverlay: any[] = []; - const hitsProdBySecondary: any[] = []; - const hitsElectron: any[] = []; - const hitsMuon: any[] = []; - const hitsPion: any[] = []; - const hitsKaon: any[] = []; - const hitsProton: any[] = []; - const hitColor = this.randomColor(); - const hitColorOverlay = this.randomColor(); - const hitColorProdBySecondary = this.randomColor(); - const hitColorElectron = this.randomColor(); - const hitColorMuon = this.randomColor(); - const hitColorPion = this.randomColor(); - const hitColorKaon = this.randomColor(); - const hitColorProton = this.randomColor(); - - rawHits.forEach((rawHit: any) => { - const position: any[] = []; - if ('position' in rawHit) { - position.push(rawHit['position']['x'] * 0.1); - position.push(rawHit['position']['y'] * 0.1); - position.push(rawHit['position']['z'] * 0.1); - } - + private getHits( + rawEvent: any, + hitCollection: edm4hep.Hit[], + ): [string, HitParams[]][] { + const categories = Object.fromEntries([ + ...Object.keys(Edm4hepJsonLoader.pidColors).map((type) => [ + type, + [] as HitParams[], + ]), + ['overlay', [] as HitParams[]], + ['secondary', [] as HitParams[]], + ]) as Record; + + const colorOverlay = this.randomColor(); + const colorSecondary = this.randomColor(); + + hitCollection.forEach((rawHit) => { + const pos: [number, number, number] = [ + rawHit.position.x * 0.1, + rawHit.position.y * 0.1, + rawHit.position.z * 0.1, + ]; + + if ((rawHit.quality & (1 << 31)) !== 0) { /* BITOverlay = 31 * https://github.com/key4hep/EDM4hep/blob/fe5a54046a91a7e648d0b588960db7841aebc670/edm4hep.yaml#L349 */ - if ((rawHit['quality'] & (1 << 31)) !== 0) { - const hit = { - type: 'CircularPoint', - pos: position, - color: '#' + hitColorOverlay, - size: 2, - }; - hitsOverlay.push(hit); - /* BITProducedBySecondary = 30 - * https://github.com/key4hep/EDM4hep/blob/fe5a54046a91a7e648d0b588960db7841aebc670/edm4hep.yaml#L350 - */ - } else if ((rawHit['quality'] & (1 << 30)) !== 0) { - const hit = { - type: 'CircularPoint', - pos: position, - color: '#' + hitColorProdBySecondary, - size: 2, - }; - hitsProdBySecondary.push(hit); - } else { - let other = true; - if (rawHit['particle'].length > 0) { - const pdg = this.getPDG( - event, - rawHit['particle'][0]['collectionID'], - rawHit['particle'][0]['index'], - ); - if (Math.abs(pdg) === 11) { - const hit = { - type: 'CircularPoint', - pos: position, - color: '#' + hitColorElectron, - size: 2, - }; - hitsElectron.push(hit); - other = false; - } else if (Math.abs(pdg) === 13) { - const hit = { - type: 'CircularPoint', - pos: position, - color: '#' + hitColorMuon, - size: 2, - }; - hitsMuon.push(hit); - other = false; - } else if (Math.abs(pdg) === 211) { - const hit = { - type: 'CircularPoint', - pos: position, - color: '#' + hitColorPion, - size: 2, - }; - hitsPion.push(hit); - other = false; - } else if (Math.abs(pdg) === 321) { - const hit = { - type: 'CircularPoint', - pos: position, - color: '#' + hitColorKaon, - size: 2, - }; - hitsKaon.push(hit); - other = false; - } else if (Math.abs(pdg) === 2212) { - const hit = { - type: 'CircularPoint', - pos: position, - color: '#' + hitColorProton, - size: 2, - }; - hitsProton.push(hit); - other = false; - } - } - if (other) { - const hit = { - type: 'CircularPoint', - pos: position, - color: '#' + hitColor, - size: 2, - }; - hits.push(hit); - } + categories.overlay.push({ + type: 'CircularPoint', + pos, + color: `#${colorOverlay}`, + size: 2, + }); + } else if ((rawHit.quality & (1 << 30)) !== 0) { + /* BITProducedBySecondary = 30 + * https://github.com/key4hep/EDM4hep/blob/fe5a54046a91a7e648d0b588960db7841aebc670/edm4hep.yaml#L350 + */ + categories.secondary.push({ + type: 'CircularPoint', + pos, + color: `#${colorSecondary}`, + size: 2, + }); + } else { + let ref: ObjectID | null = null; + + if ('particle' in rawHit && rawHit.particle.length > 0) { + // 'particle' exists in type SimTrackerHit from Schema2 onwards + ref = rawHit.particle[0]; + } else if ('MCParticle' in rawHit) { + // 'MCParticle' only exists in type SimTrackerHit within Schema1 + ref = rawHit.MCParticle; } - }); - - if (hits.length > 0) { - allHits[collName + ' | Other'] = hits; - } - if (hitsOverlay.length > 0) { - allHits[collName + ' | Overlay'] = hitsOverlay; - } - if (hitsProdBySecondary.length > 0) { - allHits[collName + ' | Secondary'] = hitsProdBySecondary; - } - if (hitsElectron.length > 0) { - allHits[collName + ' | Electron'] = hitsElectron; - } - if (hitsMuon.length > 0) { - allHits[collName + ' | Muon'] = hitsMuon; - } - if (hitsPion.length > 0) { - allHits[collName + ' | Pion'] = hitsPion; - } - if (hitsKaon.length > 0) { - allHits[collName + ' | Kaon'] = hitsKaon; - } - if (hitsProton.length > 0) { - allHits[collName + ' | Proton'] = hitsProton; - } - } - return allHits; - } + if (ref !== null) { + const pdg = + this.getCollByID(rawEvent, ref.collectionID)?.[ref.index]?.PDG ?? + null; - /** Returns the cells */ - private getCells(event: any) { - const allCells: { [key: string]: any[] } = {}; + const particleType = + Edm4hepJsonLoader.pidNames[pdg] ?? edm4hep.ParticleType.Other; - 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; + categories[particleType].push({ + type: 'CircularPoint', + pos, + color: `#${Edm4hepJsonLoader.pidColors[particleType]}`, + size: 2, + }); + } } + }); - if (!collDict['collType'].includes('CalorimeterHitCollection')) { - continue; - } + return Object.entries(categories).filter(([, arr]) => arr.length !== 0); + } - if (!('collection' in collDict)) { - continue; + /** Returns Calo cells */ + private getCaloCells( + caloCellCollection: edm4hep.CaloCell[], + ): CaloCellParams[] { + const cells: Omit[] = []; + const hue = Math.floor(Math.random() * 358); + + // Find smallest distance between cell centers and use it as cell size + let drmin = 1e9; + for (let i = 0; i < 1e4; ++i) { + const j = Math.floor(Math.random() * caloCellCollection.length); + const k = Math.floor(Math.random() * caloCellCollection.length); + if (j === k) { + continue; + } + + const dx2 = Math.pow( + caloCellCollection[j].position.x - caloCellCollection[k].position.x, + 2, + ); + const dy2 = Math.pow( + caloCellCollection[j].position.y - caloCellCollection[k].position.y, + 2, + ); + const dz2 = Math.pow( + caloCellCollection[j].position.z - caloCellCollection[k].position.z, + 2, + ); + const dr = Math.sqrt(dx2 + dy2 + dz2); + + if (dr < drmin) { + drmin = dr; } + } - const rawCells = collDict['collection']; - const cells: any[] = []; - - // Find smallest distance between cell centers and use it as cell size - let drmin = 1e9; - for (let i = 0; i < 1e4; ++i) { - const j = Math.floor(Math.random() * rawCells.length); - const k = Math.floor(Math.random() * rawCells.length); - if (j === k) { - continue; - } - - const dx2 = Math.pow( - rawCells[j].position.x - rawCells[k].position.x, - 2, - ); - const dy2 = Math.pow( - rawCells[j].position.y - rawCells[k].position.y, - 2, - ); - const dz2 = Math.pow( - rawCells[j].position.z - rawCells[k].position.z, - 2, - ); - const dr = Math.sqrt(dx2 + dy2 + dz2); - - if (dr < drmin) { - drmin = dr; - } - } - const cellSide = - Math.floor(drmin) * 0.1 > 1 ? Math.floor(drmin) * 0.1 : 1; - const cellsHue = Math.floor(Math.random() * 358); - - rawCells.forEach((rawCell: any) => { - const x = rawCell.position.x * 0.1; - const y = rawCell.position.y * 0.1; - const z = rawCell.position.z * 0.1; - - const r = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2)); - const rho = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); - const eta = Math.asinh(z / rho); - const phi = Math.acos(x / rho) * Math.sign(y); - const cellLightness = this.valToLightness(rawCell.energy, 1e-3, 1); - const cellOpacity = this.valToOpacity(rawCell.energy, 1e-3, 1); - - const cell = { - eta: eta, - phi: phi, - energy: rawCell.energy, - radius: r, - side: cellSide, - length: cellSide, // expecting cells in multiple layers - color: '#' + this.convHSLtoHEX(cellsHue, 90, cellLightness), - opacity: cellOpacity, - }; - cells.push(cell); + const side = Math.floor(drmin) * 0.1 > 1 ? Math.floor(drmin) * 0.1 : 1; + + caloCellCollection.forEach((rawCell) => { + const x = rawCell.position.x * 0.1; + const y = rawCell.position.y * 0.1; + const z = rawCell.position.z * 0.1; + const rho = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); + + cells.push({ + eta: rho === 0 ? 0 : Math.asinh(z / rho), // Check because '0 / 0 = NaN' + phi: Math.atan2(y, x), // Safer equivalent to 'Math.acos(x / rho) * Math.sign(y)' + energy: rawCell.energy, + radius: Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2)), + z, + color: this.convHSLtoHEX(hue, rawCell.energy), + opacity: this.valToOpacity(rawCell.energy, 1e-3, 1), + side: side, + length: side, // expecting cells in multiple layers }); + }); - allCells[collName] = cells; - } - - return allCells; + return cells as CaloCellParams[]; } /** Return Calo clusters */ - private getCaloClusters(event: any) { - const allClusters: { [key: string]: any[] } = {}; - - for (const collName in event) { - if (event[collName].constructor != Object) { - continue; - } - - const collDict = event[collName]; - - if (!('collType' in collDict)) { - continue; - } - - if (!(collDict['collType'] === 'edm4hep::ClusterCollection')) { - continue; - } - - if (!('collection' in collDict)) { - continue; - } - - const rawClusters = collDict['collection']; - const clusters: any[] = []; - - rawClusters.forEach((rawCluster: any) => { - const x = rawCluster.position.x * 0.1; - const y = rawCluster.position.y * 0.1; - const z = rawCluster.position.z * 0.1; - - const r = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2)); - const rho = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); - const eta = Math.asinh(z / rho); - const phi = Math.acos(x / rho) * Math.sign(y); - - const cluster = { - eta: eta, - phi: phi, - energy: rawCluster.energy * 100, - radius: r, - side: 4, - }; - clusters.push(cluster); + private getCaloClusters( + caloClusterCollection: edm4hep.CaloCluster[], + ): CaloClusterParams[] { + const clusters: CaloClusterParams[] = []; + const hue = Math.floor(Math.random() * 361); + + caloClusterCollection.forEach((rawCluster) => { + const x = rawCluster.position.x * 0.1; + const y = rawCluster.position.y * 0.1; + const z = rawCluster.position.z * 0.1; + const rho = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); + + clusters.push({ + eta: rho === 0 ? 0 : Math.asinh(z / rho), // Check because '0 / 0 = NaN' + phi: Math.atan2(y, x), // Safer equivalent to 'Math.acos(x / rho) * Math.sign(y)' + energy: rawCluster.energy * 100, // @todo more energy -> smaller porportion. by why 100 specifically? + radius: Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2)), + z, + color: this.convHSLtoHEX(hue, rawCluster.energy), + theta: Math.atan2(rho, z), + opacity: this.valToOpacity(rawCluster.energy, 1e-3, 1), + side: 4, // (overrides side width of the cluster box) + // length (overrides length (depth) of the cluster box) }); + }); - allClusters[collName] = clusters; - } - - return allClusters; + return clusters; } /** Return jets */ - private getJets(event: any) { - const allJets: { [key: string]: any[] } = {}; - - for (const collName in event) { - if (event[collName].constructor != Object) { - continue; - } - - const collDict = event[collName]; - - if (!('collType' in collDict)) { - continue; - } - - if ( - !(collDict['collType'] === 'edm4hep::ReconstructedParticleCollection') - ) { - continue; - } - - if (!(collName.includes('Jet') || collName.includes('jet'))) { - continue; - } - - if (!('collection' in collDict)) { - continue; - } - - const jets: any[] = []; - const rawJets = collDict['collection']; - - rawJets.forEach((rawJet: any) => { - if (!('momentum' in rawJet)) { - return; - } - if (!('energy' in rawJet)) { - return; - } - const px = rawJet['momentum']['x']; - const py = rawJet['momentum']['y']; - const pz = rawJet['momentum']['z']; - - const pt = Math.sqrt(Math.pow(px, 2) + Math.pow(py, 2)); - const eta = Math.asinh(pz / pt); - const phi = Math.acos(px / pt) * Math.sign(py); - - const jet = { - eta: eta, - phi: phi, - energy: 1000 * rawJet.energy, - }; - jets.push(jet); + private getJets(jetCollection: edm4hep.ReconstructedParticle[]): JetParams[] { + const jets: JetParams[] = []; + const hue = Math.floor(Math.random() * 358); + + jetCollection.forEach((rawJet) => { + const px: number = rawJet.momentum.x; + const py: number = rawJet.momentum.y; + const pz: number = rawJet.momentum.z; + const p = Math.sqrt(px * px + py * py + pz * pz); + const pt = Math.sqrt(Math.pow(px, 2) + Math.pow(py, 2)); + const eta = pt === 0 ? 0 : Math.asinh(pz / pt); + + jets.push({ + eta, + phi: Math.atan2(py, px), // Safer equivalent to 'Math.acos(px / pt) * Math.sign(py)' + theta: 2 * Math.atan(Math.exp(-eta)), + energy: rawJet.energy * 1000, + et: p === 0 ? 0 : (rawJet.energy * pt) / p, + // coneR (overrides the cone radius for visualization width) + origin_X: rawJet.referencePoint.x, + origin_Y: rawJet.referencePoint.y, + origin_Z: rawJet.referencePoint.z, + color: this.convHSLtoHEX(hue, rawJet.energy), }); - allJets[collName] = jets; - } + }); - return allJets; + return jets; } /** Return missing energy */ - private getMissingEnergy(event: any) { - const allMETs: { [key: string]: any[] } = {}; - - for (const collName in event) { - if (event[collName].constructor != Object) { - continue; - } - - const collDict = event[collName]; - - if (!('collType' in collDict)) { - continue; - } - - if ( - !(collDict['collType'] === 'edm4hep::ReconstructedParticleCollection') - ) { - continue; - } - - if (!(collName.includes('Missing') || collName.includes('missing'))) { - continue; - } - - if (!('collection' in collDict)) { - continue; - } - - const METs: any[] = []; - const rawMETs = collDict['collection']; - const METColor = '#ff69b4'; - - rawMETs.forEach((rawMET: any) => { - if (!('momentum' in rawMET)) { - return; - } - if (!('energy' in rawMET)) { - return; - } - const px = rawMET['momentum']['x']; - const py = rawMET['momentum']['y']; - const pz = rawMET['momentum']['z']; - - const p = Math.sqrt( - Math.pow(px, 2) + Math.pow(py, 2) + Math.pow(pz, 2), - ); - const etx = (rawMET['energy'] * px) / p; - const ety = (rawMET['energy'] * py) / p; - - const MET = { - etx: etx * 10, - ety: ety * 10, - color: '#ff69b4', - }; - METs.push(MET); + private getMissingEnergy( + missingEnergyCollection: edm4hep.ReconstructedParticle[], + ): MissingEnergyParams[] { + const missingEnergies: MissingEnergyParams[] = []; + + missingEnergyCollection.forEach((rawMissingEnergy: any) => { + const px: number = rawMissingEnergy.momentum.x; + const py: number = rawMissingEnergy.momentum.y; + const pz: number = rawMissingEnergy.momentum.z; + const p = Math.sqrt(Math.pow(px, 2) + Math.pow(py, 2) + Math.pow(pz, 2)); + + missingEnergies.push({ + etx: ((rawMissingEnergy.energy * px) / p) * 10, + ety: ((rawMissingEnergy.energy * py) / p) * 10, + color: '#ff69b4', }); - allMETs[collName] = METs; - } + }); - return allMETs; + return missingEnergies; } /** Return a random colour */ private randomColor() { - return Math.floor(Math.random() * 16777215) + return `#${Math.floor(Math.random() * 16777215) .toString(16) .padStart(6, '0') - .toUpperCase(); + .toUpperCase()}`; } - /** Helper conversion of HSL to hexadecimal */ - private convHSLtoHEX(h: number, s: number, l: number): string { - l /= 100; - const a = (s * Math.min(l, 1 - l)) / 100; - const f = (n: number) => { - const k = (n + h / 30) % 12; - const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); - return Math.round(255 * color) - .toString(16) - .padStart(2, '0'); - }; - - return `${f(0)}${f(8)}${f(4)}`; + /** Get the required collection */ + private getCollByID(event: any, id: number) { + const coll = Object.values(event).find((c: any) => c?.collID === id) as any; + return coll?.collection; } /** Return a lightness value from the passed number and range */ @@ -823,22 +514,21 @@ export class Edm4hepJsonLoader extends PhoenixLoader { return opacity; } - /** Get the required collection */ - private getCollByID(event: any, id: number) { - for (const collName in event) { - if (event[collName].constructor != Object) { - continue; - } + /** Helper conversion of HSL to hexadecimal */ + private convHSLtoHEX(h: number, energy: number): string { + const s = Math.floor(Math.random() * 101); + const l = this.valToLightness(energy, 1e-3, 1) / 100; - const collDict = event[collName]; + const a = (s * Math.min(l, 1 - l)) / 100; - if (!('collID' in collDict)) { - continue; - } + const f = (n: number) => { + const k = (n + h / 30) % 12; + const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); + return Math.round(255 * color) + .toString(16) + .padStart(2, '0'); + }; - if (collDict['collID'] === id) { - return collDict['collection']; - } - } + return `#${f(0)}${f(8)}${f(4)}`; } } diff --git a/packages/phoenix-ng/projects/phoenix-app/src/assets/geometry/ATLAS/.SCT.obj.icloud b/packages/phoenix-ng/projects/phoenix-app/src/assets/geometry/ATLAS/.SCT.obj.icloud deleted file mode 100644 index df24bd637..000000000 Binary files a/packages/phoenix-ng/projects/phoenix-app/src/assets/geometry/ATLAS/.SCT.obj.icloud and /dev/null differ diff --git a/packages/phoenix-ng/projects/phoenix-app/src/assets/geometry/ATLAS/.toroids.obj.icloud b/packages/phoenix-ng/projects/phoenix-app/src/assets/geometry/ATLAS/.toroids.obj.icloud deleted file mode 100644 index 3a692d39d..000000000 Binary files a/packages/phoenix-ng/projects/phoenix-app/src/assets/geometry/ATLAS/.toroids.obj.icloud and /dev/null differ diff --git a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/overlay-view/overlay-view-window/overlay-view-window.component.ts b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/overlay-view/overlay-view-window/overlay-view-window.component.ts index 4440e628b..7464c2e76 100644 --- a/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/overlay-view/overlay-view-window/overlay-view-window.component.ts +++ b/packages/phoenix-ng/projects/phoenix-ui-components/lib/components/ui-menu/overlay-view/overlay-view-window/overlay-view-window.component.ts @@ -35,7 +35,6 @@ export class OverlayViewWindowComponent implements AfterViewInit { x: number = window.innerWidth / 2.5, y: number = window.innerHeight / 2.5, ): HTMLCanvasElement { - console.log('doneee'); const width = x; const height = y; canvas.width = width;