Back to home page

EIC code displayed by LXR

 
 

    


Warning, /firebird/firebird-ng/src/app/model/point-trajectory.group.ts is written in an unsupported language. File is not indexed.

0001 /**
0002  * A data-model component for "PointTrajectory" typed data.
0003  *
0004  * This represents data in the Firebird Dex format:
0005  *
0006  *   {
0007  *     "name": "CentralTrackSegments",
0008  *     "type": "PointTrajectory",
0009  *     "origin": [...],
0010  *     "paramColumns": [...],
0011  *     "pointColumns": [...],
0012  *     "trajectories": [
0013  *       {
0014  *         "points": [ [x, y, z, t, dx, dy, dz, dt], ... ],
0015  *         "params": [ ... ]
0016  *       },
0017  *       ...
0018  *     ]
0019  *   }
0020  *
0021  * For example, each trajectory may correspond to one track segment,
0022  * and "points" is an array of arrays containing position/time/uncertainties.
0023  */
0024 
0025 import {
0026   EventGroup,
0027   EventGroupFactory,
0028   registerEventGroupFactory
0029 } from "./event-group";
0030 
0031 /**
0032  * Representation of a single line in the trajectory.
0033  */
0034 export interface PointTrajectory {
0035   /**
0036    * Array of points, each point is a numeric array matching the "pointColumns"
0037    * e.g. [ x, y, z, t, dx, dy, dz, dt ] or however many columns.
0038    */
0039   points: number[][];
0040   /**
0041    * Array of track parameters matching "paramColumns"
0042    * e.g. [theta, phi, qOverP, pdg, etc...]
0043    */
0044   params: number[];
0045 }
0046 
0047 /**
0048  * The main component class that holds multiple lines (track segments)
0049  * along with the definitions of paramColumns and pointColumns.
0050  */
0051 export class PointTrajectoryGroup extends EventGroup {
0052   static type = "PointTrajectory";
0053 
0054   /**
0055    * The param columns define the meaning of the `params` array in each line.
0056    * Example: ["theta","phi","qOverP","charge","pdg"]
0057    */
0058   paramColumns: string[] = [];
0059 
0060   /**
0061    * The point columns define the meaning of the each entry in `points`.
0062    * Example: ["x","y","z","t","dx","dy","dz","dt"]
0063    */
0064   pointColumns: string[] = [];
0065 
0066   /**
0067    * Trajectory that is built connecting points
0068    */
0069   trajectories: PointTrajectory[] = [];
0070 
0071   constructor(name: string, origin?: string) {
0072     super(name, PointTrajectoryGroup.type, origin);
0073   }
0074 
0075   /** calculate time range */
0076   override get timeRange(): [number, number] | null {
0077     // Check if there are any lines
0078     if (this.trajectories.length === 0) return null;
0079 
0080     // Find the index of time column
0081     const timeIndex = this.pointColumns.indexOf("t");
0082 
0083     // If time column doesn't exist, return null
0084     if (timeIndex === -1) return null;
0085 
0086     // Check if there are any points in any line
0087     let hasPoints = false;
0088     for (const line of this.trajectories) {
0089       if (line.points.length > 0) {
0090         hasPoints = true;
0091         break;
0092       }
0093     }
0094     if (!hasPoints) return null;
0095 
0096     // Initialize min and max times as null
0097     let minTime: number | null = null;
0098     let maxTime: number | null = null;
0099 
0100     // Loop through all lines and points
0101     for (const line of this.trajectories) {
0102       for (const point of line.points) {
0103         const time = point[timeIndex];
0104 
0105         // Skip if time is null
0106         if (time == null) continue;
0107 
0108         // Initialize min/max if not initialized yet
0109         if (minTime === null) minTime = time;
0110         if (maxTime === null) maxTime = time;
0111 
0112         // Update min/max
0113         if (time < minTime) minTime = time;
0114         if (time > maxTime) maxTime = time;
0115       }
0116     }
0117 
0118     // Return range if both min and max are not null
0119     if (minTime !== null && maxTime !== null) {
0120       return [minTime, maxTime];
0121     }
0122 
0123     return null;
0124   }
0125 
0126   /**
0127    * Convert this component to a Dex-format JS object
0128    */
0129   override toDexObject(): any {
0130     // Serialize lines
0131     const trajectoriesObj = this.trajectories.map((trajectory) => {
0132       return {
0133         points: trajectory.points,
0134         params: trajectory.params
0135       };
0136     });
0137 
0138     return {
0139       name: this.name,
0140       type: this.type,
0141       origin: this.origin,
0142       paramColumns: this.paramColumns,
0143       pointColumns: this.pointColumns,
0144       trajectories: trajectoriesObj
0145     };
0146   }
0147 }
0148 
0149 /**
0150  * Factory class to deserialize from the Dex object to our component instance.
0151  */
0152 export class PointTrajectoryGroupFactory implements EventGroupFactory {
0153   type = PointTrajectoryGroup.type;
0154 
0155   fromDexObject(obj: any): PointTrajectoryGroup {
0156     const comp = new PointTrajectoryGroup(obj["name"], obj["origin"]);
0157 
0158     // paramColumns
0159     if (Array.isArray(obj["paramColumns"])) {
0160       comp.paramColumns = [...obj["paramColumns"]];
0161     }
0162 
0163     // pointColumns
0164     if (Array.isArray(obj["pointColumns"])) {
0165       comp.pointColumns = [...obj["pointColumns"]];
0166     }
0167 
0168     // Find time column index
0169     const timeIndex = comp.pointColumns.indexOf("t");
0170 
0171     // trajectories
0172     comp.trajectories = [];
0173     if (Array.isArray(obj["trajectories"])) {
0174       for (const lineObj of obj["trajectories"]) {
0175         // Create a copy of points to avoid modifying the original data
0176         let points = Array.isArray(lineObj["points"]) ? [...lineObj["points"]] : [];
0177 
0178         // Sort points by time (4th column) if time column exists
0179         if (timeIndex !== -1 && points.length > 1) {
0180           // Sort using Array.sort which uses TimSort algorithm in most modern browsers
0181           // TimSort is efficient for arrays that are partially sorted, which is often the case here
0182           points.sort((a, b) => {
0183             // Make sure points have time value at the specified index
0184             if (a.length <= timeIndex || b.length <= timeIndex) {
0185               return 0; // Keep original order if time index is out of bounds
0186             }
0187             return a[timeIndex] - b[timeIndex]; // Sort by time ascending
0188           });
0189         }
0190 
0191         comp.trajectories.push({
0192           points: points,
0193           params: Array.isArray(lineObj["params"]) ? lineObj["params"] : []
0194         });
0195       }
0196     }
0197     return comp;
0198   }
0199 }
0200 
0201 /** Register the factory so it gets picked up by the Entry deserialization. */
0202 registerEventGroupFactory(new PointTrajectoryGroupFactory());