Tooling
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
package uplift
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"salty/terrain/internal/manifest"
|
||||
"salty/terrain/internal/world"
|
||||
)
|
||||
|
||||
// For n = 1 the uplift rate alone fixes the hillslope angle, so a uniformly painted island sits at the angle
|
||||
// of repose right down to the water. The coastal plain is what puts the range inland: the rate ramps from a
|
||||
// low value at the shore up to the class rate over a stated distance.
|
||||
//
|
||||
// The distinction from D-52, which removed a coastal taper, is that this one is asked for and does not go to
|
||||
// zero - the waterline keeps a real rate, so the strip the surf works in is not flattened.
|
||||
func TestTheCoastalPlainRampsInlandAndNeverToZero(t *testing.T) {
|
||||
// A 64 m cell so that a four-kilometre plain is 62 cells rather than 500: the grid has to be comfortably
|
||||
// wider than the thing being measured, which the first version of this test was not.
|
||||
const w, h, cellM = 256, 32, 64.0
|
||||
p := world.Planet{CellM: cellM, W: w, H: h, PadY: 0, NoisePeriodM: float64(w) * cellM}
|
||||
if err := p.Validate(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f := world.Whole(p)
|
||||
|
||||
class := make([]uint8, w*h)
|
||||
land := make([]bool, w*h)
|
||||
for y := 0; y < h; y++ {
|
||||
for x := 0; x < w; x++ {
|
||||
// Land from x = 20 rightwards, so distance to the shore is x - 20 cells.
|
||||
if x >= 20 {
|
||||
class[y*w+x], land[y*w+x] = 1, true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const rate = 0.0009 // 0.9 mm/yr
|
||||
const floor = 0.00006 // 0.06 mm/yr
|
||||
const plainM = 4000.0 // 4 km
|
||||
|
||||
m := manifest.Defaults()
|
||||
m.Source.Seed = 7
|
||||
up := FromTemplate(Paint{
|
||||
Frame: f, Class: class, Land: land,
|
||||
Rates: []float32{0, rate},
|
||||
Ks: []float32{1, 1},
|
||||
PlainM: []float64{0, plainM},
|
||||
PlainFloor: []float32{0, floor},
|
||||
Variation: 0, // the swell off, so the ramp is the only thing being measured
|
||||
}, m)
|
||||
|
||||
y := h / 2
|
||||
at := func(cellsInland int) float64 { return float64(up.Rate.Data[y*w+20+cellsInland]) }
|
||||
// Four kilometres is 62.5 cells at 64 m.
|
||||
const full = 63
|
||||
|
||||
// The first land cell is one cell from the water, not zero, so it has already climbed a sliver of the
|
||||
// ramp. A couple of per cent is that sliver; anything more would mean the ramp is not anchored at the
|
||||
// floor where it should be.
|
||||
if got := at(0); math.Abs(got-floor) > 0.02*floor {
|
||||
t.Errorf("at the waterline the rate is %.5f mm/yr, want the floor %.3f", got*1000, floor*1000)
|
||||
}
|
||||
if at(0) <= 0 {
|
||||
t.Error("the rate at the waterline is zero; that is D-52's mistake, not this feature")
|
||||
}
|
||||
if got := at(full); math.Abs(got-rate) > 1e-7 {
|
||||
t.Errorf("at 4 km inland the rate is %.4f mm/yr, want the class rate %.2f", got*1000, rate*1000)
|
||||
}
|
||||
if got := at(150); math.Abs(got-rate) > 1e-7 {
|
||||
t.Errorf("well inland the rate is %.4f mm/yr, want the class rate %.2f", got*1000, rate*1000)
|
||||
}
|
||||
// Monotonic in between, and genuinely below the class rate at the halfway mark.
|
||||
prev := 0.0
|
||||
for d := 0; d <= full; d++ {
|
||||
v := at(d)
|
||||
if v < prev-1e-12 {
|
||||
t.Fatalf("the ramp dips at %d cells inland", d)
|
||||
}
|
||||
prev = v
|
||||
}
|
||||
if got := at(full / 2); got >= rate*0.9 {
|
||||
t.Errorf("halfway across the plain the rate is already %.3f mm/yr of %.2f; that is not a plain",
|
||||
got*1000, rate*1000)
|
||||
}
|
||||
}
|
||||
|
||||
// Without the knob nothing changes, which is what keeps every existing world and every existing test where it
|
||||
// was.
|
||||
func TestNoCoastalPlainMeansTheRateReachesTheSea(t *testing.T) {
|
||||
const w, h = 64, 32
|
||||
p := world.Planet{CellM: 8, W: w, H: h, PadY: 0, NoisePeriodM: float64(w) * 8}
|
||||
f := world.Whole(p)
|
||||
class := make([]uint8, w*h)
|
||||
land := make([]bool, w*h)
|
||||
for i := range land {
|
||||
if i%w >= 8 {
|
||||
class[i], land[i] = 1, true
|
||||
}
|
||||
}
|
||||
m := manifest.Defaults()
|
||||
up := FromTemplate(Paint{
|
||||
Frame: f, Class: class, Land: land,
|
||||
Rates: []float32{0, 0.0009}, Ks: []float32{1, 1},
|
||||
PlainM: []float64{0, 0}, PlainFloor: []float32{0, 0}, Variation: 0,
|
||||
}, m)
|
||||
y := h / 2
|
||||
if got := float64(up.Rate.Data[y*w+8]); math.Abs(got-0.0009) > 1e-9 {
|
||||
t.Errorf("the first land cell is at %.4f mm/yr, want the full 0.9", got*1000)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user