Release version 1.4

Transient Simulation

The features related to time-resolved simulations are certainly the larges addition in this release. The new Allpix Squared version allows to exploit the Shockley-Ramo theorem in different ways as detailed in the following.

Total induced charge

A new transfer module named InducedTransfer is available. It can be used to calculate the total induced charge at any pixel implant after a propagation of both electrons and holes using the GenericPropagation module. With the addition of trapping or recombination (to be added in the future) this module allows to retrieve the partial contribution to the final signal generated by charge carriers which traveled a significant distance through the sensor without finally reaching the implant.

The induced charge on each of the pixel implants is defined as the difference in weighting potential between the end position x_{final} retrieved from the PropagatedCharge and the initial position x_{initial} of the charge carrier obtained from the DepositedCharge object in the history. The total induced charge is calculated by multiplying the potential difference with the charge of the carrier. The resulting induced charge is summed for all propagated charge carriers and returned as a PixelCharge object. The number of neighboring pixels taken into account can be configured using the induction_matrix parameter.

Pulse of induced charge over time

A more intricate simulation is the generation of the full current pulse at the readout electrodes. This can now be performed using the TransientPropagation module which - similar to the InducedTransfer module - calculates the difference in weighting potential for each charge carrier to obtain the induced current. This is repeated for every step of the Runge-Kutta solver, so the individual contributions of each charge carrier during its drift time are added up and result in a current pulse on each pixel implants.

The charge transport is parameterized in time and the time step each simulation step takes can be configured. For each step, the induced charge on the neighboring pixel implants is calculated via the Shockley-Ramo theorem by taking the difference in weighting potential between the current position x(i) and the previous position x(i-1) of the charge carrier and multiplying it with the charge. The resulting pulses are stored for every pixel individually.

In order to combine the individual pulses originating from the different PropagatedCharge objects, the PulseTransfer modules should be used. It simply sums the induced current pulses from all PropagatedCharge objects to form one combined pulse per readout electrode.

Changes to the framework core

Some changes to the framework core have been necessary in order to allow these simulations. The main changes are described in the following.

The Detector class now possesses a weighting potential. Since this does not wrap at pixel boundaries like the electric field does, but also needs to be evaluated for neighboring pixels, the DetectorField class has been extended with a new method getRelativeTo() which allows to calculate the field at a position relative to a reference position. For the electric field, this reference position is always the center of the current pixel, while to might be any pixel for the weighting potential.

The objects PropagatedCharge now holds a map of pixel indices and pulses. While this breaks the paradigm of a charge carrier in the sensor not possessing information about the readout channels, this is necessary in order to be able to attribute individual pulse contributions to the charge carriers (keeping the MC history intact) and also to retain separate propagation and transfer steps. Without this addition, the TransientPropagation module would have to directly output PixelCharge objects with the corresponding pulses. While this simplifies things a bit from the code point of view, it also reduces the modularity of the framework and the number of possible module combinations.

The PixelCharge object holds one Pulse, consisting of a time-binned vector with induced charge per time. The default constructor of a PixelCharge object adds a pulse with a single bin and assigns the full charge to this bin. This way, the change is backwards-compatible with algorithms just accessing the total charge of the object, such as the DefaultDigitizer.

Additional modules and tools

The WeightingPotentialReader module allows to read pre-calculated weighting potentials from files, in analogy to what the ElectricFieldReader does for electric fields. In addition, it contains a mode where the weighting field is calculated for the given planar sensor model and position just in time. Since this uses a numerical method with a Tailor expansion, this is considerably slower than the look-up from pre-calculated field maps.

In order to facilitate the usage of weighting potentials, a generator tool is provided in the repository's tools/ directory. It takes a detector model file as input and generates the corresponding weighting potential using all available cores of the executing machine. The resulting field in INIT or APF format can be read by the WeightingPotentialReader.

Binary File Format for Field Data

Support for a new file format for storing field data has been added to Allpix Squared. The new format, called APF (Allpix Squared Field) is a compact binary format with some minimal header information and versioning. It is serialized and deserialized using the cereal C++11 library. While the total file size doesn't shrink that much compared to the legacy INIT file format owing to the double-precision floating point numbers used, the time for reading and writing of the field files is reduced by a factor 100 or more. The file format is versioned to allow for future changes of the field content without breaking backwards compatibility.

Along with the format comes a set of small helper tools which allow to e.g. convert from INIT to APF or the other way around. They can be found in the tools/apf_tools folder of the repository.

Parsing and writing of field data is now done by central classes (FieldParser, FieldWriter) which can be used both by the framework and by auxiliary tools such as the TCAD Mesh Converter. The previously used key model = "init" is replaced by the new model named "mesh" for any type of field data read from a file. The type of file to be read is automatically deducted from the content of the file by the FieldParser, similar to what GNU diff does:

diff determines whether a file is text or binary by checking the first few bytes in the file; the exact number of bytes is system dependent, but it is typically several thousand. If every byte in that part of the file is non-null, diff considers the file to be text; otherwise it considers the file to be binary.

Backwards compatibility is guaranteed by overwriting outdated values of the model field with the new value.

Change Geometry from the Command Line

The allpix executable now allows to alter the loaded geometry directly from the command line via

allpix -c config.conf -g detector.option=value

By this, rotation scans can be started from a simple bash script by overwriting the detector's orientation with different rotation angles for each run, -g dut.orientation=0deg,0deg,12deg. The respective value overwrites the one stored in the detector configuration file. To change several keys, the argument can be specified multiple times.

