Project: s41467-024-50320-1 | Function: DepositCurrentSlice (cpp)

system: You are an expert C++ programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow C++ best practices and maintain consistent code style.
Return **only** the complete C++ function code.

user: Complete this C++ function:

**DESCRIPTION:** Deposits beam particle currents onto the computational grid for electromagnetic field calculations in plasma wakefield acceleration

**KEY TERMS:** {
  "jx_arr": "x-component current density",
  "jy_arr": "y-component current density",
  "jz_arr": "z-component current density",
  "depos_order": "particle shape function order",
  "ptd": "particle tile data",
  "charge": "particle charge"
}

**CONTEXT CODE:** /* Copyright 2020-2022
 *
 * This file is part of HiPACE++.
 *
 * Authors: AlexanderSinn, Andrew Myers, MaxThevenet, Remi Lehe
 * Severin Diederichs
 * License: BSD-3-Clause-LBNL
 */
#include "BeamDepositCurrent.H"
#include <iostream>

// MASKED FUNCTION: Deposits beam particle currents onto the computational grid
void
#include "BeamDepositCurrent.H"
#include <AMReX_ParallelFor.H>
#include <AMReX_GetIndex.H>
#include <AMReX_Abort.H>

void
DepositCurrentSlice(BeamParticleContainer& beam, Fields& fields,
                    amrex::Vector<amrex::Geometry> const& gm, int const lev,
                    const bool do_beam_jx_jy_deposition,
                    const bool do_beam_jz_deposition,
                    const bool do_beam_rhomjz_deposition,
                    const int which_slice, const int which_beam_slice, const bool only_highest)
{
    // Early return if no deposition is needed
    if (!do_beam_jx_jy_deposition && !do_beam_jz_deposition && !do_beam_rhomjz_deposition) {
        return;
    }

    // Skip non-highest levels if requested
    if (only_highest) {
        const int finest_level = beam.getFinestLevel();
        if (lev != finest_level) {
            return;
        }
    }

    // Retrieve current density MultiFabs for the current level
    auto& jx = fields.jx[lev];
    auto& jy = fields.jy[lev];
    auto& jz = fields.jz[lev];

    // Get geometry and grid parameters for the current level
    const auto& geom = gm[lev];
    const amrex::Real dx = geom.CellSize()[0];
    const amrex::Real dy = geom.CellSize()[1];
    const amrex::Real dz = geom.CellSize()[2];
    const amrex::Real xlo = geom.ProbLo()[0];
    const amrex::Real ylo = geom.ProbLo()[1];
    const amrex::Real zlo = geom.ProbLo()[2];

    // Get deposition order from beam properties
    const int depos_order = beam.getDeposOrder();

    // Loop over all tiles in the beam at the current level
    beam.forEachTile(lev, [&](auto& tile) {
        const auto& ptd = tile.getParticleTileData();
        const int npart = ptd.numParticles();

        // Struct-of-Arrays (SoA) access to particle attributes for GPU efficiency
        const auto& x = ptd.pos(0);
        const auto& y = ptd.pos(1);
        const auto& z = ptd.pos(2);
        const auto& vx = ptd.vel(0);
        const auto& vy = ptd.vel(1);
        const auto& vz = ptd.vel(2);
        const auto& charge = ptd.charge();

        // Parallel loop over particles (GPU-friendly)
        amrex::ParallelFor(npart, [=](int i) {
            const amrex::Real xp = x[i];
            const amrex::Real yp = y[i];
            const amrex::Real zp = z[i];
            const amrex::Real vxp = vx[i];
            const amrex::Real vyp = vy[i];
            const amrex::Real vzp = vz[i];
            const amrex::Real q = charge[i];

            // Skip particles not in the specified beam slice
            if (ptd.sliceIndex(i) != which_beam_slice) {
                return;
            }

            // Compute current density contributions (J = q * v)
            const amrex::Real Jx = q * vxp;
            const amrex::Real Jy = q * vyp;
            const amrex::Real Jz = q * vzp;

            // Convert real-space position to grid indices; check if inside domain
            int ix, iy, iz;
            bool inside = amrex::getIndex(geom, xp, yp, zp, ix, iy, iz);
            if (!inside) {
                return;
            }

            // Compute fractional coordinates within the cell (0 ≤ xi, yi, zi ≤ 1)
            const amrex::Real xi = (xp - (xlo + ix * dx)) / dx;
            const amrex::Real yi = (yp - (ylo + iy * dy)) / dy;
            const amrex::Real zi = (zp - (zlo + iz * dz)) / dz;

            // Deposit current using the specified shape function order
            if (depos_order == 1) {
                // Linear order (2nd-order accurate): deposit to 2x2x2 cells
                for (int dx_idx = 0; dx_idx <= 1; ++dx_idx) {
                    for (int dy_idx = 0; dy_idx <= 1; ++dy_idx) {
                        for (int dz_idx = 0; dz_idx <= 1; ++dz_idx) {
                            // Linear shape function weights
                            const amrex::Real wx = (dx_idx == 0) ? (1.0 - xi) : xi;
                            const amrex::Real wy = (dy_idx == 0) ? (1.0 - yi) : yi;
                            const amrex::Real wz = (dz_idx == 0) ? (1.0 - zi) : zi;
                            const amrex::Real weight = wx * wy * wz;

                            // Compute target cell indices
                            const int i_cell = ix + dx_idx;
                            const int j_cell = iy + dy_idx;
                            const int k_cell = iz + dz_idx;



Complete the function implementation replacing "throw std::runtime_error("Not implemented");".