<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;"># This file is part of COð˜•CEPT, the cosmological ð˜•-body code in Python.
# Copyright Â© 2015-2017 Jeppe Mosgaard Dakin.
#
# COð˜•CEPT is free software: You can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# COð˜•CEPT is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with COð˜•CEPT. If not, see http://www.gnu.org/licenses/
#
# The auther of COð˜•CEPT can be contacted at dakin(at)phys.au.dk
# The latest version of COð˜•CEPT is available at
# https://github.com/jmd-dk/concept/



# Import everything from the commons module.
# In the .pyx file, Cython declared variables will also get cimported.
from commons import *



# Entry point for the MacCormack method,
# which does time evolution of a fluid component.
@cython.header(# Arguments
               component='Component',
               á”‘dt='dict',
               # Locals
               attempt='int',
               i='Py_ssize_t',
               max_vacuum_corrections='int[::1]',
               mc_step='int',
               steps='Py_ssize_t[::1]',
               Ï_ptr='double*',
               Ïux_ptr='double*',
               Ïuy_ptr='double*',
               Ïuz_ptr='double*',
               )
def maccormack(component, á”‘dt):
    # Maximum allowed number of attempts to correct for
    # negative densities, for the first and second MacCormack step.
    max_vacuum_corrections = asarray([1, component.gridsize], dtype=C2np['int'])
    # Extract fluid grid pointers
    Ï_ptr   = component.Ï.grid
    Ïux_ptr = component.Ïux.grid
    Ïuy_ptr = component.Ïuy.grid
    Ïuz_ptr = component.Ïuz.grid
    # Step/flux directions for the first MacCormack step
    steps = next(maccormack_steps)
    # The two MacCormack steps
    for mc_step in range(2):
        # Evolve the fluid variables. If this leads to negative
        # densities, attempts are made to correct this.
        for attempt in range(max_vacuum_corrections[mc_step]):
            # Evolve fluid variables. In the first MacCormack step,
            # the variables are re-evolved at each attempt. In the
            # second MacCormack step, the variables should only be
            # evolved once (vacuum correction may still take place
            # multiple times).
            if mc_step == 0 or attempt == 0:
                # Nullify the starred grid buffers,
                # so that they are ready to be populated
                # by the following MacCormack step.
                if mc_step == 0:
                    component.nullify_fluid_gridË£()
                # Compute starred variables from unstarred variables
                evolve_fluid(component, á”‘dt, steps, mc_step)
            # Nullify the Î” buffers, so that they are ready to
            # be used by the following vacuum correction sweep.
            component.nullify_fluid_Î”()
            # Check and correct for density values heading dangerously
            # fast towards negative values. If every density value
            # is OK, accept this attempt at a MacCormack step as is.
            if not correct_vacuum(component, mc_step):
                break
        else:
            # None of the attempted MacCormack steps were accepted.
            # If this is the second MacCormack step, this means that
            # we have been unable to correct for negative densities.
            if mc_step == 1:
                abort('Giving up after {} failed attempts to remove negative densities in "{}"'
                      .format(max_vacuum_corrections[mc_step], component.name))
        # Reverse step direction for the second MacCormack step
        for i in range(3):
            steps[i] *= -1
    # The two MacCormack steps leave all values of all fluid variables
    # with double their actual values. All grid values thus need
    # to be halved. Note that no further communication is needed as we
    # also halve the pseudo and ghost points.
    for i in range(component.size):
        Ï_ptr  [i] *= 0.5
        Ïux_ptr[i] *= 0.5
        Ïuy_ptr[i] *= 0.5
        Ïuz_ptr[i] *= 0.5
    # Nullify the starred grid buffers and the Î” buffers,
    # leaving these with no leftover junk.
    component.nullify_fluid_gridË£()
    component.nullify_fluid_Î”()

# Infinite generator cycling through the 8 triples of
# step/flux directions, used in the maccormack function.
def generate_maccormack_steps():
    steps = []
    for sign in (+1, -1):
        steps.append(sign*asarray((+1, +1, +1), dtype=C2np['Py_ssize_t']))
        steps.append(sign*asarray((-1, +1, -1), dtype=C2np['Py_ssize_t']))
        steps.append(sign*asarray((-1, -1, +1), dtype=C2np['Py_ssize_t']))
        steps.append(sign*asarray((+1, -1, -1), dtype=C2np['Py_ssize_t']))
    yield from itertools.cycle(steps)
