← ギャラリーへ

砂丘の風紋 — 平らな砂は、平らでいられない

平らな砂面から風紋が育つ様子。0歩から4000歩までの断面5本
跳躍(風に飛ばされて弧を描き、少し先へ落ちる)とクリープ(落ちてきた粒に叩かれてじりじり転がる)だけの模型。風紋そのものは一本も描いていないのに、平らな砂面が勝手に縞になる。60 歩でもう波長が決まっていて、そこから 4000 歩まで、波長も振幅もほとんど動かない

なにか

砂浜を手でならしても、風が吹けばまた同じような間隔で縞が戻ってくる。雪原でも、水槽の底でも、砂時計をひっくり返した表面でも同じことが起きる。その「同じような間隔」はどこから来ているのか

砂の運ばれ方は 2 つに分かれる。跳躍——風に持ち上げられて弧を描き、少し先へ落ちる。クリープ——落ちてきた粒に叩かれて、その場をじりじり転がる。前者は砂を遠くへ運び、後者は凸凹をならす。西森と大内(1993)は、この2つだけを書いた最小の模型で風紋が出ることを示した。

この作品の要点は、飛距離がその場の高さで決まるところにある。出っぱったところにある砂粒は風をよく受けて遠くまで飛び、へこんだところの砂は近くに落ちる。それだけで平らな砂面は不安定になる。

波長は「選ばれる」——粗大化しない

初期のでたらめな凸凹(振幅 0.059)から始めると、60 歩でもう波長 11.2 の縞が立っている。そこから振幅は伸びるが 200 歩で止まり(1.578 → 4000 歩で 1.624)、波長も 11.1〜11.3 の幅から動かない。

これは当たり前のことではない。凸凹が育つ仕組みの多くは、時間とともにだんだん大きな構造へ移っていく(粗大化)。そうなると「波長」という量は時間の関数でしかなく、値として書けない。この模型ではそうならず、波長は定まった値に落ち着く。歩数を 1000 から 32000 まで 32 倍に振っても 11.10 → 11.89 の 7% しか動かない。

格子の刻みを振っても同じで、512/1024/2048 マスで波長の比は動かない。砂の総量は 10⁻¹¹ の幅で保存されている(跳んだぶんだけどこかに落ちるので当然だが、実装が壊れていないことの確認になる)。

★つまみが役割を分担している

3つのつまみを振ったときに波長と振幅がそれぞれ何倍動くかの比較
3つのつまみをそれぞれ振り、いちばん小さい値で 1 に正規化して比べた。跳躍距離だけが波長を動かす(6.14 倍)。高さへの敏感さとクリープは、波長をほとんど動かさない(1.18 倍・0.84 倍)のに、振幅は 0.26 倍・0.21 倍まで変える

「風紋の間隔は砂粒の飛距離で決まる」というのはよく聞く説明だが、模型で実際につまみを振ってみると、その言い方がどのくらい正確かが分かる。

つまみが3つあっても、波長を握っているのは1つだけだった。あとの2つは、波長をほとんど動かさずに「模様の濃さ」だけを変える。ユークリッドリズムで「均等の二つの条件が、個数と並べ方を分担していた」のと同じ形——複数のつまみがあるとき、それぞれが別々の量を握っていることがある

ならしすぎると、模様は立たない

クリープを強くしていくと、あるところで模様が育たなくなる。しきい値は D* ≈ 0.615(種を5通り変えても 0.612〜0.619)。それより上では、初期のでたらめな凸凹がならされて終わる。チューリング結晶のかたちと同じで、模様には「立つか立たないか」の境目がある

⚠️このしきい値を測るとき、道具の癖に一度だまされた。最初は「振幅が初期の 5 倍を超えたら模様が立った」と判定していて、二分探索は D* = 1.098 を返した。ところが実物を見ると、そこで出ていたのは波長 2.01 ——格子2マスおきに上下する振動だった。クリープをあらわに解く書き方は D < 1 でしか安定でなく、その外では格子の振動が発散していただけである。振幅が大きい=模様がある、ではない。いまは「NaN でない」と「波長が3マス以上」を一緒に見るようにして、直す前は落ちる検査を置いてある。

★自分で動かす

下の絵はこの場で計算している(あらかじめ描いた絵の切り替えではない)。上の図を作っているのと同じ 1 本のコード gallery/assets/ripple-live.js を、記事の中で呼んでいる。歩数を動かすと、平らな砂から風紋が育つところがそのまま見える。

模様は立ったか
波長
振幅
山の尖り(歪度)
砂の増減

スライダーで決めた条件で、その歩数まで進めた砂の断面

跳躍距離だけを動かして、波長の数字だけが素直について来ることを見てほしい。高さへの敏感さとクリープを動かすと、波長はほとんど動かないのに絵の濃さが変わる。クリープを 0.62 あたりより上げると、模様は立たなくなる。

どう作ったか

高さの列を輪にして、毎歩ぜんぶのマスから同じ量の砂を飛ばし、着地点で受け取る。着地は丸めずに線形補間で2マスに分ける——ここが要で、丸めると高さのちがい b·h が 1 マスに満たないうちは飛距離が全マス同じになり、模様が永久に育たない(実際にそれで固まって、原因を探した)。波長はスペクトルの山の近く3本の重みつき平均で読む(山の位置は整数の波数にしか置けないので、長い波長ほど階段状に飛ぶ)。機械検査は17件: ①平らな砂から模様が育つ ②砂の総量が保存(9通り)③★歩数を16倍に振っても波長が動かない(粗大化しない=波長は選ばれている)④格子を512→2048に振っても波長/跳躍距離が動かない ⑤掃引18通りすべてがしきい値の内側 ⑥★波長を動かすのは跳躍距離だけ(6.14倍/1.18倍/0.84倍)⑦★敏感さとクリープは振幅を動かす(0.26倍・0.21倍)⑧⚠️ただし波長/跳躍距離は1.41〜1.80と動く=「比例」と言い切るには足りない ⑨★クリープのしきい値が種5通りで再現(0.612〜0.619)⑩⚠️D=1.0 の「振幅が大きい」は格子2マスの振動=模様と数えない(直す前はこれをしきい値と誤っていた)⑪D=1.3 では発散する ⑫歪度が正=山が鋭い ⑬⚠️着地を丸めると模様が育たない(直す前に実際に固まった)⑭記事のドラッグ版を偽DOMで実際に走らせる14項目 ⑮出荷SVGとドラッグ版が同じ1本を共有 ⑯出荷SVG2枚。ドラッグ版の検査の実体は tools/ripple-live-test.js

→ チューリング(こちらも「一様が壊れて波長が選ばれる」棚。しくみは反応拡散)

→ ユークリッドリズム(つまみが役割を分担する、もうひとつの例)

→ 川の分岐(同じ「流れが地形を作る」棚。あちらは削る側)

出典

数理
H. Nishimori and N. Ouchi, "Formation of ripple patterns and dunes by wind-blown sand", Phys. Rev. Lett. 71 (1993) 197(跳躍+クリープの最小模型)。⚠️ 実物の砂紋の間隔・粒径・風速と突き合わせたわけではない——確かめたのは「この最小模型から何が出るか」だけで、実物との比較はしていない
生成
generators/ripple.js(跳躍とクリープの1歩・スペクトルと波長の読み取り・模様が立ったかの判定・クリープのしきい値の二分探索・つまみを振る掃引・図2枚。依存ゼロ・乱数は初期の凸凹だけ=種を決めれば答えも決まる)砂の数理は gallery/assets/ripple-live.js に置き、出荷SVGの生成器と記事のドラッグ版が同じ1本を共有している