112 lines
3.9 KiB
Go
112 lines
3.9 KiB
Go
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)
|
|
}
|
|
}
|