Questions regarding ElectricFieldReader

Hi everyone!

I am using allpix squared for a new detector under development, and I am currently trying to load the electric field. I am using COMSOL to simulate the field, exporting in an equally spaced array to a file, and I then use Python to convert the data to the .init format required by Allpix.
So I have some questions:

  1. Given the simulated field, am I understanding correctly that I need to have the xyz coordinates on the strict form of X = [1,2,3,4,…] etc, i.e. strict increasing?
  2. If I use PIXEL_FULL in the ElectricFieldReader, where is the position (1,1,1), is it one of the top corners of the pixel, or one of the bottom corners?
  3. I noticed that when the module is loading the field, it refuses to take any other coordinates than integer microns and throws “invalid data” when decimals are used. This is a bit of a pickle since the pixels are quite small and I would like to be able to have a higher sampled field if proven necessary. Is it possible to set the reader, either in the .init file or in the module, to use nano meter as a unit instead to allow for finer sampling?
  4. Given that we can load the field, is the field supposed to be sampled from edge to edge? What I mean is, say that the pitch of the pixels is 20 microns, should the sampling be from ON the border between two pixels to ON the next border (with 1um sampling this would be 21 points), or should it be half a sampling step in from the border?

Thank you in advance!

Dear @rickard

  1. In the best of all worlds, your pixel array shows some periodicity, e.g. every pixel is them same. In this case you only need to simulate, export and convert a single pixel - Allpix Squared will take care of replicating that single pixel electric field over the entire sensor matrix you are simulating. There are situations where this is not possible, e.e. when the sensor has a double-column structure with asymmetries in the pixel fields. Then you would simulate e.g. two adjacant pixels and load them - and again Allpix Squared takes care of paaing them to the full matrix.
  2. PIXEL_FULL assumes that the field you provide is centered around a pixel, e.g. the center of your field map coincides with the center of a pixel.
  3. As per 1. the field is supposed to be provided for a single pixel, I am not sure which setting you are attempting to use here. We regularly use fields that have a meshing of the order of 10nm for pixels of a fiew micrometers pitch.
  4. With PIXEL_FULL you would really have to center it. I strongly recommend enabling the plotting feature of the ElectricFieldReader module and cross-check that what is rendered there corresponds to the electric field mapping to the pixels as you wished for.

I hope this helps - if you have more questions it might be necessary to share the actual configuration you are using currently.

Best regards,
Simon

Dear @simonspa

Thank you for the very quick reply!

I understand that it needs to be centered, I am mostly wondering if the coordinates needs to be strictly positive, and strictly integers? Since it works when I have it centered and have positive integers in the electricField.init file. For example, with the header and the rest formatted as shown in the mesh converter documentation, I get the following:

Positive integers work: 15 505 1 58.526565600186586 156.79006517259404 963.2954811432282
Negative not working: -6 205 1 58.526565600186586 156.79006517259404 963.2954811432282
Decimals not working: 6.0 205.0 1.0 58.526565600186586 156.79006517259404 963.2954811432282

which means I can not get a meshing finer than 1um. I do not know if there is a problem in my formatting, the python code to convert to the .init format is as follows:

with open("electricField.init", 'wb') as f:
    line = "fullPixel_WidthxDepthyHeightz_BiasV_293K \n\
##SEED##  ##EVENTS## \n\
##TURN## ##TILT## 1.0 \n\
0.00 0.0 0.00 \n\
height width depth 293 0 0 0 {} {} {} 0\n".format(xBins,yBins),zBins).encode('ascii')
    f.write(line)

    for idx in range(x.shape[0]):
        line = "{} {} {} {} {} {}\n".format(int(x[idx]), int(y[idx]), int(z[idx]), Ex[idx],Ey[idx],Ez[idx]).encode('ascii')
        f.write(line)

where Width, Depth, and Height are the dimansions of the active pixel volume in microns, and xBins, yBins, zBins are the number of bins. x, y, and, z are the coordinates in numpy arrays, and Ex, Ey, and Ez are the corresponding field values in numpy arrays.

I then try to use it in the ElectricFieldReader according to
[ElectricFieldReader]
model = "mesh
file_name = “./electricField.init”
field_mapping = “PIXEL_FULL”

It is confusing since it works when x, y, and z are positive integers, but not when the pixel is centered on (x,y)=(0,0), i.e. x in [-width/2, width/2] and similar for y. And it does not work if the x, y, and z, values have decimals, even if strictly positive.

I wish I could share some more, but it is a bit difficult in a public forum, but thought if there’s a solution, others may benefit. But any help is appreciated.

Best,
Rickard

Hi @rickard

I see - I better understand your question now. The coordinates provided in the file are not really coordinates but just indices of a 3D map, so they need to be positive definitive, starting from 0.

The actual binning/bin width/position of these map indices on the pixel are automatically calculated from the height, width, depth parameters you need to provide. An example:

  • height = width = 25 (this is in units of micrometers)
  • depth = 50 (also um)
  • xBins = yBins = 1000 (this is just the number of bins)
  • zBins = 50 (same)

would result in a field which has a bin width of 25nm across the x-y plane and a bin width of 1um in the depth. The field would be aligned on the pixel such that the pixel center gets the value between bins [499, 500].

Does this explain the situation?

FWIW our MeshConverter tool will take input fields with adaptive meshes as often generated by TCAD tools and generate regularly spaced meshes from them either by nearest-neigbor selection or by barycentric interpolation. The reason we use a regular mesh is the possibility of easily calculating indices to jump around the map.

The MeshConverter tool has a file parser class that could be extended to directly read COMSOl fields - maybe this would be worth looking into? See here.

Best,
Simon

Hi @simonspa

Yes, that explains it perfectly! I got a bit confused interpreting <node.x> in the mesh converter docs as coordinates and not indices!
Regarding the MeshConverter, I do not have a lot of C++ experience, but definitely worth looking into if I get the time!

Thank you for the help!

/Rickard

1 Like