Coarse and fine plasma

Concept

In order to increase stability and combat transverse grid noise, LCODE 3D utilises a dual plasma appoach.

../_images/virtplasma.png

Positioning of the coarse and fine particles in dual plasma approach.

Coarse particles are the ones that get tracked throughout the program, and pushed by the pusher. There coarse plasma grid is many times more sparse than the fields grid, think \(\frac{1}{9}\) particles per cell.

config_example.plasma_coarseness = 3

Square root of the amount of cells per coarse particle

Fine particles only exist inside the deposition phase. There are several fine particles per cell, think \(4\) or more. Their characteristic values are neither stored or evolved; instead they are intepolated from the coarse particle grid as a part of the the deposition process (and they don’t ‘exist’ in any form outside of it).

config_example.plasma_fineness = 2

Square root of the amount of fine particles per cell

Initialization

lcode.make_coarse_plasma_grid(steps, step_size, coarseness=3)[source]

Create initial coarse plasma particles coordinates (a single 1D grid for both x and y).

lcode.make_fine_plasma_grid(steps, step_size, fineness=2)[source]

Create initial fine plasma particles coordinates (a single 1D grid for both x and y).

Avoids positioning particles at the cell edges and boundaries.

  • fineness=3 (and coarseness=2):

    +-----------+-----------+-----------+-----------+
    | .   .   . | .   .   . | .   .   . | .   .   . |
    |           |           |           |           |   . - fine particle
    | .   .   . | .   *   . | .   .   . | .   *   . |
    |           |           |           |           |   * - coarse+fine particle
    | .   .   . | .   .   . | .   .   . | .   .   . |
    +-----------+-----------+-----------+-----------+
    
  • fineness=2 (and coarseness=2):

    +-------+-------+-------+-------+-------+
    | .   . | .   . | .   . | .   . | .   . |           . - fine particle
    |       |   *   |       |   *   |       |
    | .   . | .   . | .   . | .   . | .   . |           * - coarse particle
    +-------+-------+-------+-------+-------+
    
lcode.make_plasma(steps, cell_size, coarseness=3, fineness=2)[source]

Make coarse plasma initial state arrays and the arrays needed to intepolate coarse plasma into fine plasma (virt_params).

Coarse is the one that will evolve and fine is the one to be bilinearly interpolated from the coarse one based on the initial positions (using 1 to 4 coarse plasma particles that initially were the closest).

Initializing coarse particles is pretty simple: coarse_x_init and coarse_y_init are broadcasted output of make_coarse_plasma_grid(). coarse_x_offt and coarse_y_offt are zeros and so are coarse_px, coarse_py and coarse_pz. coarse_m and coarse_q are constants divided by the factor of coarseness by fineness squared because fine particles represent smaller macroparticles.

Initializing fine particle boils down to calculating the interpolation coefficients (influence_prev and influence_next) and the indices of the coarse particles (indices_prev, indices_next) that the characteristics will be intepolated from.

influence_prev and influence_next are linear interpolation coefficients based on the initial closest coarse particle positioning. Note that these are constant and do not change in \(\xi\). The edges get special treatment later.

indices_next happens to be pretty much equal to np.searchsorted(coarse_grid, fine_grid) and indices_prev is basically indices_next - 1, except for the edges, where a fine particle can have less than four ‘parent’ coarse particles. For such ‘outer’ particles, existing coarse particles are used instead, so clipping the indices and fixing influence-arrays is carried out.

Note that these arrays are 1D for memory considerations [Memory considerations].

The function returns the coarse particles and virtparams: a GPUArrays instance that conveniently groups the fine-particle related arrays, which only matter during deposition, under a single name.

Coarse-to-fine interpolation

../_images/virtplasma_moved.png
lcode.mix(coarse, A, B, C, D, pi, ni, pj, nj)[source]

Bilinearly interpolate fine plasma properties from four historically-neighbouring plasma particle property values:

B    D   #  y ^         A - bottom-left  neighbour, indices: pi, pj
   .     #    |         B - top-left     neighbour, indices: pi, nj
         #    +---->    C - bottom-right neighbour, indices: ni, pj
A    C   #         x    D - top-right    neighbour, indices: ni, nj

See the rest of the deposition and plasma creation for more info.

This is just a shorthand for the characteristic value mixing for internal use in coarse_to_fine.

../_images/coarse_to_fine.png
lcode.coarse_to_fine(fi, fj, c_x_offt, c_y_offt, c_m, c_q, c_px, c_py, c_pz, virtplasma_smallness_factor, fine_grid, influence_prev, influence_next, indices_prev, indices_next)[source]

Bilinearly interpolate fine plasma properties from four historically-neighbouring plasma particle property values.

The internals are pretty straightforward once you wrap your head around the indexing.

A single fine particle with the indices [fi, fj] (in fine particles virt_params 1D arrays) is interpolated from four particles with indices [pi, pj], [pi, nj], [ni, pj], [ni, nj] (in coarse particles c_* arrays) and four weights A, B, C, D respectively. The weights are, in turn, composed as a products of values from influence_prev and influence_next arrays, indiced, once again, with [fi, fj]. It would be convenient to calculate them beforehand, but they are recalculated instead as a result of time-memory tradeoff [Memory considerations].

Finally, momenta, charge and mass are scaled according to the coarse-to-fine macrosity coefficient discussed above.

Alternative illustration

(Source code, png, hires.png, pdf)

../_images/coarse_and_fine_plasma-1.png