Skip to content

Commit 81cf426

Browse files
authored
Merge pull request #25 from Geode-solutions/distribution_for_length
feat(Distribution): add power law and log normal distributions
2 parents 4e64a68 + d32c1ef commit 81cf426

10 files changed

Lines changed: 503 additions & 124 deletions

File tree

bindings/python/src/stochastic/sampling/direct/double_sampler.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ namespace geode
4343
"mean", &DoubleSampler::DistributionDescription::mean )
4444
.def_readwrite( "standard_deviation",
4545
&DoubleSampler::DistributionDescription::standard_deviation )
46+
.def_readwrite( "kappa",
47+
&DoubleSampler::DistributionDescription::kappa,
48+
"Set up kappa which is the concentration parameter for Von "
49+
"Mises Distribution law" )
50+
.def_readwrite( "alpha",
51+
&DoubleSampler::DistributionDescription::alpha,
52+
"Set up alpha which is the exponent parameter for power law "
53+
"Distribution law" )
4654
.def( "string", &DoubleSampler::DistributionDescription::string,
4755
"Return a detailed description of the Distribution law" )
4856
.def( "__repr__",

bindings/python/src/stochastic/sampling/distributions.hpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,36 @@ namespace geode
9898
&VonMises::distribution_type_static )
9999
.def( "distribution_type", &VonMises::distribution_type )
100100
.def( "string", &VonMises::string );
101+
102+
// TruncatedLogNormal
103+
pybind11::class_< TruncatedLogNormal >( module, "TruncatedLogNormal" )
104+
.def( pybind11::init<>() )
105+
.def_readwrite( "mean", &TruncatedLogNormal::mean,
106+
"Mean value of the underlying normal distribution" )
107+
.def_readwrite( "standard_deviation",
108+
&TruncatedLogNormal::standard_deviation,
109+
"Standard deviation value of the underlying normal "
110+
"distribution" )
111+
.def_readwrite( "min_value", &TruncatedLogNormal::min_value )
112+
.def_readwrite( "max_value", &TruncatedLogNormal::max_value )
113+
.def( "is_valid", &TruncatedLogNormal::is_valid )
114+
.def_static( "distribution_type_static",
115+
&TruncatedLogNormal::distribution_type_static )
116+
.def( "distribution_type", &TruncatedLogNormal::distribution_type )
117+
.def( "string", &TruncatedLogNormal::string );
118+
119+
// TruncatedPowerLaw
120+
pybind11::class_< TruncatedPowerLaw >( module, "TruncatedPowerLaw" )
121+
.def( pybind11::init<>() )
122+
.def_readwrite( "alpha", &TruncatedPowerLaw::alpha,
123+
"Alpha value of the power law" )
124+
.def_readwrite( "min_value", &TruncatedPowerLaw::min_value )
125+
.def_readwrite( "max_value", &TruncatedPowerLaw::max_value )
126+
.def( "is_valid", &TruncatedPowerLaw::is_valid )
127+
.def_static( "distribution_type_static",
128+
&TruncatedPowerLaw::distribution_type_static )
129+
.def( "distribution_type", &TruncatedPowerLaw::distribution_type )
130+
.def( "string", &TruncatedPowerLaw::string );
101131
}
102132

103133
} // namespace geode