maccormack_steps = generate_maccormack_steps()

# Function which evolve the fluid variables of a component
@cython.header(# Arguments
               component='Component',
               á”‘dt='dict',
               steps='Py_ssize_t[::1]',
               mc_step='int',
               # Locals
               h='double',
               i='Py_ssize_t',
               indices_local_start='Py_ssize_t[::1]',
               indices_local_end='Py_ssize_t[::1]',
               j='Py_ssize_t',
               k='Py_ssize_t',
               shape='tuple',
               step_i='Py_ssize_t',
               step_j='Py_ssize_t',
               step_k='Py_ssize_t',
               ux_ijk='double',
               ux_sjk='double',
               uy_ijk='double',
               uy_isk='double',
               uz_ijk='double',
               uz_ijs='double',
               w='double',
               Ï='double[:, :, ::1]',
               Ï_ijk='double',
               Ï_ijs='double',
               Ï_isk='double',
               Ï_sjk='double',
               Ïux='double[:, :, ::1]',
               Ïux_ijk='double',
               Ïux_ijs='double',
               Ïux_isk='double',
               Ïux_sjk='double',
               ÏuxË£='double[:, :, ::1]',
               Ïuy='double[:, :, ::1]',
               Ïuy_ijk='double',
               Ïuy_ijs='double',
               Ïuy_isk='double',
               Ïuy_sjk='double',
               ÏuyË£='double[:, :, ::1]',
               Ïuz='double[:, :, ::1]',
               Ïuz_ijk='double',
               Ïuz_ijs='double',
               Ïuz_isk='double',
               Ïuz_sjk='double',
               ÏuzË£='double[:, :, ::1]',
               ÏË£='double[:, :, ::1]',
               )
