{"id":156,"date":"2007-07-27T14:00:46","date_gmt":"2007-07-27T18:00:46","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/2007\/07\/27\/upslope-area-part-7\/"},"modified":"2019-10-23T13:44:05","modified_gmt":"2019-10-23T17:44:05","slug":"upslope-area-part-7","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2007\/07\/27\/upslope-area-part-7\/","title":{"rendered":"Upslope area &#8211; Recursive calculation procedure"},"content":{"rendered":"<div xmlns:mwsh=\"https:\/\/www.mathworks.com\/namespace\/mcode\/v1\/syntaxhighlight.dtd\" class=\"content\">\r\n   <p>So far in this series I've talked about calculating pixel flow directions and handling plateaus, but I haven't yet discussed\r\n      the actual upslope area calculation.  The Tarboton paper presents a recursive formulation of the upslope area calculation (from page 313):\r\n   <\/p><pre>  Procedure DPAREA(i, j)\r\n    if AREA(i, j) is known\r\n      then\r\n        no action\r\n      else\r\n        AREA(i, j) = 1 (the area of a single pixel)\r\n        for each neighbor (location in, jn)\r\n          p = proportion of neighbor (in, jn) that drains to\r\n              pixel (i, j) based on angle\r\n          if (p &gt; 0) then\r\n            call DPAREA(in, jn) (this is the recursive call to\r\n                 calculate the area for the neighbor)\r\n            AREA(i, j) = AREA(i, j) + p x AREA(in, jn)\r\n  Return<\/pre><p>I had to read the surrounding text a couple of times to figure out exactly how the author intends to calculate <i>p<\/i>.  Consider the flow direction for a particular neighbor, (in, jn).  If the flow direction points directly at pixel (i, j),\r\n      then the corresponding weight <i>p<\/i> is 1. In other words, pixel (i, j) gets all of the flow from (in, jn).  If the flow direction is pi\/4 or greater away from\r\n      the direction toward (i, j), then the weight <i>p<\/i> is 0.  Pixel (i, j) gets none of the flow from (in, jn).  In between an angular difference of 0 and pi\/4, the weight <i>p<\/i> varies proportionally between 1 and 0.\r\n   <\/p>\r\n   <p>For example, consider the computation of upslope area for pixel number 5 in this set of 9 pixels:<\/p><pre>   1 4 7\r\n   2 5 8\r\n   3 6 9<\/pre><p>If the flow direction for pixel 2 is zero radians, its flow is pointing directly at pixel 5, so the corresponding weight is\r\n      1.0.  If the flow direction for pixel 8 is pi\/4 radians, then its flow is pointing directly at pixel 4. The corresponding\r\n      weight for pixel 5 is 0.0.  If the flow direction is pi\/8 radians, its flow is pointing between pixels 5 and 4, and the weight\r\n      for the pixel 5 computation is 0.5.\r\n   <\/p>\r\n   <p>It also took me a few minutes to figure out how to compute the radial difference between two angles, properly taking into\r\n      account the 2*pi periodicity of angles.  (For example, the radial difference between pi\/8 and 2*pi - pi\/8 should be pi\/4.)\r\n       Here's what I came up with:\r\n   <\/p><pre>   radial_difference = abs(mod(theta1 - theta2 + pi), 2*pi) - pi)<\/pre><p>(Does anyone else have a better way to compute this quantity?)  To calculate the weight for a given neighbor of pixel (i,j),\r\n      first determine the angle that points directly from that neighbor to the pixel (i, j).  Call that angle theta_c.  Then find\r\n      the flow direction for that neighbor; call it theta_f.  Now compute the radial difference:\r\n   <\/p><pre>   radial_difference = abs(mod(theta_c - theta_f + pi), 2*pi) - pi)<\/pre><p>And finally compute the weight:<\/p><pre>   p = max(1 - (radial_difference * 4 \/ pi), 0)<\/pre><p>So, are we ready to start writing a recursive MATLAB function based on DPAREA above? Nope! I don't actually want to use a\r\n      recursive formulation at all.\r\n   <\/p>\r\n   <p>Here's a different way to think about it:<\/p><pre>  AREA(i,j) = 1 + p1*AREA(i1,j1) + p2*AREA(i2,j2) + ... + p8*AREA(i8,j8)<\/pre><p>If we write down this equation for each pixel in the image, we'll end up with a system of N linear equations in N unknowns.\r\n       Although the system is very large (N-by-N, where N is the number of pixels), it is also very sparse, because each equation\r\n      involves no more than nine of the unknowns.\r\n   <\/p>\r\n   <p>So we are getting very close to calculating upslope area. We \"just\" have to set up an extremely large sparse system of equations\r\n      and then solve it.\r\n   <\/p>\r\n   <p>Next time I'll tackle that.<\/p><script language=\"JavaScript\">\r\n<!--\r\n\r\n    function grabCode_8da7fc049ac845d681b92036d41169f7() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='8da7fc049ac845d681b92036d41169f7 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 8da7fc049ac845d681b92036d41169f7';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        author = 'Steve Eddins';\r\n        copyright = 'Copyright 2007 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add author and copyright lines at the bottom if specified.\r\n        if ((author.length > 0) || (copyright.length > 0)) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (author.length > 0) {\r\n                d.writeln('% _' + author + '_');\r\n            }\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n      \r\n      d.title = title + ' (MATLAB code)';\r\n      d.close();\r\n      }   \r\n      \r\n-->\r\n<\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_8da7fc049ac845d681b92036d41169f7()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n            the MATLAB code \r\n            <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; 7.4<br><\/p>\r\n<\/div>\r\n<!--\r\n8da7fc049ac845d681b92036d41169f7 ##### SOURCE BEGIN #####\r\n%%\r\n% So far in this series I've talked about calculating pixel flow\r\n% directions and handling plateaus, but I haven't yet discussed the actual\r\n% upslope area calculation.  The \r\n% <http:\/\/www.engineering.usu.edu\/cee\/faculty\/dtarb\/96wr03137.pdf \r\n% Tarboton paper> presents a recursive\r\n% formulation of the upslope area calculation (from page 313):\r\n%\r\n%    Procedure DPAREA(i, j)\r\n%      if AREA(i, j) is known\r\n%        then\r\n%          no action\r\n%        else\r\n%          AREA(i, j) = 1 (the area of a single pixel)\r\n%          for each neighbor (location in, jn)\r\n%            p = proportion of neighbor (in, jn) that drains to\r\n%                pixel (i, j) based on angle\r\n%            if (p > 0) then\r\n%              call DPAREA(in, jn) (this is the recursive call to\r\n%                   calculate the area for the neighbor)\r\n%              AREA(i, j) = AREA(i, j) + p x AREA(in, jn)\r\n%    Return\r\n%\r\n% I had to read the surrounding text a couple of times to figure out\r\n% exactly how the author intends to calculate _p_.  Consider the flow\r\n% direction for a particular neighbor, (in, jn).  If the flow direction\r\n% points directly at pixel (i, j), then the corresponding weight _p_ is 1.\r\n% In other words, pixel (i, j) gets all of the flow from (in, jn).  If the\r\n% flow direction is pi\/4 or greater away from the direction toward (i, j),\r\n% then the weight _p_ is 0.  Pixel (i, j) gets none of the flow from (in,\r\n% jn).  In between an angular difference of 0 and pi\/4, the weight _p_\r\n% varies proportionally between 1 and 0.\r\n%\r\n% For example, consider the computation of upslope area for pixel number 5\r\n% in this set of 9 pixels:\r\n%\r\n%     1 4 7\r\n%     2 5 8\r\n%     3 6 9\r\n%\r\n% If the flow direction for pixel 2 is pi radians, its flow is pointing\r\n% directly at pixel 5, so the corresponding weight is 1.0.  If the flow\r\n% direction for pixel 8 is pi\/4 radians, then its flow is pointing\r\n% directly at pixel 4. The corresponding weight for pixel 5 is 0.0.  If the\r\n% flow direction is pi\/8 radians, its flow is pointing between pixels 5 and\r\n% 4, and the weight for the pixel 5 computation is 0.5.\r\n%\r\n% It also took me a few minutes to figure out how to compute the radial\r\n% difference between two angles, properly taking into account the 2*pi\r\n% periodicity of angles.  (For example, the radial difference between pi\/8\r\n% and 2*pi - pi\/8 should be pi\/4.)  Here's what I came up with:\r\n%\r\n%     radial_difference = abs(mod(theta1 - theta2 + pi), 2*pi) - pi)\r\n%\r\n% (Does anyone else have a better way to compute this quantity?)  To\r\n% calculate the weight for a given neighbor of pixel (i,j), first \r\n% determine the angle that points directly from that neighbor to the pixel\r\n% (i, j).  Call that angle theta_c.  Then find the flow direction for that\r\n% neighbor; call it theta_f.  Now compute the radial difference:\r\n%\r\n%     radial_difference = abs(mod(theta_c - theta_f + pi), 2*pi) - pi)\r\n%\r\n% And finally compute the weight:\r\n%\r\n%     p = max(1 - (radial_difference * 4 \/ pi), 0)\r\n%\r\n% So, are we ready to start writing a recursive MATLAB function based on\r\n% DPAREA above? Nope! I don't actually want to use a recursive formulation\r\n% at all. \r\n%\r\n% Here's a different way to think about it:\r\n%\r\n%    AREA(i,j) = 1 + p1*AREA(i1,j1) + p2*AREA(i2,j2) + ... + p8*AREA(i8,j8)\r\n%\r\n% If we write down this equation for each pixel in the image, we'll end up\r\n% with a system of N linear equations in N unknowns.  Although the system\r\n% is very large (N-by-N, where N is the number of pixels), it is also very\r\n% sparse, because each equation involves no more than nine of the unknowns.\r\n%\r\n% So we are getting very close to calculating upslope area. We \"just\" have\r\n% to set up an extremely large sparse system of equations and then solve\r\n% it.\r\n%\r\n% Next time I'll tackle that.\r\n##### SOURCE END ##### 8da7fc049ac845d681b92036d41169f7\r\n-->","protected":false},"excerpt":{"rendered":"<p>\r\n   So far in this series I've talked about calculating pixel flow directions and handling plateaus, but I haven't yet discussed\r\n      the actual upslope area calculation.  The Tarboton paper... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2007\/07\/27\/upslope-area-part-7\/\">read more >><\/a><\/p>","protected":false},"author":42,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[9],"tags":[208,122,388],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/156"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/users\/42"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/comments?post=156"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/156\/revisions"}],"predecessor-version":[{"id":2251,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/156\/revisions\/2251"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=156"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=156"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=156"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}