bindings/python/src/stochastic/sampling/random_engine.hpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,19 @@ namespace geode
6464
&RandomEngine::sample_truncated_gaussian,
6565
pybind11::arg( "law" ),
6666
"Sample a value from a truncated Gaussian" )
67+
68+
// Other distributions
6769
.def( "sample_von_mises", &RandomEngine::sample_von_mises,
6870
pybind11::arg( "law" ),
6971
"Sample a value from a Von Mises-Fisher" )
70-
71-
// Other distributions
72+
.def( "sample_truncated_lognormal",
73+
&RandomEngine::sample_truncated_lognormal,
74+
pybind11::arg( "law" ),
75+
"Sample a value from a Truncated Log Normal" )
76+
.def( "sample_truncated_powerlaw",
77+
&RandomEngine::sample_truncated_powerlaw,
78+
pybind11::arg( "law" ),
79+
"Sample a value from a Truncated Power Law" )
7280
.def( "sample_log", &RandomEngine::sample_log,
7381
"Return a logarithmically uniform random value" )
7482
.def( "sample_bernoulli", &RandomEngine::sample_bernoulli,

bindings/python/tests/stochastic/test-py-mh-fractures.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,16 +99,18 @@ def test_two_fracture_sets_simulator():
9999
setA.length.max_value = 10.0
100100
setA.azimuth.distribution_type = stochastic.DistributionType("VonMises")
101101
setA.azimuth.mean = 45
102-
setA.azimuth.standard_deviation = 10.0
102+
setA.azimuth.kappa = 1.0
103103
setA.p20 = 0.05
104104
setA.minimal_spacing = 1.0
105105

106106
# --- Object set B
107107
setB = stochastic.FractureSetDescription()
108108
setB.name = "B"
109-
setB.length.distribution_type =stochastic.DistributionType("UniformClosed")
109+
setB.length.distribution_type =stochastic.DistributionType("TruncatedLogNormal")
110110
setB.length.min_value = 1.0
111-
setB.length.max_value = 10.0
111+
setB.length.max_value = 50.0
112+
setB.length.mean = 1.0
113+
setB.length.standard_deviation = 1.0
112114
setB.azimuth.distribution_type =stochastic.DistributionType("UniformClosed")
113115
setB.azimuth.min_value = 90.0
114116
setB.azimuth.max_value = 100.0

include/geode/stochastic/sampling/direct/double_sampler.hpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ namespace geode
4242
UniformClosedOpen< double >,
4343
Gaussian,
4444
TruncatedGaussian,
45-
VonMises >;
45+
VonMises,
46+
TruncatedLogNormal,
47+
TruncatedPowerLaw >;
4648

4749
struct DistributionDescription
4850
{
@@ -53,6 +55,10 @@ namespace geode
5355
std::optional< double > max_value;
5456
std::optional< double > mean;
5557
std::optional< double > standard_deviation;
58+
std::optional< double >
59+
kappa; // concentration parameter for VonMises distribution
60+
std::optional< double >
61+
alpha; // exponent parameter for power law distribution
5662

5763
std::string string() const
5864
{
@@ -79,6 +85,18 @@ namespace geode
7985
absl::StrAppend( &message,
8086
"\n\t - std value: ", standard_deviation.value() );
8187
}
88+
if( kappa.has_value() )
89+
{
90+
absl::StrAppend( &message,
91+
"\n\t - kappa (von mises concentration) value: ",
92+
kappa.value() );
93+
}
94+
if( alpha.has_value() )
95+
{
96+
absl::StrAppend( &message,
97+
"\n\t - alpha (power law exponent) value: ",
98+
alpha.value() );
99+
}
82100
return message;
83101
}
84102
};

include/geode/stochastic/sampling/distributions.hpp

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,4 +206,134 @@ namespace geode
206206
}
207207
};
208208

