TerrainGen coverage


terraingen/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
38 / 38
100.0%
Branches:
34 / 68
50.0%
Functions:
3 / 3, 1 excl
100.0%

albedo/splotches.h
Line Branch Exec Source
1 /// @file
2 /// @brief Splotches: the dark and bright marks secondary impacts of loose regolith leave.
3 #pragma once
4
5 #include "terraingen/albedo/albedo.h"
6 #include "terraingen/layers/craters/crater.h"
7 #include "terraingen/layers/fade.h"
8 #include "terraingen/random/value_distribution.h"
9 #include "terraingen/util/cells.h"
10 #include "terraingen/util/surface.h"
11
12 #include <cstdint>
13 #include <memory>
14 #include <optional>
15 #include <vector>
16
17 namespace terraingen {
18
19 /// Swarms of splotches around new craters, the low-velocity secondaries of their ejecta (Robinson
20 /// et al. 2015); off by default. New craters from `minCraterDiameter` to `maxCraterDiameter` form
21 /// at `craterRate` (D / 10 m)^-`craterSlope` per km^2 per year (Speyerer et al. 2016: 16 a year of
22 /// at least 10 m over 3.305e6 km^2 yr, with the Neukum slope of 2.97 to 3.15), each throwing
23 /// `referenceCount` (D / `referenceDiameter`)^(3 + 1.5 `mu`) splotches, as the ejecta mass faster
24 /// than a speed grows (Housen and Holsapple 2011, `mu` 0.41 for sand), landing between `minRange`
25 /// and `maxRange` with N(> r) ~ r^(-1.5 `mu`) for launches at 45 degrees. Robinson et al. counted
26 /// 248 splotches 2 to 22 m across (median 6 m) within 30 km of an 18.8 m crater, at a median
27 /// distance of 8.7 km, which sets `minRange`; 239 were darker (median -4%), 3 brighter (+4% to
28 /// +12%), and some wedges pointing back to the crater. The spread of sizes, the share of wedges and
29 /// their elongation are illustrative. The swarms fade with the splotches' lifetime.
30 struct SplotchSwarms {
31 1 bool enabled = false; ///< Whether new craters throw swarms.
32 1 double craterRate = 4.84e-6; ///< New craters of at least 10 m, per km^2 per year.
33 1 double craterSlope = 3.06; ///< Cumulative slope of the new craters; positive.
34 1 double minCraterDiameter = 10.0; ///< Smallest crater with a swarm (m); positive.
35 1 double maxCraterDiameter = 50.0; ///< Largest (m); above the smallest.
36 1 double referenceDiameter = 18.8; ///< Diameter of the reference crater (m).
37 1 double referenceCount = 248.0; ///< Splotches of the reference crater; positive.
38 1 double mu = 0.41; ///< Velocity exponent of the target, in (0, 1).
39 1 double minRange = 4300.0; ///< Nearest landing distance (m); positive.
40 1 double maxRange = 30000.0; ///< Farthest landing distance (m); above the nearest.
41 /// Diameter of a swarm splotch (m); positive and bounded.
42 1 ValueDistribution splotchDiameter{ValueDistribution::Kind::LogNormal, 6.0, 0.6, 2.0, 22.0};
43 1 double darkShare = 239.0 / 248.0; ///< Share darker than the ground, in [0, 1].
44 1 double brightShare = 3.0 / 248.0; ///< Share brighter; the rest are mixed.
45 /// Reflectance change of a dark swarm splotch; above -1 and bounded.
46 1 ValueDistribution darkChange{ValueDistribution::Kind::Constant, -0.04};
47 /// Reflectance change of a bright swarm splotch; above -1 and bounded.
48 1 ValueDistribution brightChange{ValueDistribution::Kind::Uniform, 0.04, 0.12};
49 1 double wedgeShare = 0.2; ///< Share of wedges pointing back to the crater, [0, 1].
50 1 double wedgeElongation = 2.0; ///< Long over short axis of a wedge; at least 1.
51 /// New craters given by hand, such as an observed impact, each throwing a swarm like the
52 /// generated ones; IDs of 0 come from `ManualCraterId`.
53 1 std::vector<Crater> craters;
54
55 /// New craters of at least 1 m per m^2 within `lifetimeMyr`.
56 double Coefficient(double lifetimeMyr) const;
57
58 /// The splotches a crater `diameter` metres across throws, on average.
59 double Count(double diameter) const;
60
61
18/36
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 time.
✗ Branch 16 not taken.
✓ Branch 17 taken 1 time.
✗ Branch 18 not taken.
✓ Branch 19 taken 1 time.
✗ Branch 21 not taken.
✓ Branch 22 taken 1 time.
✗ Branch 23 not taken.
✓ Branch 24 taken 1 time.
✗ Branch 25 not taken.
✓ Branch 26 taken 1 time.
✗ Branch 28 not taken.
✓ Branch 29 taken 1 time.
✗ Branch 31 not taken.
✓ Branch 32 taken 1 time.
✗ Branch 33 not taken.
✓ Branch 34 taken 1 time.
✗ Branch 35 not taken.
✓ Branch 36 taken 1 time.
✗ Branch 38 not taken.
✓ Branch 39 taken 1 time.
1 bool operator==(const SplotchSwarms&) const = default;
62 };
63
64 /// Splotches after Speyerer et al. (2016): formed at a cumulative rate of `rateCoefficient`
65 /// d^-`rateExponent` per km^2 per year for diameter d in km, each lasting `lifetimeMyr`, the
66 /// time splotches take to churn the top centimetres. Most are dark, some bright and the rest mixed,
67 /// each nearly round; a younger splotch covers older ones as it fades.
68 struct SplotchOptions {
69 1 std::uint32_t seed = 0; ///< Seed of where splotches fall and what they are.
70 1 double rateCoefficient = 1.483e-11; ///< Formation rate coefficient, per km^2 per year.
71 1 double rateExponent = 4.144; ///< Cumulative slope of the formation rate; positive.
72 1 double lifetimeMyr = 0.081; ///< How long a splotch lasts, fading linearly (Myr).
73 1 double minDiameter = 1.0; ///< Smallest splotch (m); the fit is extrapolated below 10.
74 1 double maxDiameter = 40.0; ///< Largest splotch (m), above `minDiameter`.
75 1 double darkShare = 0.907; ///< Share of dark splotches, in [0, 1].
76 1 double brightShare = 0.074; ///< Share of bright ones; the rest are mixed.
77 /// Reflectance change of a dark splotch, relative to the ground before it; above -1.
78 1 ValueDistribution darkChange{ValueDistribution::Kind::Constant, -0.04};
79 /// Reflectance change of a bright splotch; above -1.
80 1 ValueDistribution brightChange{ValueDistribution::Kind::Constant, 0.10};
81 /// Share of splotches on slopes steeper than `steepSlopeDegrees` that are bright, in [0, 1];
82 /// unset keeps `brightShare`. Bright splotches are found mostly on such slopes, where mature
83 /// regolith is thin (Speyerer et al. 2016), but the sources give no share; needs the ground.
84 1 std::optional<double> steepBrightShare;
85 1 double steepSlopeDegrees = 15.0; ///< Slope from which ground is steep, in (0, 90) degrees.
86 1 double softness = 0.3; ///< Share of the radius over which the edge fades, in (0, 1].
87 1 double raggedness = 0.15; ///< Share of the radius the edge's lobes pull in, in [0, 1).
88 1 ResolutionFade fade{}; ///< How splotches too small to resolve fade out.
89 1 SplotchSwarms swarms{}; ///< Swarms around new craters; off by default.
90
91 /// The cumulative number of splotches of diameter at least 1 m per m^2 at any time.
92 double Coefficient() const;
93
94
16/32
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 time.
✗ Branch 17 not taken.
✓ Branch 18 taken 1 time.
✗ Branch 20 not taken.
✓ Branch 21 taken 1 time.
✗ Branch 23 not taken.
✓ Branch 24 taken 1 time.
✗ Branch 25 not taken.
✓ Branch 26 taken 1 time.
✗ Branch 27 not taken.
✓ Branch 28 taken 1 time.
✗ Branch 29 not taken.
✓ Branch 30 taken 1 time.
✗ Branch 32 not taken.
✓ Branch 33 taken 1 time.
✗ Branch 35 not taken.
✓ Branch 36 taken 1 time.
1 bool operator==(const SplotchOptions&) const = default;
95 };
96
97 /// Checks splotch options.
98 /// @throws std::invalid_argument for a non-positive rate, slope or lifetime, diameters that are
99 /// not positive and increasing, shares outside [0, 1] or summing above 1, changes that can reach
100 /// -1 or are unbounded, a softness outside (0, 1], a raggedness outside [0, 1), a steep bright
101 /// share outside [0, 1], a steep slope outside (0, 90) degrees, an invalid fade, or swarms with
102 /// a non-positive rate, slope, count or range, crater diameters or ranges not increasing, a mu
103 /// outside (0, 1), invalid or unbounded distributions, shares outside [0, 1] or summing above 1,
104 /// or a wedge elongation below 1.
105 void ValidateSplotches(const SplotchOptions& options);
106
107 /// One splotch.
108 struct Splotch {
109 Crater mark; ///< Centre, diameter, age and ID, as a crater's.
110 double change = 0.0; ///< Reflectance change of its dark or only side.
111 double otherChange = 0.0; ///< Reflectance change of its other side; `change` unless mixed.
112 double split = 0.0; ///< Direction across which a mixed splotch changes side, radians.
113 std::uint32_t key = 0; ///< Key of its edge's lobes.
114 double elongation = 1.0; ///< Long over short axis; 1 for round.
115 double heading = 0.0; ///< Toward the crater that threw it, radians from east.
116 bool wedge = false; ///< Narrowing to a point toward the crater.
117 };
118
119 /// The splotches of `SplotchOptions` on `surface`, darkening and brightening the albedo; the
120 /// same in any grid, tile or point.
121 class SplotchAlbedo final : public AlbedoLayer {
122 public:
123 /// @throws std::invalid_argument for options invalid as `ValidateSplotches`.
124 explicit SplotchAlbedo(SplotchOptions options = {}, Surface surface = {});
125
126 /// Changes the albedo at one point by the splotches over it; NaN stays NaN.
127 void ApplyAt(AlbedoSample& value, std::size_t bands, double x, double y,
128 const AlbedoContext& context) const override;
129
130 /// `ApplyAt` at every cell centre, generating the splotches once.
131 void Apply(std::vector<Raster<float>>& bands, const AlbedoContext& context) const override;
132
133 /// The splotches resolved at `spacing` metres reaching `region`, youngest first; with
134 /// `ground`, those on steep slopes follow `steepBrightShare`.
135 std::vector<Splotch> Splotches(const Bounds2d& region, double spacing,
136 const Ground* ground = nullptr) const;
137
138 /// The splotches of the swarm `crater` throws, resolved at `spacing` metres (0 for all).
139 std::vector<Splotch> Swarm(const Crater& crater, double spacing) const;
140
141 /// The relative reflectance change `splotch` alone gives (`x`, `y`) at `spacing` metres.
142 double Change(const Splotch& splotch, double x, double y, double spacing) const;
143
144 /// The slope in degrees of `ground` at the centre of a splotch `diameter` metres across at
145 /// (`x`, `y`), over its width, read at `spacing` metres (half the smallest splotch for 0).
146 double SlopeDegrees(const Ground& ground, double x, double y, double diameter,
147 double spacing) const;
148
149 /// What the splotches are.
150 1 const SplotchOptions& Options() const {
151 1 return options_;
152 }
153
154 private:
155 /// Adds the splotches of the swarms reaching `region` to `splotches`.
156 void AddSwarms(const Bounds2d& region, double spacing, std::vector<Splotch>& splotches) const;
157 /// The change of `splotches`, youngest first, at (`x`, `y`).
158 double ChangeAt(const std::vector<const Splotch*>& splotches, double x, double y,
159 double spacing) const;
160
161 SplotchOptions options_;
162 Surface surface_;
163 std::shared_ptr<const SurfaceCells> cells_;
164 };
165
166 } // namespace terraingen
167