TerrainGen coverage


terraingen/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
18 / 18
100.0%
Branches:
6 / 6
100.0%
Functions:
9 / 9
100.0%

distribution/size_frequency.h
Line Branch Exec Source
1 /// @file
2 /// @brief The size-frequency distribution base class, its kinds and diameter ranges.
3 #pragma once
4
5 #include "terraingen/random/stream.h"
6
7 #include <limits>
8 #include <memory>
9 #include <vector>
10
11 namespace terraingen {
12
13 /// What a size-frequency distribution's values measure.
14 enum class SfdKind {
15 Density, ///< Cumulative count per m^2 (an equilibrium or present-day population).
16 ProductionRate, ///< Cumulative count per m^2 per Gyr (a production function).
17 };
18
19 /// Diameters in metres where a distribution is defined: (`min`, `max`], or with `min` = 0 all
20 /// positive diameters up to `max`.
21 struct DiameterRange {
22 double min = 0.0; ///< Lower bound in metres, >= 0.
23 double max = std::numeric_limits<double>::infinity(); ///< Upper bound in metres, > `min`.
24
25 /// Whether `diameter` (metres) is positive and within [`min`, `max`].
26 21616671 bool Contains(double diameter) const {
27
6/6
✓ Branch 0 taken 21616670 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 21616656 times.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 21616649 times.
✓ Branch 5 taken 7 times.
21616671 return diameter > 0.0 && diameter >= min && diameter <= max;
28 }
29 };
30
31 /// A cumulative size-frequency distribution N(>=D) of craters or boulders.
32 ///
33 /// Diameters are in metres and counts per m^2 (or per m^2 per Gyr; see `Kind`). Distributions
34 /// decrease monotonically. Evaluating outside `ValidRange` throws unless extrapolation is allowed.
35 class SizeFrequencyDistribution {
36 public:
37 104764 virtual ~SizeFrequencyDistribution() = default;
38
39 /// What the values measure.
40 376196 SfdKind Kind() const {
41 376196 return kind_;
42 }
43
44 /// The diameters in metres where the distribution may be evaluated without extrapolation.
45 4162 const DiameterRange& ValidRange() const {
46 4162 return range_;
47 }
48
49 /// Whether evaluation outside `ValidRange` is allowed.
50 2424 bool AllowsExtrapolation() const {
51 2424 return extrapolate_;
52 }
53
54 /// Permits or forbids evaluation at positive diameters outside `ValidRange`.
55 512 void SetAllowExtrapolation(bool allow) {
56 512 extrapolate_ = allow;
57 512 }
58
59 /// N(>=D), the count per m^2 (or per m^2 per Gyr) of features at least `diameter` metres
60 /// across.
61 /// @throws std::domain_error if `diameter` is not positive and finite, or is outside the valid
62 /// range without extrapolation.
63 double Cumulative(double diameter) const;
64
65 /// -dN/dD at `diameter` metres, per m^2 per metre (or per m^2 per Gyr per metre).
66 /// @throws std::domain_error under the same conditions as `Cumulative`.
67 double Incremental(double diameter) const;
68
69 /// Expected number of features with diameter in [`dMin`, `dMax`), area * (N(dMin) - N(dMax)).
70 /// @param area Area in m^2 (or m^2 Gyr for a production rate), finite and >= 0.
71 /// @param dMin Smallest diameter in metres.
72 /// @param dMax Largest diameter in metres; may be infinite.
73 /// @throws std::invalid_argument unless 0 < `dMin` < `dMax` and `area` >= 0 is finite.
74 /// @throws std::domain_error if a diameter is outside the valid range without extrapolation,
75 /// or `dMax` is infinite and the valid range is bounded.
76 double ExpectedCount(double area, double dMin, double dMax) const;
77
78 /// Draws a diameter in metres in [`dMin`, `dMax`) by inverting N(>=D); `dMax` may be infinite.
79 /// @throws std::invalid_argument unless 0 < `dMin` < `dMax`, or if N(dMin) = N(dMax).
80 /// @throws std::domain_error under the same conditions as `ExpectedCount`.
81 double SampleDiameter(RandomStream& random, double dMin, double dMax) const;
82
83 protected:
84 /// Sets the kind and valid range.
85 /// @throws std::invalid_argument unless 0 <= `range.min` < `range.max`.
86 SizeFrequencyDistribution(SfdKind kind, DiameterRange range);
87
88 /// N(>=D) at a positive `diameter` in metres, without range checks.
89 virtual double CumulativeAt(double diameter) const = 0;
90
91 /// -dN/dD without range checks; defaults to a central difference in log diameter.
92 virtual double IncrementalAt(double diameter) const;
93
94 /// Diameter D in metres in [`dMin`, `dMax`] with N(>=D) = `target`; defaults to bisection in
95 /// log diameter.
96 /// @param target Cumulative count with N(dMax) <= `target` <= N(dMin).
97 /// @param dMax Largest diameter in metres; may be infinite.
98 virtual double InvertCumulative(double target, double dMin, double dMax) const;
99
100 /// Unchecked `CumulativeAt` of another distribution, for distributions built from others.
101 43572433 static double CumulativeOf(const SizeFrequencyDistribution& distribution, double diameter) {
102 43572433 return distribution.CumulativeAt(diameter);
103 }
104
105 /// Unchecked `IncrementalAt` of another distribution.
106 2428657 static double IncrementalOf(const SizeFrequencyDistribution& distribution, double diameter) {
107 2428657 return distribution.IncrementalAt(diameter);
108 }
109
110 /// Unchecked `InvertCumulative` of another distribution.
111 165453 static double InvertCumulativeOf(const SizeFrequencyDistribution& distribution, double target,
112 double dMin, double dMax) {
113 165453 return distribution.InvertCumulative(target, dMin, dMax);
114 }
115
116 private:
117 void CheckDiameter(double diameter) const;
118
119 SfdKind kind_;
120 DiameterRange range_;
121 bool extrapolate_ = false;
122 };
123
124 } // namespace terraingen
125