実際の分析経験に基づいて、DEMの窪み(シンク)を処理して埋める速度以外に、これら2つの窪み埋めアルゴリズムに違いがある場合、誰にも教えてもらえますか?
デジタル標高モデルの不況を埋める、高速でシンプルで多用途のアルゴリズム
オリビエプランション、フレデリックダルブー
そして
水文解析とモデリングのためのデジタル標高モデルで表面のくぼみを識別して埋めるための効率的な方法
王とLi
ありがとう。
実際の分析経験に基づいて、DEMの窪み(シンク)を処理して埋める速度以外に、これら2つの窪み埋めアルゴリズムに違いがある場合、誰にも教えてもらえますか?
デジタル標高モデルの不況を埋める、高速でシンプルで多用途のアルゴリズム
オリビエプランション、フレデリックダルブー
そして
水文解析とモデリングのためのデジタル標高モデルで表面のくぼみを識別して埋めるための効率的な方法
王とLi
ありがとう。
回答:
理論的には、うつ病の治療には1つの解決策しかありませんが、その解決策には多くの方法があります。そのため、非常に多くの異なるうつ病の治療アルゴリズムが存在します。したがって、PlanchonとDarboux、WangとLiu、または他のうつ病充填アルゴリズムのいずれかで満たされたDEMは、理論的には同じように見えるはずです。ただし、そうはしない可能性が高く、いくつかの理由があります。まず、窪みを埋めるための解決策は1つだけですが、埋められた窪みの平面に勾配を適用するためのさまざまな解決策があります。つまり、通常、窪みを埋めるだけでなく、その窪みの表面に強制的に流れたいと考えています。それには通常、非常に小さな勾配を追加する必要があり、1)これを行うためのさまざまな戦略があり(その多くはさまざまなうつ病充填アルゴリズムに直接組み込まれています)、2)そのような小さな数値を扱うと、しばしば小さな丸め誤差が発生します満たされたDEMの違いに現れます。この画像を見てください:
ソースDEMから生成された2つのDEMの「差のDEM」を示していますが、1つはプランションとダルブーアルゴリズムを使用して窪みを埋め、もう1つは王とandのアルゴリズムを使用して埋めました。うつ病充填アルゴリズムは、どちらもWhitebox GAT内のツールであり、したがって、上記の回答で説明したものとは異なるアルゴリズムの実装であると言えます。DEMの違いはすべて0.008 m未満であり、地形のくぼみの領域内に完全に含まれていることに注意してください(つまり、くぼみ内にないグリッドセルは、入力DEMとまったく同じ高さです)。8 mmの小さな値は、充填操作によって残された平坦な表面に流れを強制するために使用される小さな値を反映しており、浮動小数点値でこのような小さな数値を表す場合、丸め誤差のスケールによって多少影響を受ける可能性があります。上の画像では、2つの塗りつぶされたDEMが表示されていませんが、凡例エントリから、予想どおり正確に同じ範囲の標高値を持っていることがわかります。
それでは、なぜ上記の回答でDEMのピークや他の非うつ領域に沿った標高差を観察するのでしょうか?それは本当にアルゴリズムの特定の実装に帰着するだけだと思います。これらの違いを説明するためにツール内で何かが行われている可能性があり、実際のアルゴリズムとは無関係です。学術論文におけるアルゴリズムの記述と、GIS内でのデータの内部処理方法の複雑さを組み合わせた実際の実装とのギャップを考えると、これはそれほど驚くことではありません。とにかく、この非常に興味深い質問をしてくれてありがとう。
乾杯、
ジョン
私は自分の質問に答えようとします-ダンダンダン
SAGA GISを使用して、PlanchonおよびDarboux(PD)ベースの充填ツール(および6つの異なる流域のWangおよびLiu(WL)ベースの充填ツールを使用して、充填された流域の違いを調べました。それらは6つの流域すべてで類似していました)違いはアルゴリズムに起因するのか、アルゴリズムの特定の実装に起因するのかという疑問が常にあるため、「ベース」と言います。
流域DEMは、USGSが提供する流域シェープファイルを使用して、モザイク化されたNED 30 mデータをクリッピングすることによって生成されました。各ベースDEMについて、2つのツールが実行されました。両方のツールで0.01に設定された最小強制勾配は、各ツールに1つのオプションしかありません。
集水域が満たされた後、ラスタ計算機を使用して、結果のグリッドの違いを判断しました。これらの違いは、2つのアルゴリズムの動作の違いによるものです。
差異または差異の欠如(基本的には計算された差異ラスター)を表す画像を以下に示します。差の計算に使用される式は次のとおりでした:(((PD_Filled-WL_Filled)/ PD_Filled)* 100)-セルごとの差をパーセントで示します。灰色のセルは違いを示し、赤色のセルはPDの上昇が大きいことを示し、緑色のセルはWLの上昇が大きいことを示します。
第1流域:清流域、ワイオミング
これらの画像の凡例は次のとおりです。
差の範囲は-0.0915%から+ 0.0910%のみです。差異はピークと狭いストリームチャネルに集中しているようで、WLアルゴリズムはチャネル内でわずかに高く、PDは局所ピーク付近でわずかに高くなっています。
明確な流域、ワイオミング、ズーム1
清流域、ワイオミング、ズーム2
第2流域:ウィニペソーキー川、ニューハンプシャー州
これらの画像の凡例は次のとおりです。
ウィニペソーキー川、ニューハンプシャー州、ズーム1
差の範囲は-0.323%〜+ 0.315%のみです。差異は、ピークと狭いストリームチャネルに集中しているようです(以前と同様)。
すごい、考え?私にとって、この違いはささいなものであるように思われますが、おそらくそれ以上の計算には影響しません。誰もが同意しますか?これら6つの流域のワークフローを完了して確認しています。
編集: 詳細。WLアルゴリズムは、より広くより明確でないチャネルにつながり、高い地形インデックス値(私の最終的な派生データセット)を引き起こすようです。下の左の画像はPDアルゴリズム、右の画像はWLアルゴリズムです。
これらの画像は、同じ場所での地形指数の違いを示しています。右側のWL写真では、より広い湿ったエリア(より多くのチャネル-赤く、より高いTI)です。左側のPDの写真の狭いチャネル(濡れた領域が少ない-赤が少なく、赤い領域が狭く、TIが小さい)。
さらに、ここでPDが窪みを処理する方法(左)とWLがそれを処理する方法(右)があります。
そのため、わずかな違いであっても、追加の分析を通じて少しずつ差が出るようです。
誰かが興味を持っている場合のPythonスクリプトは次のとおりです。
#! /usr/bin/env python
# ----------------------------------------------------------------------
# Create Fill Algorithm Comparison
# Author: T. Taggart
# ----------------------------------------------------------------------
import os, sys, subprocess, time
# function definitions
def runCommand_logged (cmd, logstd, logerr):
p = subprocess.call(cmd, stdout=logstd, stderr=logerr)
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# environmental variables/paths
if (os.name == "posix"):
os.environ["PATH"] += os.pathsep + "/usr/local/bin"
else:
os.environ["PATH"] += os.pathsep + "C:\program files (x86)\SAGA-GIS"
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# global variables
WORKDIR = "D:\TomTaggart\DepressionFillingTest\Ran_DEMs"
# This directory is the toplevel directoru (i.e. DEM_8)
INPUTDIR = "D:\TomTaggart\DepressionFillingTest\Ran_DEMs"
STDLOG = WORKDIR + os.sep + "processing.log"
ERRLOG = WORKDIR + os.sep + "processing.error.log"
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# open logfiles (append in case files are already existing)
logstd = open(STDLOG, "a")
logerr = open(ERRLOG, "a")
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# initialize
t0 = time.time()
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# loop over files, import them and calculate TWI
# this for loops walks through and identifies all the folder, sub folders, and so on.....and all the files, in the directory
# location that is passed to it - in this case the INPUTDIR
for dirname, dirnames, filenames in os.walk(INPUTDIR):
# print path to all subdirectories first.
#for subdirname in dirnames:
#print os.path.join(dirname, subdirname)
# print path to all filenames.
for filename in filenames:
#print os.path.join(dirname, filename)
filename_front, fileext = os.path.splitext(filename)
#print filename
if filename_front == "w001001":
#if fileext == ".adf":
# Resetting the working directory to the current directory
os.chdir(dirname)
# Outputting the working directory
print "\n\nCurrently in Directory: " + os.getcwd()
# Creating new Outputs directory
os.mkdir("Outputs")
# Checks
#print dirname + os.sep + filename_front
#print dirname + os.sep + "Outputs" + os.sep + ".sgrd"
# IMPORTING Files
# --------------------------------------------------------------
cmd = ['saga_cmd', '-f=q', 'io_gdal', 'GDAL: Import Raster',
'-FILES', filename,
'-GRIDS', dirname + os.sep + "Outputs" + os.sep + filename_front + ".sgrd",
#'-SELECT', '1',
'-TRANSFORM',
'-INTERPOL', '1'
]
print "Beginning to Import Files"
try:
runCommand_logged(cmd, logstd, logerr)
except Exception, e:
logerr.write("Exception thrown while processing file: " + filename + "\n")
logerr.write("ERROR: %s\n" % e)
print "Finished importing Files"
# --------------------------------------------------------------
# Resetting the working directory to the ouputs directory
os.chdir(dirname + os.sep + "Outputs")
# Depression Filling - Wang & Liu
# --------------------------------------------------------------
cmd = ['saga_cmd', '-f=q', 'ta_preprocessor', 'Fill Sinks (Wang & Liu)',
'-ELEV', filename_front + ".sgrd",
'-FILLED', filename_front + "_WL_filled.sgrd", # output - NOT optional grid
'-FDIR', filename_front + "_WL_filled_Dir.sgrd", # output - NOT optional grid
'-WSHED', filename_front + "_WL_filled_Wshed.sgrd", # output - NOT optional grid
'-MINSLOPE', '0.0100000',
]
print "Beginning Depression Filling - Wang & Liu"
try:
runCommand_logged(cmd, logstd, logerr)
except Exception, e:
logerr.write("Exception thrown while processing file: " + filename + "\n")
logerr.write("ERROR: %s\n" % e)
print "Done Depression Filling - Wang & Liu"
# Depression Filling - Planchon & Darboux
# --------------------------------------------------------------
cmd = ['saga_cmd', '-f=q', 'ta_preprocessor', 'Fill Sinks (Planchon/Darboux, 2001)',
'-DEM', filename_front + ".sgrd",
'-RESULT', filename_front + "_PD_filled.sgrd", # output - NOT optional grid
'-MINSLOPE', '0.0100000',
]
print "Beginning Depression Filling - Planchon & Darboux"
try:
runCommand_logged(cmd, logstd, logerr)
except Exception, e:
logerr.write("Exception thrown while processing file: " + filename + "\n")
logerr.write("ERROR: %s\n" % e)
print "Done Depression Filling - Planchon & Darboux"
# Raster Calculator - DIff between Planchon & Darboux and Wang & Liu
# --------------------------------------------------------------
cmd = ['saga_cmd', '-f=q', 'grid_calculus', 'Grid Calculator',
'-GRIDS', filename_front + "_PD_filled.sgrd",
'-XGRIDS', filename_front + "_WL_filled.sgrd",
'-RESULT', filename_front + "_DepFillDiff.sgrd", # output - NOT optional grid
'-FORMULA', "(((g1-h1)/g1)*100)",
'-NAME', 'Calculation',
'-FNAME',
'-TYPE', '8',
]
print "Depression Filling - Diff Calc"
try:
runCommand_logged(cmd, logstd, logerr)
except Exception, e:
logerr.write("Exception thrown while processing file: " + filename + "\n")
logerr.write("ERROR: %s\n" % e)
print "Done Depression Filling - Diff Calc"
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# finalize
logstd.write("\n\nProcessing finished in " + str(int(time.time() - t0)) + " seconds.\n")
logstd.close
logerr.close
# ----------------------------------------------------------------------
アルゴリズムレベルでは、2つのアルゴリズムは同じ結果を生成します。
なぜ違いが出るのでしょうか?
データ表現
アルゴリズムの1つがfloat
(32ビット)を使用し、別のアルゴリズムが(double
64 ビット)を使用する場合、それらが同じ結果を生成することを期待しないでください。同様に、一部の実装では、浮動小数点値が整数データ型を使用することを表しますが、これも違いをもたらす可能性があります。
排水の実施
ただし、両方のアルゴリズムは、ローカライズされた方法を使用して流れの方向を決定する場合、流出しない平坦な領域を生成します。
PlanchonとDarbouxは、排水を強制するために平坦な領域の高さにわずかな増分を追加することでこれに対処します。Barnes等で議論されているように。(2014)の論文「ラスターデジタル標高モデルでの平らな表面上の排水方向の効率的な割り当て」では、この増分を追加すると、増分が大きすぎる場合に実際に平らな領域の外側の排水が不自然に再ルーティングされる可能性があります。解決策は、たとえばnextafter
関数を使用することです。
他の考え
Wang and Liu(2006)は、私の論文「Priority-flood:デジタル標高モデルのための最適なうつ病の充填および分水界ラベル付けアルゴリズム」で説明したように、Priority-Floodアルゴリズムの変形です。
Priority-Floodには、整数データと浮動小数点データの両方に対する時間の複雑さがあります。私の論文では、優先度キューにセルを配置しないことは、アルゴリズムのパフォーマンスを向上させる良い方法であることに注目しました。Zhou等の他の著者。(2016)およびWei et al。(2018)このアイデアを使用して、アルゴリズムの効率をさらに向上させました。これらすべてのアルゴリズムのソースコードは、ここから入手できます。
これを念頭に置いて、Planchon and Darboux(2001)アルゴリズムは、科学が失敗した場所の物語です。プライオリティ洪水で動作しながら、O(N)整数データとの時間O(NログN)浮動小数点データの時刻、P&Dは、O(Nで動作1.5)時間。これは、DEMのサイズとともに指数関数的に大きくなる大きなパフォーマンスの違いに変換されます。
2001年までに、Ehlschlaeger、Vincent、Soille、Beucher、Meyer、およびGratinは、Priority-Floodアルゴリズムを詳述した5つの論文をまとめて発表しました。PlanchonとDarboux、およびそのレビュー担当者は、これらすべてを逃し、桁違いに遅いアルゴリズムを発明しました。2018年になり、より良いアルゴリズムを構築していますが、P&Dはまだ使用されています。それは残念だと思います。