def evolve_fluid(component, á”‘dt, steps, mc_step):
    """It is assumed that the unstarred and starred grids have
    correctly populated pseudo and ghost points.
    """
    # Physical grid spacing
    h = boxsize/component.gridsize
    # Exract steps in each direction
    step_i, step_j, step_k = steps
    # Arrays of start and end indices for the local part of the
    # fluid grids, meaning disregarding pseudo points and ghost points.
    # We have 2 ghost points in the beginning and 1 pseudo point and
    # 2 ghost points in the end.
    shape = component.shape
    indices_local_start = asarray((2, 2, 2), dtype=C2np['Py_ssize_t'])
    indices_local_end   = asarray(shape    , dtype=C2np['Py_ssize_t']) - 2 - 1
    # Extract fluid grids
    Ï   = component.Ï  .grid_mv
    Ïux = component.Ïux.grid_mv
    Ïuy = component.Ïuy.grid_mv
    Ïuz = component.Ïuz.grid_mv
    # Extract starred fluid grids
    ÏË£   = component.Ï  .gridË£_mv
    ÏuxË£ = component.Ïux.gridË£_mv
    ÏuyË£ = component.Ïuy.gridË£_mv
    ÏuzË£ = component.Ïuz.gridË£_mv
    # Get the equation of state parameter w at this instance in time
    w = component.w()
    # In the case of the second MacCormack step, the role of the
    # starred and the unstarred variables should be swapped.
    if mc_step == 1:
        Ï  , ÏË£   = ÏË£  , Ï
        Ïux, ÏuxË£ = ÏuxË£, Ïux
        Ïuy, ÏuyË£ = ÏuyË£, Ïuy
        Ïuz, ÏuzË£ = ÏuzË£, Ïuz
    # Loop which update the parsed starred variables
    # from the parsed unstarred variables.
    for         i in range(â„¤[indices_local_start[0]], â„¤[indices_local_end[0]]):
        for     j in range(â„¤[indices_local_start[1]], â„¤[indices_local_end[1]]):
            for k in range(â„¤[indices_local_start[2]], â„¤[indices_local_end[2]]):
                # Density at this point
                Ï_ijk = Ï[i, j, k]
                # Momentum density components at this point
                Ïux_ijk = Ïux[i, j, k]
                Ïuy_ijk = Ïuy[i, j, k]
                Ïuz_ijk = Ïuz[i, j, k]
                # Velocity components at this point
                ux_ijk = Ïux_ijk/Ï_ijk
                uy_ijk = Ïuy_ijk/Ï_ijk
                uz_ijk = Ïuz_ijk/Ï_ijk
                # Density at forward (backward) points
                Ï_sjk = Ï[i + step_i, j         , k         ]
                Ï_isk = Ï[i         , j + step_j, k         ]
                Ï_ijs = Ï[i         , j         , k + step_k]
                # Momentum density components at forward (backward) points
                Ïux_sjk = Ïux[i + step_i, j         , k         ]
                Ïux_isk = Ïux[i         , j + step_j, k         ]
                Ïux_ijs = Ïux[i         , j         , k + step_k]
                Ïuy_sjk = Ïuy[i + step_i, j         , k         ]
                Ïuy_isk = Ïuy[i         , j + step_j, k         ]
                Ïuy_ijs = Ïuy[i         , j         , k + step_k]
                Ïuz_sjk = Ïuz[i + step_i, j         , k         ]
                Ïuz_isk = Ïuz[i         , j + step_j, k         ]
                Ïuz_ijs = Ïuz[i         , j         , k + step_k]
                # Velocity components at forward (backward) points
                ux_sjk = Ïux_sjk/Ï_sjk
                uy_isk = Ïuy_isk/Ï_isk
                uz_ijs = Ïuz_ijs/Ï_ijs
                # Flux of Ï (Ï*u)
                Ï_flux = (+ step_i*(Ïux_sjk - Ïux_ijk)
                          + step_j*(Ïuy_isk - Ïuy_ijk)
                          + step_k*(Ïuz_ijs - Ïuz_ijk)
                          )
                # Flux of Ïux (Ïux*u)
                Ïux_flux = (+ step_i*(Ïux_sjk*ux_sjk - Ïux_ijk*ux_ijk)
                            + step_j*(Ïux_isk*uy_isk - Ïux_ijk*uy_ijk)
                            + step_k*(Ïux_ijs*uz_ijs - Ïux_ijk*uz_ijk)
                            # Pressure term
                            + step_i*â„[w/(1 + w)]*(Ï_sjk - Ï_ijk)
                            )
                # Flux of Ïuy (Ïuy*u)
                Ïuy_flux = (+ step_i*(Ïuy_sjk*ux_sjk - Ïuy_ijk*ux_ijk)
                            + step_j*(Ïuy_isk*uy_isk - Ïuy_ijk*uy_ijk)
                            + step_k*(Ïuy_ijs*uz_ijs - Ïuy_ijk*uz_ijk)
                            # Pressure term
                            + step_j*â„[w/(1 + w)]*(Ï_isk - Ï_ijk)
                            )
                # Flux of Ïuz (Ïuz*u)
                Ïuz_flux = (+ step_i*(Ïuz_sjk*ux_sjk - Ïuz_ijk*ux_ijk)
                            + step_j*(Ïuz_isk*uy_isk - Ïuz_ijk*uy_ijk)
                            + step_k*(Ïuz_ijs*uz_ijs - Ïuz_ijk*uz_ijk)
                            # Pressure term
                            + step_k*â„[w/(1 + w)]*(Ï_ijs - Ï_ijk)
                            )
                # Update Ï
                ÏË£[i, j, k] += (# Initial value
                                + Ï_ijk
                                # Flux
                                - â„[á”‘dt['aâ»Â²']/h]*Ï_flux
                                )
                # Update Ïux
                ÏuxË£[i, j, k] += (# Initial value
                                  + Ïux_ijk
                                  # Flux
                                  - â„[á”‘dt['aâ»Â²']/h]*Ïux_flux
                                  )
                # Update Ïuy
                ÏuyË£[i, j, k] += (# Initial value
                                  + Ïuy_ijk
                                  # Flux
                                  - â„[á”‘dt['aâ»Â²']/h]*Ïuy_flux
                                  )
                # Update Ïuz
                ÏuzË£[i, j, k] += (# Initial value
                                  + Ïuz_ijk
                                  # Flux
                                  - â„[á”‘dt['aâ»Â²']/h]*Ïuz_flux
                                  )
    # Populate the pseudo and ghost points with the updated values.
    # Depedendent on whether we are doing the first of second
    # MacCormack step (mc_step), the updated grids are really the
    # starred grids (first MacCormack step) or the
    # unstarred grids (second MacCormack step)
    if mc_step == 0:
        component.communicate_fluid_gridsË£(mode='populate')
    else:  # mc_step == 1
        component.communicate_fluid_grids(mode='populate')