New Module: DepositionPointCharge

A new module has been added to the repository which deposits a defined number of charge carriers at a specific point within the active volume the detector. The number of charge carriers to be deposited can be specified in the configuration.

Two different source types are available:

  • The point source deposits charge carriers at a specific point in the sensor, which can be configured via the position parameter with three dimensions. The number of charge carriers deposited can be adjusted using the number_of_charges parameter.
  • The mip model allows to deposit charge carriers along a straight line through the sensor, perpendicular to its surface. Charge carriers are deposited linearly along this line with 80 electron-hole pairs per micrometer. The number of steps through the sensor can be configured using the number_of_steps parameter, the position can be given in two dimensions via the position parameter.

This module supports three different deposition models:

  • In the fixed model, charge carriers are always deposited at the exact same position, specified via the position parameter, in every event of the simulation. This model ist mostly interesting for development of new charge transport algorithms, where the initial position of charge carriers should be known exactly.
  • In the scan model, the position where charge carriers are deposited changes with every event. The scanning positions are distributed such, that the volume of one pixel cell is homogeneously scanned. The total number of positions is taken from the total number of events configured for the simulation. If this number doesn't allow for a full illumination, a warning is printed, suggesting a different number of events. The pixel volume to be scanned is always placed at the center of the active sensor area. The scan model can be used to generate sensor response templates for fast simulations by generating a lookup table from the final simulation results.
  • In the spot model, charge carriers are deposited in a Gaussian spot around the configured position. The sigma of the Gaussian distribution in all coordinates can be configured via the spot_size parameter. Charge carriers are only deposited inside the active sensor volume.

Monte Carlo particles are generated at the respective positions, bearing a particle ID of -1. All charge carriers are deposited at time zero, i.e. at the beginning of the event.

This module allows to e.g. simulate a straight particle track through the sensor with linear energy deposition and no secondary particles to facilitate direct comparison with TCAD simulations, or to simulate particle passage in a Gaussian beam without any effect from Landau fluctuations or secondary particles.

TCAD Mesh Converter: Improved Performance and Interpolation Algorithm

Central parts of the MeshConverter tool have been reworked to be more efficient and the code more clean. The old interpolation approach did not necessarily always find the smallest mesh volume possible around the point of interest since it implemented a reverse permutation of a bit vector with the closest points at the MSB. This means, the order of search of e.g. 3 out of 8 points would be


while combinations which contain much closer points such as 10110000 come much later in the permutation chain. By then, a valid mesh element, but with larger volume, will have been found. When using std::next_permutation instead of std::prev_permutation and a reversed bit mask vector, the algorithm automatically loops over the most nearby points instead of racing off in one direction and the search order is correct:


and further away elements are only successively taken into account. While this approach has benefits in its accuracy, it might lead to more permutations required, since very close-by elements might be co-planar (co-linear for 2D). To offset the performance impact introduced by this, the code has been rewritten to avoid repeated memory allocations for temporary objects, and by replacing the STL permutation implementation by the combinations algorithm developed by Howard Hinnant.

The performance gain depends on whether it is a 2D field (fewer combinations to test) or a 3D field as well as on the density of the points in the original mesh. Especially fields with a strong variation of mesh density in different regions will take longer, since the search radius has to match the widest possible distance between mesh points - which will include many points in dense regions and drastically increase the number of possible combinations. This is where these improvements are strongest.

The initial search radius is now automatically set to the expected bin width of the final regular mesh, but can still be overwritten using the initial_radius parameter.

Other Notable Features and Improvements

  • Extended TextWriter module for ASCII output: The TextWriter module now also knows about the data types DepositedCharge, PropagatedCharge and PixelCharge and can print information about them into the output file.
  • Removed restrictions on Geant4 source macros: The DepositonGeant4 module's macro parsing functionality has been extended to support all Geant4 commands in its gpgs/ command tree. This means that e.g. multiple particle sources can be directly set up using source_type = "macro" The world volume is automatically extended to include all defined sources from the macro.
  • ProjectionPropagation can stop propagation: The newly added parameter integration_time allows to set a cut-off for propagating charge carriers in the projection, analogous to what is possible in GenericPropagation.
  • Example Python script for data analysis: An example script written in Python has been added to the repository to demonstrate how to analyze files generated by the ROOTObjectWriter module.
  • Full Proteus configuration: The RCEWriter module now produces a complete set of configuration files for direct use in the Proteus reconstruction framework, including sensor descriptions and geometry file.
  • New module for GDML output: The generation of GDML files for the geometry setup has been moved to a dedicated module called GDMLOutputWriter.
  • Depletion from Sensor Backside: The ElectricFieldReader module now allows to deplete sensors from the backside when using linear electric fields via the deplete_from_implants option. This allows to e.g. more accurately model n-in-n sensors.
  • Restructure Manual & Introduce "Coding Conventions" Section: As suggested at the user workshop in November 2018, the manual has been restructured a bit to better document coding guidelines and naming conventions. Especially the "Developing a new Module" has seen some extension and a new section "Coding and Naming Conventions" was added to the development section.
  • ROOTObjectWriter can handle missing messages: In previous versions, the ROOT trees written to disk might have gotten out of sync if not all messages were present in the first event. Now, the ROOTObjectWriter fills these trees to the correct event number whenever receiving the first message of the respective type. See MR176.