konigcell.dynamic3d#
- konigcell.dynamic3d(positions, mode, values=None, radii=None, voxels=None, resolution=None, xlim=None, ylim=None, zlim=None, executor=<class 'concurrent.futures.thread.ThreadPoolExecutor'>, max_workers=None, verbose=True)[source]#
Voxelize / rasterize a moving particle’s trajectory onto a 3D voxel grid.
This function is very general, so the description below may seem abstract; do check out the examples for specific applications and consult these docs if / as needed.
The particle’s positions are given as a 2D NumPy array, with three columns representing the X, Y and Z locations; each row corresponds to a single recorded particle position. Multiple trajectories can be separated by a row of NaN.
As a particle moves in a straight line between two consecutive positions, it will be approximated as the convex hull of two spheres (centred at the given positions, with radii defined by the input radii) - like a cylinder with two spherical ends. Each such spherical cylinder defined by two consecutive particle positions will be rasterized onto a voxel grid.
The values contained by the returned voxel grid depend on the input mode:
kc.RATIO: each voxel will contain the ratio of its intersected volume to the total volume of the spherical cylinder defined by a particle moving between two adjacent positions. This is useful for e.g. velocity probability distributions.
kc.INTERSECTION: each voxel will contain the intersected volume of the spherical cylinder; if the entire voxel was covered by the particle movement, it will simply contain the voxel volume v_dx * v_dy * v_dz. This is useful for e.g. residence time distributions.
kc.PARTICLE: each voxel will contain the volume spanned by the spherical cylinder.
kc.ONE: each intersected voxel will have one added to it.
The volumes defined above can be multiplied by a particle-related quantity, e.g. particle velocity or time interval between two consecutive particle locations. They are defined by the input values; if unset all values are considered 1.
The particles may have a radius; if the input radii is given as a single number, all particles will have this radius. Alternatively, the particle may change radius if radii is given as a NumPy vector containing a radius associated with each particle location. If unset (None), the particle is considered point-like / infinitesimally small.
The voxel grid can be defined in two ways:
Set the input voxels to a pre-existing konigcell.Voxels to reuse it, minimising memory allocation.
Set the input resolution so that a new konigcell.Voxels will be created and returned by this function. If unset (None), xlim, ylim zlim will be computed automatically to contain all particle positions.
The rasterization can be done in parallel, as defined by the input executor, which can be a
concurrent.futures.Executorsubclass; e.g. ThreadPoolExecutor for multi-threaded execution, or mpi4py.futures MPIPoolExecutor for distributing the computation across multiple MPI nodes. It can also be an instance of such class, configured beforehand.The number of parallel workers (threads, processes or ranks) is set by max_workers; if set to 1, execution is sequential (and produces better error messages). If unset, the os.cpu_count() is used.
If verbose is True, the computation is timed and (hopefully) helpful messages are printed during execution.
- Parameters:
- positions(
N, 3)np.ndarray[ndim=2, dtype=float64] The 3D particle positions. Separate multiple trajectories with a row of NaN.
- mode
kc.RATIO,kc.INTERSECTION,kc.PARTICLE,kc.ONE The rasterization mode, see above for full details.
- values
float, (N-1,)np.ndarray, optional The particle values to rasterize, will be multiplied with what the mode returns; if a single float, all values are set to it. Multiple values can be given in a NumPy array for each particle movement, so it needs 1 fewer values than positions (e.g. for particle positions A, B, C, there are only movements AB then BC). If unset (default), it is considered 1.
- radii
float, (N,)np.ndarray, optional Each particle’s radius; if a single number, all particles are will have this radius. Multiple radii can be given in a NumPy array for each particle position. If None (default), the particle is considered point-like / infinitesimally small.
- voxels
konigcell.Voxels, optional A pre-created voxel grid to use; if unset, a new one will be created - so resolution must be set.
- resolution3-tuple, optional
If voxels is unset, a new voxel grid will be created; this resolution contains the number of voxels in the X, Y and Z dimensions, e.g.
(50, 50, 50). There must be at least 2 voxels in each dimension.- xlim2-tuple, optional
If voxels is unset, a new voxel grid will be created; you can manually set the physical rectangle spanned by this new grid as [xmin, xmax]. If unset, it is automatically computed to contain all particle positions.
- ylim2-tuple, optional
Same as for xlim.
- zlim2-tuple, optional
Same as for xlim.
- executor
concurrent.futures.Executorsubclassorinstance The parallel executor to use, implementing the Executor interface. For distributed computation with MPI, use MPIPoolExecutor from mpi4py. The default is ThreadPoolExecutor, which has the lowest overhead - useful because the main computation is done by C code releasing the GIL.
- max_workers
int, optional The maximum number of workers (threads, processes or ranks) to use by the parallel executor; if 1, it is sequential (and produces the clearest error messages should they happen). If unset, the os.cpu_count() is used.
- verbosebool or
strdefaultTrue If True, time the computation and print the state of the execution. If str, show a message before loading bars.
- positions(
Examples
TODO