# Function which checks for imminent vacuum in a fluid component
# and does one sweep of vacuum corrections.
@cython.header(# Arguments
               component='Component',
               mc_step='int',
               # Locals
               dist2='Py_ssize_t',
               fac_smoothing='double',
               fac_time='double',
               i='Py_ssize_t',
               indices_local_start='Py_ssize_t[::1]',
               indices_local_end='Py_ssize_t[::1]',
               j='Py_ssize_t',
               k='Py_ssize_t',
               m='Py_ssize_t',
               mi='Py_ssize_t',
               mj='Py_ssize_t',
               mk='Py_ssize_t',
               n='Py_ssize_t',
               ni='Py_ssize_t',
               nj='Py_ssize_t',
               nk='Py_ssize_t',
               shape='tuple',
               timespan='double',
               vacuum_imminent='bint',
               Î”Ï='double[:, :, ::1]',
               Î”Ï_ptr='double*',
               Î”Ïux='double[:, :, ::1]',
               Î”Ïux_ptr='double*',
               Î”Ïuy='double[:, :, ::1]',
               Î”Ïuy_ptr='double*',
               Î”Ïuz='double[:, :, ::1]',
               Î”Ïuz_ptr='double*',
               Ï='double[:, :, ::1]',
               Ï_correction='double',
               Ï_ijk='double',
               Ï_ptr='double*',
               Ïux='double[:, :, ::1]',
               Ïux_correction='double',
               Ïux_ptr='double*',
               ÏuxË£='double[:, :, ::1]',
               Ïuy='double[:, :, ::1]',
               Ïuy_correction='double',
               Ïuy_ptr='double*',
               ÏuyË£='double[:, :, ::1]',
               Ïuz='double[:, :, ::1]',
               Ïuz_correction='double',
               Ïuz_ptr='double*',
               ÏuzË£='double[:, :, ::1]',
               ÏË£='double[:, :, ::1]',
               ÏË£_ijk='double',
               returns='bint',
               )
