Warning, /firebird/README.md is written in an unsupported language. File is not indexed.
0001 # EIC Phoenix based event display
0002
0003 [](https://github.com/eic/firebird/actions/workflows/frontend.yaml)
0004
0005
0006 Visit working display:
0007
0008 https://eic.github.io/firebird/
0009
0010
0011 ## Development server
0012
0013 Run `ng serve` in `firebird-ng` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
0014
0015 # Firebird Data Exchange format
0016
0017 Data exchange is both JSON and Javascript object compatible.
0018
0019 It starts with `"type":"firebird-dex-json"` and the version, any custom origin info and a list of entries.
0020 In HENP physics `entry` may correspond to `event` data.
0021
0022 ```json
0023 {
0024 "type":"firebird-dex-json",
0025 "version": "0.01",
0026 "origin": {any custom origin info here"},"entries": [
0027 entry1, entry2, ...
0028 ]
0029 }
0030 ```
0031
0032 - **version** - is JSON schema version
0033 - **origin** - designed for any general custom info such as original file name,
0034 timestamp, simulation software version, etc.
0035 - **entries** - list of entries/events. The format is below.
0036
0037 ## Entry format
0038
0039 Entry is an object with `id` and `components` properties.
0040 By design components represent different hits, tracks, vertices, collections, etc.
0041 While can be any arbitary data, that will be further rendered by the frontend.
0042
0043 ```json
0044 {
0045 "id": "entry number or unique string",
0046 "components": [
0047
0048 ...
0049
0050 ]
0051 }
0052 ```
0053
0054 requrired fields are `id` and `components`.
0055
0056
0057 ## Component format
0058
0059 - "name": unique string id
0060 - "type": string with type (depends on what component will be used in the frontend to render it)
0061 - "originType": optional string with type of origin, e.g. "edm4eic::TrackerHitData",
0062 - all other fields are depend on "type"
0063
0064 So far example of exchange format looks like (only required fields are used here):
0065
0066 ```json
0067 {
0068 "version": "0.01",
0069 "entries": [
0070 {
0071 "id": "event 0",
0072 "components": [
0073 {
0074 "name": "BarrelVertexHits",
0075 "type": "HitBox",
0076 ...,
0077 },
0078 ...
0079 ]
0080 },
0081 ...
0082 ]
0083 }
0084 ```
0085
0086 ## BoxTrackerHit component
0087
0088 ```json
0089 {
0090 "pos": [1, 2, 3],
0091 "dim": [10, 10, 1],
0092 "t": [4, 1],
0093 "ed": [0.001, 0.0001]
0094 }
0095 ```
0096 Hit has
0097
0098 - "pos": position [mm] (x, y, z),
0099 - "dim": box dimensions [mm] (dx, dy, dz),
0100 - "t": time information [ns] (time, err_time),
0101 - "ed": energy deposit with error [GeV] (edep, err_edep)
0102
0103 Example
0104
0105 ```json
0106 "components": [
0107 {
0108 "name": "MPGDBarrelRecHits",
0109 "type": "BoxTrackerHit",
0110 "originType": "edm4eic::TrackerHitData",
0111 "hits": [
0112 {
0113 "pos": [-567, -84.1, -908],
0114 "dim": [0.05, 0.04, 0.0],
0115 "t": [-10.6, 10.0],
0116 "ed": [2e-06, 0.0]
0117 },
0118 {
0119 "pos": [368, -424, 406],
0120 "dim": [0.05, 0.045, 0.0],
0121 "t": [33, 10],
0122 "ed": [9e-06, 0.0]
0123 },
0124 ...
0125 }]
0126
0127 ```
0128
0129 ## TrackerLinePointTrajectory component
0130
0131 Trajectories that are built based on points.
0132
0133 ```json
0134 "components": [
0135 {
0136 "name": "CentralTrackSegments",
0137 "type": "TrackerLinePointTrajectory",
0138 "originType": ["edm4eic::TrackPoint","edm4eic::TrackSegment"],
0139 "paramColumns": [".."], // Param columns should correspond to what is written in line/track params
0140 "pointColumns": ["x", "y", "z", "t", "dx", "dy", "dz", "dt"]
0141
0142 "lines": [
0143 {
0144 points: [
0145 [x, y, z, t, dx, dy, dz, dt],
0146 [x, y, z, t, dx, dy, dz, dt],
0147 ... // all points go here
0148 ],
0149 params: [...] // values to parameter columns here
0150 },
0151 ... // other lines
0152 ]
0153 ...
0154 ]
0155 ```
0156
0157 ## TypeScript Event Model
0158
0159
0160 The Firebird Data Exchange model provides a structured way to serialize and deserialize
0161 event data. This model is implemented in TypeScript and designed to be extensible,
0162 allowing users to add their own custom components without modifying the core parsing logic.
0163
0164 The implementation consists of several TypeScript classes and interfaces that mirror the data exchange
0165 format and provide methods for serialization and deserialization.
0166
0167 - **DataExchange** class - Represents the entire data exchange object.
0168 - **Entry** class - Represents an individual event entry.
0169 - **EntryComponent** abstract class - A base class representing a generic entry component. Described below.
0170
0171 It Typescript Firebird Data Exchange often referenced as Dex (Data EXchange). E.g.
0172 `toDexObject`, `fromDexObject`. `DexObject` is a JS object, that if serialized to JSON
0173 would correspond a part of DataExchangeFormat. E.g. Dex HitBox will have `pos`, `dim` etc.
0174
0175 We can put it differently. In general JSON format is very close to object definition in JS => TS.
0176 But despite that, Firebird JSON format is just a data exchange layer and when deserialized from
0177 JSON is not designed to be a 100% a convenient to work with JS data structure.
0178 More over, it lacks some methods and abstractions, that our domain data-model should have,
0179 such as links between event model and three.js rendering tree objects.
0180
0181 Summarizing:
0182
0183 - Firebird Data Exchange - is JSON schema shaping data exchange between backend and frontend
0184 - DexObject - JSON parsed to JS object
0185 - TypeScript event model - Frontend set of classes mimicking DexObject structure but designed
0186 to be convenient in terms of the frontend API
0187
0188
0189 ### EntryComponent machinery
0190
0191 Different collection of objects such as hits, tracks, vertexes, etc.
0192 that firebird can work with are represented as various event or Entry Component-s.
0193 Each type derive from EntryComponent and registered in a system.
0194 Then corresponding Painters classes know how to render/paint them, there are rules how
0195 to display them in tables, etc.
0196
0197 - **EntryComponent** An abstract class representing a generic entry component.
0198 - Contains common properties:
0199 - `name`: Unique identifier.
0200 - `type`: Component type (used for determining the appropriate factory).
0201 - `originType`: Optional string indicating the origin type.
0202 - Declares an abstract method `toDexObject()` that must be implemented by subclasses.
0203
0204 - **EntryComponentFactory Interface**: Defines a factory for creating `EntryComponent`
0205 instances from Dex objects - deserialized data.
0206 - **Component Registry**: A mapping of component types to their corresponding factories.
0207 - Functions:
0208 - `registerComponentFactory(factory: EntryComponentFactory)`: Registers a new factory.
0209 - `getComponentFactory(type: string)`: Retrieves a factory based on the component type.
0210
0211
0212 ## Extending the Model
0213
0214 ### Adding a New Component Type
0215
0216 To add a new component type, follow these steps:
0217
0218 1. **Create a New Component Class**: Extend `EntryComponent` and implement the `toDexObject()` method.
0219
0220 ```typescript
0221 export class CustomComponent extends EntryComponent {
0222 static type = 'CustomType';
0223 // Define additional properties
0224
0225 constructor(name: string, /* additional parameters */, originType?: string) {
0226 super(name, CustomComponent.type, originType);
0227 // Initialize additional properties
0228 }
0229
0230 toDexObject(): any {
0231 return {
0232 name: this.name,
0233 type: this.type,
0234 originType: this.originType,
0235 // Serialize additional properties
0236 };
0237 }
0238 }
0239 ```
0240
0241 2. **Create a Factory for the Component**: Implement `EntryComponentFactory` for your component.
0242
0243 ```typescript
0244 export class CustomComponentFactory implements EntryComponentFactory {
0245 type: string = CustomComponent.type;
0246
0247 fromDexObject(obj: any): EntryComponent {
0248 const name = obj["name"];
0249 // Extract additional properties
0250 const originType = obj["originType"];
0251
0252 // Validate required fields
0253 if (!name /* || missing other required fields */) {
0254 throw new Error("Missing required fields in CustomComponent");
0255 }
0256
0257 return new CustomComponent(name, /* additional parameters */, originType);
0258 }
0259 }
0260 ```
0261
0262 3. **Register the Factory**: Use the `registerComponentFactory()` function to register your component factory.
0263
0264 ```typescript
0265 // Register the custom component factory
0266 registerComponentFactory(new CustomComponentFactory());
0267 ```
0268
0269 4. **Update JSON Parsing Logic**: No need to modify existing parsing logic. The registry will dynamically resolve the new component type.
0270