# How can I get weighted Flow Accumulation to deal with negative values? [duplicate]

here's one I haven't seen anywhere, to my surprise. I am trying to do something a little different with Flow Accumulation, which I would think has been attempted before, but it's stumping me for now.

I want to weight flow accumulation by a loading map of pollutant z to get its accumulation as it's transported downstream. This is simple enough, except I'd like some areas to be net sinks -- that is, where a fixed amount of the pollutant is removed rather than accumulated. So, say our flow path contains cells with values 1 1 -1 1. -1 is a net sink, and so our accumulation here, with flow going left to right, would be 1 2 1 2. This too seems to be doable. I can make one weighting raster of 1 1 0 1 and another of 0 0 1 0, run the flow accumulation with both, then subtract the 2nd from the 1st. OK.

However, imagine this flowpath scenario -- 1 1 -5 1. Here I have a powerful "sink" at -5, which is in a position to remove everything that has flowed to it. Accumulation at that cell would be 2, and with 5 removed, this leaves us with -3 using the above method. But of course, having a quantity of -3 is nonsensical, and instead it should simply drop to 0, as everything is removed. At the end of this little 4-cell flowpath, accumulation should thus be 1.

Is there any way to weight or otherwise get Flow Accumulation to intelligently do the opposite of accumulating (de ... cumulating?) in certain specific areas, while also respecting a lower bound of 0? I'm hoping the method, if it exists, will be implementable in Python as well.

UPDATE:
If anyone is interested in this problem in the future, I may have figured out how to do it (though am still open to correction, as I'm not 100% sure). By default, the Flow Accumulation tool treats negative weightings as 0.

The steps are as follows:
1). Run Flow Accumulation with your weighting grid that includes negatives.
2). Apply the following conditional statement to the result:

``````Con(("FlowWeight" < 0) & ("FlowAccum" > 0),Con(-"FlowWeight" < "FlowAccum",
-"FlowWeight","FlowAccum"),0)
``````

This assigns a non-zero value to all cells with a negative weight and a non-zero accumulation, such that if the weight represents uptake of some but not all of what has accumulated there, the cell gets the value of that amount, as a positive number, and if uptake is more than what has accumulated, the value is simply the accumulated amount.

3). Run Flow Accumulation weighted by the grid resulting from the above. This is like the "loss accumulation".

4). Subtract the result of step 3 from the result of step 1. Force any negative values to 0.

• Please explain a little the framework in which you work on this. It is a GIS software? Jan 30, 2013 at 19:57
• Whoops, didn't actually mean to relegate that information to the tags. Yes I am working on this with the Spatial Analyst tools in ArcGIS 10.0, via Python (though my problem isn't w/ Python but with the tools themselves). Jan 30, 2013 at 20:38
• Re the edit: That's a good try, but it won't work in general when negative weights occur in succession. Consider the 1D problem, where water flows left to right, and let the weights be (1,1,1,-5,-3,4,1). FlowAccumulation will produce the values (1, 2, 3, -2, -5, -1, 0). Your conditional always produces 0, so the "loss accumulation" is also 0. The desired result is (1, 1, 1, 0, 0, 4, 5). It's hard to see how to fix up the calculation using a predetermined number of adjustments of this sort. I think you're stuck with writing your own version of FlowAccumulation from scratch. Feb 2, 2013 at 23:05
• Oh no, looks like you're right, I succumbed to a little wishful thinking about the solution & didn't test it for such a case (plus the solution was basically an attempt to recreate the logic of the script I linked in a comment below, which I guess must also be wrong?). Hard to believe FlowAcc has this limitation. Seems like it would be a worthwhile project to recreate it & modify in this way, but I have no idea how to get that far under the hood of ArcGIS. Thanks for your input! Feb 6, 2013 at 18:59

## 2 Answers

I do not work with ArcGIS, but I use SAGA mainly for hydrologic modelling. What I can suggest here is: - fill the drainage depressions, and then subtract the filled DEM from the original DEM, getting a raster with the depression depth; - compute flow accumulation, which will flow over the filled depressions; - compute an accumulation function, depending on the depression depth, to get a raster of accumulated polluant; - use the accumulation polluant raster in the modelling process (in SAGA there is an option for both material and weight in such a modelling).

• Hmm I'm afraid I'm not following your answer, because I am not sure I see how getting a raster of depression depths in the DEM is related to my problem. I'm using the term "sink" to mean a cell where pollutant that is routed to the cell is removed & does not continue along the flow path (b/c of, for instance, the type of land cover), rather than a "sink" that is a topographic depression in the DEM that can be filled. Sorry if I am telling you something you already know b/c I've failed to follow your logic. Jan 31, 2013 at 18:51
• Well, then just use the pollutant layer as material, and use negative weights for accumulation. Jan 31, 2013 at 21:28
• Of course, that would be the way to do it, unfortunately it seems in Arc weighting the Flow Accumulation tool with negative values produces ... well, I'm not sure exactly. But it doesn't appear to be correct arithmetic. Granted, it's a confusing chore to manually check the accuracy of a flow accumulation grid, so if anyone could confirm whether or not using weighting rasters with negative values in FlowAcc ever works, that would be helpful too. The other issue with this approach is that it would produce negative values in the FlowAcc grid, where only 0's would make real-world sense. Feb 1, 2013 at 0:18
• Actually, in weighting, you should use values from 0.1 to 1, and not negative. Feb 1, 2013 at 4:39
• I'm not sure how this would work -- flow accumulation is additive, and the weighting raster changes the values that it's adding from a default of 1. Therefore, the weighting values have to be specific values of pollutant either loaded or removed in a given cell. It seems someone wrote a script 12 years ago (!) to do just what I want at <arcscripts.esri.com/details.asp?dbid=11612>, but it's in Avenue, an old ArcView language, and as a scripting newbie, I can't make much sense of it. Feb 1, 2013 at 18:22

I dealt with a similar problem here. Like you speculated, you have to split your weight raster into positive and negative values, flow accumulate them separately, and recombine them. Here's a python code snippet from my answer that will do it for you:

``````def angleAccum(flowdir,angle):
pos_angle = Con(angle,angle,0,"Value > 0")
neg_angle = Abs(Con(angle,angle,0,"Value < 0"))
pos_accum = FlowAccumulation(flowdir, pos_angle,"FLOAT")
neg_accum = FlowAccumulation(flowdir, neg_angle,"FLOAT")
return Minus(pos_accum,neg_accum)
``````

It was written with averaging upslope aspect in mind (hence the`angle` argument), but it will work on any raster with negative values.

To use it, open your python window and enter:

``````from arcpy.sa import *
``````

then copy and paste the function into the window and hit enter. Finally, call the `angleAccum` function passing in your flow direction raster and your weight raster like so:

``````weightAccum = angleAccum(inFlowDir,inWeightRaster)
weightAccum.save("C:/Path/to/outputraster")
``````

Another option that should theoretically work is to transform all of your numbers to be positive numbers, then subtract the unweighted accumulation from your weighted accumulation. However, in practice this didn't seem to work quite right (See comments in linked question).