Back to home page

EIC code displayed by LXR

 
 

    


Warning, /firebird/packages/firebird-example-extension/src/cherenkov-ring.piece.ts is written in an unsupported language. File is not indexed.

0001 /**
0002  * Model side of the example extension: a data type Firebird has never heard
0003  * of (Cherenkov rings from a RICH detector) arrives in DEX and is decoded
0004  * into a typed EventPiece.
0005  *
0006  * This file is a @dexvis/firebird-core citizen: plain TS, worker-safe, no
0007  * Angular. Only the registration lines (see index.ts) are Angular.
0008  *
0009  * The DEX v1 piece is columnar — parallel arrays, ring id == array index:
0010  *
0011  *   {
0012  *     "name": "ExampleRings", "type": "example.CherenkovRing", "version": "1.0",
0013  *     "count": 2,
0014  *     "columns": {
0015  *       "center": [x0,y0,z0, x1,y1,z1],  // [mm] flat, 3 values per ring
0016  *       "radius": [600, 450],            // [mm]
0017  *       "nPhotons": [14, 9],
0018  *       "time": [5, 4],                  // [ns]
0019  *       "track": [0, -1]                 // optional: index into a trajectory piece
0020  *     },
0021  *     "refs": { "track": "ExampleTracks" }
0022  *   }
0023  *
0024  * The optional "track" column shows the v1 reference mechanism: its values are
0025  * entity indexes into the piece named by refs (-1 = no reference), so linking
0026  * is a plain array lookup — no id maps.
0027  */
0028 
0029 // The /model subpath on purpose: the factory is registered from app.config
0030 // (initial bundle), and the @dexvis/firebird-core root re-exports painter
0031 // modules that pull three.js. The model imports no three.js.
0032 import {
0033   EntityRefLink,
0034   EventPiece,
0035   EventPieceFactory,
0036   readPieceCount,
0037   readNumberColumn,
0038   readOptionalNumberColumn,
0039 } from '@dexvis/firebird-core/model';
0040 
0041 export class CherenkovRingPiece extends EventPiece {
0042   /** Namespaced type string: reverse-dns-lite prefix prevents collisions
0043    * between experiment packages; bare names are reserved for core types. */
0044   static type = 'example.CherenkovRing';
0045 
0046   /** Number of rings. */
0047   count = 0;
0048 
0049   /** Ring centers [mm]: flat x,y,z per ring, `3 * count` values. */
0050   center: Float32Array = new Float32Array(0);
0051 
0052   /** Ring radii [mm], `count` values. */
0053   radius: Float32Array = new Float32Array(0);
0054 
0055   /** Detected photons per ring, `count` values, or null when not written. */
0056   nPhotons: Float32Array | null = null;
0057 
0058   /** Ring production times [ns], `count` values, or null when not written. */
0059   time: Float32Array | null = null;
0060 
0061   /** Ring -> trajectory references (-1 = none), or null when not written. */
0062   track: Float32Array | null = null;
0063 
0064   /** Name of the piece the `track` column points into (from `refs`). */
0065   trackPieceName: string | null = null;
0066 
0067   constructor(name: string, origin?: any) {
0068     super(name, CherenkovRingPiece.type, origin);
0069   }
0070 
0071   /** Ring label: radius, plus photon count when written. */
0072   override entityLabel(ringIndex: number): string {
0073     let label = `#${ringIndex} r=${this.radius[ringIndex].toFixed(0)}`;
0074     if (this.nPhotons !== null) label += ` nphot=${this.nPhotons[ringIndex]}`;
0075     return label;
0076   }
0077 
0078   /** The ring -> trajectory reference, when the writer declared it. */
0079   override entityRefs(ringIndex: number): EntityRefLink[] {
0080     if (this.track === null || this.trackPieceName === null) return [];
0081     const target = this.track[ringIndex];
0082     if (target < 0) return [];
0083     return [{ column: 'track', targetPiece: this.trackPieceName, targetIndex: Math.floor(target) }];
0084   }
0085 
0086   static fromDexObject(obj: any): CherenkovRingPiece {
0087     const piece = new CherenkovRingPiece(obj['name'], obj['origin']);
0088     piece.count = readPieceCount(obj);
0089     piece.center = readNumberColumn(obj, 'center', piece.count, 3);
0090     piece.radius = readNumberColumn(obj, 'radius', piece.count);
0091     piece.nPhotons = readOptionalNumberColumn(obj, 'nPhotons', piece.count);
0092     piece.time = readOptionalNumberColumn(obj, 'time', piece.count);
0093     piece.track = readOptionalNumberColumn(obj, 'track', piece.count);
0094     piece.trackPieceName = obj['refs']?.['track'] ?? null;
0095     return piece;
0096   }
0097 
0098   override toDexObject(): any {
0099     const columns: any = {
0100       center: Array.from(this.center),
0101       radius: Array.from(this.radius),
0102     };
0103     if (this.nPhotons !== null) columns.nPhotons = Array.from(this.nPhotons);
0104     if (this.time !== null) columns.time = Array.from(this.time);
0105     if (this.track !== null) columns.track = Array.from(this.track);
0106 
0107     const result: any = {
0108       name: this.name,
0109       type: this.type,
0110       version: '1.0',
0111       count: this.count,
0112       columns: columns,
0113     };
0114     if (this.trackPieceName !== null) result.refs = { track: this.trackPieceName };
0115     if (this.origin !== undefined) result.origin = this.origin;
0116     return result;
0117   }
0118 
0119   override get timeRange(): [number, number] | null {
0120     if (this.time === null || this.count === 0) return null;
0121     let minTime = this.time[0];
0122     let maxTime = this.time[0];
0123     for (let i = 1; i < this.count; i++) {
0124       if (this.time[i] < minTime) minTime = this.time[i];
0125       if (this.time[i] > maxTime) maxTime = this.time[i];
0126     }
0127     return [minTime, maxTime];
0128   }
0129 }
0130 
0131 export class CherenkovRingPieceFactory implements EventPieceFactory {
0132   type = CherenkovRingPiece.type;
0133 
0134   fromDexObject(obj: any): EventPiece {
0135     return CherenkovRingPiece.fromDexObject(obj);
0136   }
0137 }