Querying sub-(and sub-sub-sub- etc) components returned by getInstrument

Hello!

General mantidic/pythonic question: the getInstrument method returns a component and all of its subcomponents (and sub-sub components etc) as a multidimensional list. In my case, if I read a whole detector assembly, let’s call it “East”, I have to go down to fourth level in the list to find individual pixels i.e. I need four indices i,j,k,l to specify the pixel at East[i][j][k][l].

If I wanted to find the smallest pixel ID in the total “East” assembly, is there anything smarter than running four nested for-loops that pulls out every pixel (in my case requiring 33256*256 = 589824 loops)?

Second question: in the general case, where I need n indices to get to my pixel i.e. East[i1][i2][i3]…[in], how would I set that up? If I went the nested for-loop approach I’d need n of these and have no idea how to construct a nested loop of arbitrary size.

Thanks!

Hi Malcolm!

To find the smallest detector ID, I think this should work:

# import mantid algorithms, numpy
from mantid.simpleapi import *
import numpy as np

ws = CreateSampleWorkspace()
detInfo = ws.detectorInfo()
detIDs = detInfo.detectorIDs()

print(np.min(detIDs))

Tell me if this isn’t quite what you’re looking for!

A few searches for arbitrary nested for-loops on stackoverflow seem to be focussed on C++ where the performance is much better. I’m not sure if the lines above are calling a nested for-loop in the background, but they are calling C++ commands, so I think trying to pursue this nested for-loop in Python isn’t advisable.

Hi Malcolm,

regarding your second question, you can use a recursive function to drill down arbitray nested loops… e.g.

from mantid.simpleapi import *
import numpy as np

def recursive_ids(inp):
    if hasattr(inp, '__len__'):
        return [recursive_ids(inp[ii]) for ii in range(len(inp))]
    elif hasattr(inp, 'getID'):
        return inp.getID()
    else:
        return None

def recursive_min_ids(inp):
     if isinstance(inp, list) and isinstance(inp[0], list):
         return [recursive_min_ids(inp[ii]) for ii in range(len(inp))]
     else:
         return np.min(inp)
        
detIDs = recursive_ids(workspace.getInstrument())
min_IDs = recursive_min_ids(detIDs)

print(min_IDs)

In the above, detIDs is a nested list of detector ID numbers, and min_IDs is a nested list of the minimum ID numbers for each set of (nested) CompAssembly.

All the best,

Duc.

1 Like

Hi Both, by chance I happened to look at the forum and see I never replied to you. How rude of me! My only excuse is I was in the middle of moving job and country and it got quite chaotic…

Anyway, thank you very much for the suggestions! In the end, a solution to my original problem (a bug in AlignComponents when detectors pixels are not numbered sequentially in the IDF) was solved by one of the ORNL developers. But your input is still helpful as I’m still trying to understand how IDF’s work!