Okay, I went ahead and looked at performance a bit. First, here's an alternate to your rho function:
rho2[xp_, xg_, carga_, np_, ng_, dx_] :=
Module[
{rhoTable = Table[carga*np/(dx*ng), 1 + ng]},
rhoTable[[1 + ng]] = 0;
With[
{neighbors = Nearest[xg -> {"Index", "Distance"}, xp, {All, dx}]},
Map[(rhoTable[[#[[1]]]] -= (carga*(1 - (#[[2]])/dx)/dx)) &,
neighbors, {-2}];
rhoTable[[1]] += rhoTable[[ng + 1]];
{Length[Flatten@neighbors]/2, rhoTable}]]
I used local variables rather than update global ones. It looked like you were interested in number of updates, so I returned both that and the rho table, although I don't know if number of updates would ever be anything other than 2*nparticles
.
Here's the timing I got on my machine for your version:
(result1 = rho[x, xgrid, q, nparticles, ngrid, dx]; {r, \[Rho]}) // AbsoluteTiming // Short
(*{0.11498, {4000, {-12152.9, 8155.76, -4859.24, <<195>>, -11347.9, 468.88, -60255.7}}}*)
And here's the timing with the version using Nearest:
(result2 = rho2[x, xgrid, q, nparticles, ngrid, dx]) // AbsoluteTiming // Short
(*{0.02478, {4000, {-12152.9, 8155.76, -4859.24, <<195>>, -11347.9, 468.88, -60255.7}}}*)
And a quick check:
result1[[2]] == result2[[2]]
(*True*)