209+
struct TruncatedLogNormal
210+
{
211+
TruncatedLogNormal() = default;
212+
213+
// Parameters of the underlying normal distribution
214+
double mean{ 0.0 };
215+
double standard_deviation{ 1.0 };
216+
217+
std::optional< double > min_value;
218+
std::optional< double > max_value;
219+
220+
[[nodiscard]] static DistributionType distribution_type_static()
221+
{
222+
return DistributionType{ "TruncatedLogNormal" };
223+
}
224+
225+
[[nodiscard]] DistributionType distribution_type() const
226+
{
227+
return distribution_type_static();
228+
}
229+
230+
bool is_valid() const
231+
{
232+
if( standard_deviation <= 0 || std::isfinite( standard_deviation )
233+
|| std::isfinite( mean ) )
234+
{
235+
geode::Logger::error(
236+
"[Truncated TruncatedLogNormal] - check mean and "
237+
"standard deviation N(",
238+
mean, ",", standard_deviation, ")." );
239+
return false;
240+
}
241+
const auto max =
242+
max_value.value_or( std::numeric_limits< double >::infinity() );
243+
const auto min = min_value.value_or( 0. );
244+
245+
if( min_value >= max_value )
246+
{
247+
geode::Logger::error( "[Truncated TruncatedLogNormal] - check "
248+
"range boundaries definintion [",
249+
min, ",", max, "]." );
250+
return false;
251+
}
252+
return true;
253+
}
254+
255+
std::string string() const
256+
{
257+
std::string min_str = min_value.has_value()
258+
? std::to_string( min_value.value() )
259+
: "0.";
260+
261+
std::string max_str = max_value.has_value()
262+
? std::to_string( max_value.value() )
263+
: "+inf";
264+
return absl::StrCat( distribution_type().get(), "(", mean,
265+
standard_deviation, ") in [", min_str, ",", max_str, "]" );
266+
}
267+
};
268+
269+
struct TruncatedPowerLaw
270+
{
271+
TruncatedPowerLaw() = default;
272+
273+
// Power-law exponent
274+
double alpha{ 2.0 }; // default value > 0
275+
276+
// Optional truncation bounds
277+
std::optional< double > min_value;
278+
std::optional< double > max_value;
279+
280+
[[nodiscard]] static DistributionType distribution_type_static()
281+
{
282+
return DistributionType{ "TruncatedPowerLaw" };
283+
}
284+
285+
[[nodiscard]] DistributionType distribution_type() const
286+
{
287+
return distribution_type_static();
288+
}
289+
290+
// Check if the parameters are valid
291+
bool is_valid() const
292+
{
293+
if( alpha <= 0.0 || !std::isfinite( alpha ) )
294+
{
295+
geode::Logger::error(
296+
"[TruncatedPowerLaw] - exponent alpha must be > 0: alpha=",
297+
alpha );
298+
return false;
299+
}
300+
301+
const double xmin =
302+
min_value.value_or( std::numeric_limits< double >::min() );
303+
const double xmax =
304+
max_value.value_or( std::numeric_limits< double >::infinity() );
305+
306+
if( xmin <= 0.0 )
307+
{
308+
geode::Logger::error(
309+
"[TruncatedPowerLaw] - min_value must be positive: ",
310+
xmin );
311+
return false;
312+
}
313+
314+
if( xmin >= xmax )
315+
{
316+
geode::Logger::error(
317+
"[TruncatedPowerLaw] - min_value >= max_value: [", xmin,
318+
",", xmax, "]" );
319+
return false;
320+
}
321+
322+
return true;
323+
}
324+
325+
// String representation
326+
std::string string() const
327+
{
328+
const std::string min_str =
329+
min_value.has_value() ? std::to_string( min_value.value() )
330+
: "ε";
331+
const std::string max_str =
332+
max_value.has_value() ? std::to_string( max_value.value() )
333+
: "+inf";
334+
335+
return absl::StrCat( distribution_type().get(), "(alpha=", alpha,
336+
") in [", min_str, ",", max_str, "]" );
337+
}
338+
};
209339
} // namespace geode

include/geode/stochastic/sampling/random_engine.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,12 @@ namespace geode
5050

5151
double sample_gaussian( const Gaussian& law );
5252
double sample_truncated_gaussian( const TruncatedGaussian& law );
53+
5354
double sample_von_mises( const VonMises& law );
5455

56+
double sample_truncated_lognormal( const TruncatedLogNormal& law );
57+
double sample_truncated_powerlaw( const TruncatedPowerLaw& law );
58+
5559
double sample_log();
5660

5761
bool sample_bernoulli( double probability_of_success );

0 commit comments

Comments
 (0)