def correct_vacuum(component, mc_step):
    """This function will detect and correct for imminent vacuum in a
    fluid component. The vacuum detection is done differently depending
    on the MacCormack step (the parsed mc_step). For the first
    MacCormack step, vacuum is considered imminent if a density below
    the vacuum density, Ï_vacuum, will be reached within timespan
    similiar time steps. For the second MacCormack step, vacuum is
    considered imminent if the density is below the vacuum density.
    The vacuum correction is done by smoothing all fluid variables in
    the 3x3x3 neighbouring cells souronding the vacuum cell.
    The smoothing between each pair of cells, call them (Ïi, Ïj),
    is given by
    Ïi += fac_smoothing*(Ïj - Ïi)/rÂ²,
    Ïj += fac_smoothing*(Ïi - Ïj)/rÂ²,
    where r is the distance between the cells in grid units.
    Whether or not any vacuum corrections were made is returned
    as the return value.
    Experimentally, it has been found that when
    max_vacuum_corrections[0] == 1,
    the following values give good, stable results:
    timespan = 30
    fac_smoothing = 1.5/(6/1 + 12/2 + 8/3)
    """
    # In the case of the first MacCormack step, consider vacuum to be
    # imminent if a cell will reach the vacuum density after this many
    # similar time steps. Should be at least 1.
    timespan = 30
    # Amount of smoohing to apply when vacuum is detected.
    # A numerator of 0 implies no smoothing.
    # A numerator of 1 implies that in the most extreme case,
    # a vacuum cell will be replaced with a weighted average of its
    # 26 neighbour cells (all of the original cell will be distributed
    # among these neighbors).
    fac_smoothing = â„[1.5/(6/1 + 12/2 + 8/3)]
    # Arrays of start and end indices for the local part of the
    # fluid grids, meaning disregarding pseudo points and ghost points.
    # We have 2 ghost points in the beginning and 1 pseudo point and
    # 2 ghost points in the end.
    shape = component.shape
    indices_local_start = asarray([2, 2, 2], dtype=C2np['Py_ssize_t'])
    indices_local_end   = asarray(shape    , dtype=C2np['Py_ssize_t']) - 2 - 1
    # Extract memory views and pointers to the fluid variables
    Ï        = component.Ï  .grid_mv
    Ï_ptr    = component.Ï  .grid
    ÏË£       = component.Ï  .gridË£_mv
    ÏË£_ptr   = component.Ï  .gridË£
    Î”Ï       = component.Ï  .Î”_mv
    Î”Ï_ptr   = component.Ï  .Î”
    Ïux      = component.Ïux.grid_mv
    Ïux_ptr  = component.Ïux.grid
    ÏuxË£     = component.Ïux.gridË£_mv
    ÏuxË£_ptr = component.Ïux.gridË£
    Î”Ïux     = component.Ïux.Î”_mv
    Î”Ïux_ptr = component.Ïux.Î”
    Ïuy      = component.Ïuy.grid_mv
    Ïuy_ptr  = component.Ïuy.grid
    ÏuyË£     = component.Ïuy.gridË£_mv
    ÏuyË£_ptr = component.Ïuy.gridË£
    Î”Ïuy     = component.Ïuy.Î”_mv
    Î”Ïuy_ptr = component.Ïuy.Î”
    Ïuz      = component.Ïuz.grid_mv
    Ïuz_ptr  = component.Ïuz.grid
    ÏuzË£     = component.Ïuz.gridË£_mv
    ÏuzË£_ptr = component.Ïuz.gridË£
    Î”Ïuz     = component.Ïuz.Î”_mv
    Î”Ïuz_ptr = component.Ïuz.Î”
    # In the case of the second MacCormack step, the role of the
    # starred and the unstarred variables should be swapped.
    if mc_step == 1:
        Ï      , ÏË£       = ÏË£      , Ï
        Ï_ptr  , ÏË£_ptr   = ÏË£_ptr  , Ï_ptr
        Ïux    , ÏuxË£     = ÏuxË£    , Ïux
        Ïux_ptr, ÏuxË£_ptr = ÏuxË£_ptr, Ïux_ptr
        Ïuy    , ÏuyË£     = ÏuyË£    , Ïuy
        Ïuy_ptr, ÏuyË£_ptr = ÏuyË£_ptr, Ïuy_ptr
        Ïuz    , ÏuzË£     = ÏuzË£    , Ïuz
        Ïuz_ptr, ÏuzË£_ptr = ÏuzË£_ptr, Ïuz_ptr
    # Loop over the local domain and check and compute
    # corrections for imminent vacuum.
    vacuum_imminent = False
    for         i in range(â„¤[indices_local_start[0]], â„¤[indices_local_end[0]]):
        for     j in range(â„¤[indices_local_start[1]], â„¤[indices_local_end[1]]):
            for k in range(â„¤[indices_local_start[2]], â„¤[indices_local_end[2]]):
                # Unstarred and starred density at this point
                Ï_ijk  = Ï [i, j, k]
                ÏË£_ijk = ÏË£[i, j, k]
                # Check for imminent vacuum.
                # After the first MacCormack step, vacuum is considered
                # to be imminent if a density below the vacuum density,
                # Ï_vacuum, will be reached within timespan similiar
                # time steps. That is, vacuum is imminent if
                # Ï + timespan*dÏ &lt; Ï_vacuum,
                # where dÏ is the change in Ï from the first MacCormack
                # step, given by dÏ = Â½(ÏË£ - Ï), where the factor Â½ is
                # due to ÏË£ really holding double the change,
                # ÏË£ = Ï + 2*dÏ. Put together, this means that vacuum
                # is imminent if
                # ÏË£ + Ï*(2/timespan - 1) &lt; 2/timespan*Ï_vacuum.
                # After the second MacCormack step, vacuum is considered
                # to be imminent only if the density is lower than the
                # vacuum density, Ï_vacuum. Because the starred
                # variables hold double their actual values,
                # this corresponds to
                # ÏË£_ijk &lt; 2*Ï_vacuum.
                if (   (mc_step == 0 and Ï_ijk*â„[2/timespan - 1] + ÏË£_ijk &lt; â„[2/timespan*Ï_vacuum])
                    or (mc_step == 1 and                           ÏË£_ijk &lt; â„[2*Ï_vacuum])
                    ):
                    vacuum_imminent = True
                    # The amount of smoothing to apply depends upon
                    # how far into the future densities below the vacuum
                    # density will be reached.
                    if mc_step == 0:
                        # The number of time steps before densities
                        # lower than the vacuum density is given by
                        # Ï + timesteps*dÏ == Ï_vacuum, dÏ = Â½(ÏË£ - Ï).
                        # --&gt; timesteps = 2*(Ï - Ï_vacuum)/(Ï - ÏË£).
                        fac_time = 0.5*(Ï_ijk - ÏË£_ijk)/(Ï_ijk - Ï_vacuum)
                    else:  # mc_step == 1
                        # The density is already lower
                        # than the vaccuum density.
                        fac_time = 1
                    # Loop over all cell pairs (m, n) in the 3x3x3 block
                    # souronding the vacuum cell and apply smoothing.
                    for m in range(27):
                        # 3D indices of m'th cell
                        mi = i + relative_neighbour_indices_i[m]
                        mj = j + relative_neighbour_indices_j[m]
                        mk = k + relative_neighbour_indices_k[m]
                        for n in range(m + 1, 27):
                            # 3D indices of n'th cell
                            ni = i + relative_neighbour_indices_i[n]
                            nj = j + relative_neighbour_indices_j[n]
                            nk = k + relative_neighbour_indices_k[n]
                            # Distance squared between the two cells,
                            # in grid units (1 â‰¤ dist2 â‰¤ 12).
                            dist2 = (ni - mi)**2 + (nj - mj)**2 + (nk - mk)**2
                            # Compute vacuum corrections
                            Ï_correction   = (Ï  [ni, nj, nk] - â„[Ï  [mi, mj, mk]])*â„[fac_smoothing*fac_time/dist2]
                            Ïux_correction = (Ïux[ni, nj, nk] - â„[Ïux[mi, mj, mk]])*â„[fac_smoothing*fac_time/dist2]
                            Ïuy_correction = (Ïuy[ni, nj, nk] - â„[Ïuy[mi, mj, mk]])*â„[fac_smoothing*fac_time/dist2]
                            Ïuz_correction = (Ïuz[ni, nj, nk] - â„[Ïuz[mi, mj, mk]])*â„[fac_smoothing*fac_time/dist2]
                            # Store vacuum corrections
                            Î”Ï  [mi, mj, mk] += Ï_correction
                            Î”Ïux[mi, mj, mk] += Ïux_correction
                            Î”Ïuy[mi, mj, mk] += Ïuy_correction
                            Î”Ïuz[mi, mj, mk] += Ïuz_correction
                            Î”Ï  [ni, nj, nk] -= Ï_correction
                            Î”Ïux[ni, nj, nk] -= Ïux_correction
                            Î”Ïuy[ni, nj, nk] -= Ïuy_correction
                            Î”Ïuz[ni, nj, nk] -= Ïuz_correction
    # If vacuum is imminent on any process, consider it to be
    # imminent on every process.
    vacuum_imminent = allreduce(vacuum_imminent, op=MPI.LOR)
    if vacuum_imminent:
        # Communicate contributions to local vacuum corrections
        # residing on other processes.
        component.communicate_fluid_Î”(mode='add contributions')
        # Local Î” buffers now store final values. Populate pseudo
        # and ghost points of Î” buffers.
        component.communicate_fluid_Î”(mode='populate')
        # Apply vacuum corrections. Note that no further communication
        # is needed as we also apply vacuum corrections to the
        # pseudo and ghost points.
        for i in range(component.size):
            Ï_ptr  [i] += Î”Ï_ptr  [i]
            Ïux_ptr[i] += Î”Ïux_ptr[i]
            Ïuy_ptr[i] += Î”Ïuy_ptr[i]
            Ïuz_ptr[i] += Î”Ïuz_ptr[i]
    # The return value should indicate whether or not
    # vacuum corrections have been carried out.
    return vacuum_imminent
# 1D memory views of relative indices to the 27 neighbours of a cell
# (itself included). These are thus effectively mappings from
# 1D indices to 3D indices.
cython.declare(relative_neighbour_indices_i='Py_ssize_t[::1]',
               relative_neighbour_indices_j='Py_ssize_t[::1]',
               relative_neighbour_indices_k='Py_ssize_t[::1]',
               )
relative_neighbour_indices = asarray([(i, j, k) for i in range(-1, 2)
                                                for j in range(-1, 2)
                                                for k in range(-1, 2)], dtype=C2np['Py_ssize_t'])
relative_neighbour_indices_i = asarray(relative_neighbour_indices[:, 0]).copy()
relative_neighbour_indices_j = asarray(relative_neighbour_indices[:, 1]).copy()
relative_neighbour_indices_k = asarray(relative_neighbour_indices[:, 2]).copy()
</pre></body></html>