TerrainGen coverage


terraingen/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
16 / 16
100.0%
Branches:
8 / 12
66.7%
Functions:
6 / 6, 1 excl
100.0%

layers/craters/degradation/diffusion.h
Line Branch Exec Source
1 /// @file
2 /// @brief Crater degradation by topographic diffusion: `DiffusedProfile`, `DiffusionDegradation`.
3 #pragma once
4
5 #include "terraingen/layers/craters/degradation/degradation_model.h"
6 #include "terraingen/layers/craters/profiles/profile.h"
7 #include "terraingen/util/lru_cache.h"
8
9 #include <cstddef>
10 #include <functional>
11 #include <memory>
12 #include <vector>
13
14 namespace terraingen {
15
16 /// A crater's diffusion age kappa t in m^2 from its diameter (m) and age (Gyr), such as a
17 /// `PowerLawDiffusivity`; must be thread-safe.
18 using DiffusionAgeModel = std::function<double(double diameter, double ageGyr)>;
19
20 /// A diffusivity kappa = `coefficient` (D / 1 km)^`exponent` m^2/Myr, held at its value at
21 /// `minDiameter` below it; usable as a `DiffusionAgeModel`.
22 struct PowerLawDiffusivity {
23 5 double coefficient = 1.0; ///< kappa of a 1 km crater, in m^2/Myr; positive.
24 5 double exponent = 0.0; ///< Power of the diameter; 0 for a constant diffusivity.
25 5 double minDiameter = 0.0; ///< Diameter below which kappa is held (m); non-negative.
26
27 /// kappa in m^2/Myr of craters of `diameter` metres.
28 double Diffusivity(double diameter) const;
29 /// The diffusion age kappa t in m^2 of a crater of `diameter` metres and `ageGyr` Gyr.
30 double operator()(double diameter, double ageGyr) const;
31
32
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
5 bool operator==(const PowerLawDiffusivity&) const = default;
33 };
34
35 /// Checks a power-law diffusivity.
36 /// @throws std::invalid_argument for a coefficient that is not positive, or an exponent or minimum
37 /// diameter that is not finite, or a negative minimum diameter.
38 void ValidatePowerLawDiffusivity(const PowerLawDiffusivity& law);
39
40 /// A fresh crater profile worn by topographic diffusion, tabulated in the diffusion age
41 /// tau = kappa t / D^2 (`CraterState::diffusion`) from 1e-5 to 0.5.
42 ///
43 /// Heights are interpolated linearly in distance and log tau; craters older than the table keep
44 /// its last shape. Simple craters share one table per fresh morphometry, complex ones get one per
45 /// diameter, cached.
46 class DiffusedProfile final : public CraterProfile {
47 public:
48 /// @param reachRadii Radius of the solution domain, in crater radii; at least `fresh`'s reach.
49 /// @param cells Radial cells of the solver; at least 100.
50 /// @param cacheTables Most tables kept; positive.
51 /// @throws std::invalid_argument for a null `fresh`, `reachRadii` below the fresh profile's
52 /// reach, fewer than 100 cells, or no cache.
53 explicit DiffusedProfile(std::shared_ptr<const CraterProfile> fresh, double reachRadii = 3.0,
54 std::size_t cells = 600, std::size_t cacheTables = 64);
55
56 /// The fresh profile at diffusion age 0, the tabulated diffused shape after it; reads `fresh`
57 /// and `diffusion` of `state`.
58 double Height(double distance, double diameter, const CraterState& state) const override;
59
60 /// `reachRadii`.
61 4952462 double ReachRadii() const override {
62 4952462 return reachRadii_;
63 }
64
65 /// As the fresh profile says.
66 4399 bool IsComplex(double diameter) const override {
67 4399 return fresh_->IsComplex(diameter);
68 }
69
70 /// The morphometry of a crater of `diameter` metres diffused to age `tau` (kappa t / D^2): rim
71 /// crest height (highest point beyond half a radius) and depth below it (to the lowest point
72 /// within a radius), over the diameter.
73 CraterMorphometry Morphometry(const CraterMorphometry& fresh, double diameter,
74 double tau) const;
75
76 /// The diffusion ages tau tabulated, from 0, increasing.
77 const std::vector<double>& Ages() const;
78
79 /// The fresh profile.
80 103719 const CraterProfile& Fresh() const {
81 103719 return *fresh_;
82 }
83
84 /// Radial cells of the solver; each row of a table holds one more height.
85 103719 std::size_t Cells() const {
86 103719 return cells_;
87 }
88
89 /// The heights over the diameter a crater of `fresh` morphometry and `diameter` metres is read
90 /// from: a row per age of `Ages`, `Cells` + 1 heights per row out to half the reach in
91 /// diameters.
92 std::shared_ptr<const std::vector<float>> HeightTable(const CraterMorphometry& fresh,
93 double diameter) const;
94
95 private:
96 struct Key {
97 8775976 double depthRatio;
98 7690056 double rimHeightRatio;
99 7690056 double diameter;
100
5/6
✓ Branch 0 taken 1085920 times.
✓ Branch 1 taken 7690056 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7690056 times.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 7690055 times.
8775976 bool operator==(const Key&) const = default;
101 };
102 struct KeyHash {
103 std::size_t operator()(const Key& key) const;
104 };
105 struct Table {
106 std::vector<float> heights; ///< Row per age, `cells_ + 1` heights over D per row.
107 std::vector<CraterMorphometry> morphometry;
108 };
109
110 std::shared_ptr<const Table> TableFor(const CraterMorphometry& fresh, double diameter) const;
111 Table Solve(const CraterMorphometry& fresh, double diameter) const;
112
113 std::shared_ptr<const CraterProfile> fresh_;
114 double reachRadii_;
115 std::size_t cells_;
116 std::shared_ptr<LruCache<Key, Table, KeyHash>> tables_;
117 std::uint64_t instance_; ///< Unique to this profile, keying each thread's last table.
118 };
119
120 /// Craters worn by topographic diffusion; pair it with the crater layer's `DiffusedProfile`.
121 class DiffusionDegradation final : public DegradationModel {
122 public:
123 /// @param ages Each crater's diffusion age kappa t.
124 /// @param profile Gives the current morphometry; the layer's profile.
125 /// @throws std::invalid_argument for an empty `fresh` or `ages`, or a null `profile`.
126 DiffusionDegradation(FreshMorphometry fresh, DiffusionAgeModel ages,
127 std::shared_ptr<const DiffusedProfile> profile);
128
129 /// The crater's fresh morphometry, current morphometry from the profile, and diffusion age.
130 /// @throws std::domain_error for a diameter that is not positive and finite, a negative or
131 /// non-finite age, or a diffusion age that is negative or not finite.
132 CraterState State(const Crater& crater) const override;
133
134 /// The state with the diffusion age kappa t `rate` times larger, as diffusion `rate` times as
135 /// fast would give.
136 CraterState WornState(const Crater& crater, double rate) const override;
137
138 private:
139 FreshMorphometry fresh_;
140 DiffusionAgeModel ages_;
141 std::shared_ptr<const DiffusedProfile> profile_;
142 };
143
144 } // namespace terraingen
145