Skip to content

Commit

Permalink
[frontend] Full geometry optimized
Browse files Browse the repository at this point in the history
  • Loading branch information
DraTeots committed May 15, 2024
1 parent 74c4e04 commit b6c877c
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 109 deletions.
179 changes: 82 additions & 97 deletions firebird-ng/src/app/geometry.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,109 +12,117 @@ import {
import {build} from 'jsrootdi/geom';


export class DetectorGeometryFineTuning {
namePattern: string = "";
editRules: GeoNodeEditRule[] = [];
}


export class DetectorGeometryFineTuning {
public namePattern: string;
public editRules: GeoNodeEditRule[];

constructor(
namePattern: string,
editRules:GeoNodeEditRule[] = []
)
{
this.namePattern = namePattern;
this.editRules = editRules;
function pruneTopLevelDetectors(geoManager: any, removeNames: string[]): any {
const volume = geoManager.fMasterVolume === undefined ? geoManager.fVolume : geoManager.fMasterVolume;
const nodes: any[] = volume?.fNodes?.arr ?? [];
let removedNodes: any[] = [];

// Don't have nodes? Have problems?
if(!nodes.length) {
return {nodes, removedNodes};
}

// Collect nodes to remove
for(let node of nodes) {
let isRemoving = removeNames.some(substr => node.fName.startsWith(substr))
if(isRemoving) {
removedNodes.push(node);
}
}

// Now remove nodes
for(let node of removedNodes) {
removeGeoNode(node);
}

return {nodes, removedNodes}
}



@Injectable({
providedIn: 'root'
})
export class GeometryService {

/**
* Simple to fill list of patterns of elements to drop
* @typedef {Array.<string>} FullGeometryPruneList
* Detectors (top level TGeo nodes) to be removed.
* (!) startsWith function is used for filtering (aka: detector.fName.startsWith(removeDetectorNames[i]) ... )
*/
removeDetectorsStartsWith: string[];

detectorTopNodes=[];

/// This inted to become users rule
fineTuneRules: GeoNodeEditRule[] = [];
totalRules: GeoNodeEditRule[] = [];

subDetectors: DetectorGeometryFineTuning[] = [
removeDetectorNames: string[] = [
"Lumi",
"Magnet",
"B0",
"B1",
"B2",
"Q0",
"Q1",
"Q2",
"BeamPipe",
"Pipe",
"ForwardOffM",
"Forward",
"Backward",
"Vacuum",
"SweeperMag",
"AnalyzerMag",
"ZDC",
"LFHCAL",
"HcalFarForward"
];

subDetectorsRules: DetectorGeometryFineTuning[] = [
{
namePattern: "*/EcalBarrelScFi*",
editRules: [
{pattern: "*/fiber_grid*", prune:PruneRuleActions.Remove, pruneSubLevel:0},
{pattern: "*/fiber_grid*", prune:PruneRuleActions.Remove},
]
},
{
namePattern: "*/EcalBarrelImaging*",
editRules: [
{pattern: "*/stav*", prune:PruneRuleActions.RemoveChildren, pruneSubLevel:0},
{pattern: "*/stav*", prune:PruneRuleActions.RemoveChildren},
]
},
{
namePattern: "*/DRICH*",
editRules: [
{pattern: "*/DRICH_cooling*", prune:PruneRuleActions.RemoveSiblings, pruneSubLevel:0},
{pattern: "*/DRICH_cooling*", prune:PruneRuleActions.RemoveSiblings},
]
},
{
namePattern: "*/EcalEndcapN*",
editRules: [
{pattern: "*/crystal*", prune:PruneRuleActions.RemoveSiblings, pruneSubLevel:0},
{pattern: "*/crystal*", prune:PruneRuleActions.RemoveSiblings},
]
},
{
namePattern: "*/HcalBarrel*",
editRules: [
{pattern: "*/Tile*", prune:PruneRuleActions.Remove},
{pattern: "*/ChimneyTile*", prune:PruneRuleActions.Remove},
]
},
{
namePattern: "*/EndcapTOF*",
editRules: [
{pattern: "*/suppbar*", prune:PruneRuleActions.Remove},
{pattern: "*/component*3", prune:PruneRuleActions.RemoveSiblings},
]
}
]

]

constructor() {
this.removeDetectorsStartsWith = [
"Lumi",
"Magnet",
"B0",
"B1",
"B2",
"Q0",
"Q1",
"Q2",
"BeamPipe",
"Pipe",
"ForwardOffM",
"Forward",
"Backward",
"Vacuum",
"SweeperMag*",
"AnalyzerMag*",
"ZDC"
//"LFHCAL"
];

this.fineTuneRules = [
{pattern: "Default/EcalBarrel*/sector*", prune: PruneRuleActions.RemoveChildren, pruneSubLevel: 0}
]

// Fill rules with prune
for(let pattern of this.removeDetectorsStartsWith) {
this.totalRules.push(new GeoNodeEditRule(pattern, PruneRuleActions.Remove ));
}

// Copy users rules
for(let rule of this.fineTuneRules) {
this.totalRules.push(rule);
}


}




async loadEicGeometry() {
//let url: string = 'assets/epic_pid_only.root';
//let url: string = 'https://eic.github.io/epic/artifacts/tgeo/epic_dirc_only.root';
Expand All @@ -135,38 +143,13 @@ export class GeometryService {
console.timeEnd('Reading geometry from file');

// Getting main detector nodes

const nodeName = rootGeoManager.fName;
const volume = rootGeoManager.fMasterVolume === undefined ? rootGeoManager.fVolume : rootGeoManager.fMasterVolume;
const allTopNodes = volume?.fNodes?.arr ?? null;
if(!allTopNodes) {
console.log("No top level detector nodes found. Wrong geometry? ")
return {rootGeoManager: null, rootObject3d: null};
}

for(let topNode of allTopNodes) {
let isRemoving = this.removeDetectorsStartsWith.some(substr => topNode.fName.startsWith(substr))

console.log(`NODE ${topNode.fName}: ${topNode} isRemoving: ${isRemoving}`);

if(isRemoving) {
removeGeoNode(topNode);
} else {
printAllGeoBitsStatus(topNode);
console.log(`VOLUME: ${topNode.fVolume.fName}: ${topNode.fVolume}`);
printAllGeoBitsStatus(topNode.fVolume);
}
}

// >oO debug: analyzeGeoNodes(rootGeoManager, 1);
console.time('Prune nodes coarse');
editGeoNodes(rootGeoManager, this.totalRules, 1)
console.timeEnd('Prune nodes coarse');

// >oO
let result = pruneTopLevelDetectors(rootGeoManager, this.removeDetectorNames);
console.log("Filtered top level detectors: ", result);


for(let detector of this.subDetectors) {
// >oO analyzeGeoNodes(rootGeoManager, 1);
// Now we go with the fine tuning each detector
for(let detector of this.subDetectorsRules) {
let topDetNode = findSingleGeoNode(rootGeoManager, detector.namePattern, 1);
console.log(`Processing ${topDetNode}`);
if(!topDetNode) {
Expand All @@ -180,12 +163,14 @@ export class GeometryService {
console.timeEnd(`Process sub-detector: ${detector.namePattern}`);
}

console.log(`Done processing ${this.subDetectors.length} detectors`);
console.log(`Done processing ${this.subDetectorsRules.length} detectors`);

console.log(`---- DETECTOR ANALYSIS ----`);
analyzeGeoNodes(rootGeoManager, 1);
console.log(`---- END DETECTOR ANALYSIS ----`);

//analyzeGeoNodes(geoManager, 1);
return {rootGeoManager: null, rootObject3d: null};
// return {rootGeoManager: null, rootObject3d: null};

//
console.time('Build geometry');
Expand Down
21 changes: 9 additions & 12 deletions firebird-ng/src/app/utils/cern-root.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,18 +76,9 @@ export enum PruneRuleActions {
* Defines editing rules for geographic nodes based on a pattern.
*/
export class GeoNodeEditRule {
/**
* Constructs an instance of GeoNodeEditRule.
* @param pattern Matching pattern for node selection. Default is an empty string.
* @param prune Type of pruning action to take. Default is PruneRuleActions.Nothing.
* @param pruneSubLevel How many sublevels to prune. Defaults to Infinity.
* Effective only if prune rule is `RemoveBySubLevel`.
*/
constructor(
public pattern: string = '',
public prune: PruneRuleActions = PruneRuleActions.Nothing,
public pruneSubLevel: number = Infinity
) { }
public pattern: string = '';
public prune: PruneRuleActions = PruneRuleActions.Nothing;
public pruneSubLevel?: number = Infinity
}

/**
Expand Down Expand Up @@ -177,11 +168,17 @@ export function analyzeGeoNodes(node: any, level:number=2) {

let highLevelNodes = getGeoNodesByLevel(node, 1);

let totalNodes = 0;

console.log(`--- Detector subcomponents analysis --- Detectors: ${highLevelNodes.length}`);
for(let item of highLevelNodes) {
// Now run walkNodes for each of high level node to get number of subnodes
let numSubNodes = walkGeoNodes(item.geoNode, null, Infinity);
totalNodes += numSubNodes;
console.log(`${numSubNodes}: ${item.fullPath}`);
}
console.log(`--- End of analysis --- Total elements: ${totalNodes}`);

}

export function getGeoNodesByLevel(topNode: any, selectLevel:number=1) {
Expand Down
52 changes: 52 additions & 0 deletions firebird-ng/src/app/utils/list.utils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { filterIntersectingItems, removeIntersectingItemsInPlace } from './list.utils';

describe('List Utilities', () => {

describe('filterIntersectingItems', () => {
it('should filter out items from list1 that are present in list2', () => {
const list1 = [1, 2, 3, 4, 5];
const list2 = [3, 4, 5, 6, 7];
const result = filterIntersectingItems(list1, list2);
expect(result).toEqual([1, 2]);
expect(list1).toEqual([1, 2, 3, 4, 5]); // Ensure list1 is not modified
});

it('should return an empty array if all items in list1 are in list2', () => {
const list1 = [1, 2, 3];
const list2 = [1, 2, 3];
const result = filterIntersectingItems(list1, list2);
expect(result).toEqual([]);
});

it('should return the original list1 if no items in list1 are in list2', () => {
const list1 = [1, 2, 3];
const list2 = [4, 5, 6];
const result = filterIntersectingItems(list1, list2);
expect(result).toEqual([1, 2, 3]);
});
});

describe('removeIntersectingItemsInPlace', () => {
it('should remove items from list1 that are present in list2 in place', () => {
const list1 = [1, 2, 3, 4, 5];
const list2 = [3, 4, 5, 6, 7];
removeIntersectingItemsInPlace(list1, list2);
expect(list1).toEqual([1, 2]);
});

it('should remove all items from list1 if they are all in list2', () => {
const list1 = [1, 2, 3];
const list2 = [1, 2, 3];
removeIntersectingItemsInPlace(list1, list2);
expect(list1).toEqual([]);
});

it('should not modify list1 if no items in list1 are in list2', () => {
const list1 = [1, 2, 3];
const list2 = [4, 5, 6];
removeIntersectingItemsInPlace(list1, list2);
expect(list1).toEqual([1, 2, 3]);
});
});

});
27 changes: 27 additions & 0 deletions firebird-ng/src/app/utils/list.utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* @summary Filters out items from list1 that are present in list2 and returns a new list.
* @param {T[]} list1 - The first list of items.
* @param {T[]} list2 - The second list of items to be removed from the first list.
* @return {T[]} A new list with items from list1 that are not in list2.
*/
export function filterIntersectingItems<T>(list1: T[], list2: T[]): T[] {
const set2 = new Set(list2);
return list1.filter(item => !set2.has(item));
}

/**
* @summary Removes items from list1 that are present in list2 in place.
* @param {T[]} list1 - The first list of items.
* @param {T[]} list2 - The second list of items to be removed from the first list.
*/
export function removeIntersectingItemsInPlace<T>(list1: T[], list2: T[]): void {
const set2 = new Set(list2);
let i = 0;
while (i < list1.length) {
if (set2.has(list1[i])) {
list1.splice(i, 1); // Remove the item at index i
} else {
i++;
}
}
}

0 comments on commit b6c877c

Please sign in to comment.