Skip to content

Commit 59c6407

Browse files
authored
Merge pull request #441 from pdziekan/user_defined_rd_min_max
option to set rd bin edges in opts_init
2 parents 8e98d21 + 3de4959 commit 59c6407

File tree

2 files changed

+76
-55
lines changed

2 files changed

+76
-55
lines changed

include/libcloudph++/lgrngn/opts_init.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ namespace libcloudphxx
126126
// SGS mixing length profile [m]
127127
std::vector<real_t> SGS_mix_len;
128128

129-
real_t rd_min; // minimal dry radius of droplets (works only for init from spectrum)
129+
real_t rd_min, rd_max; // min/max dry radius of droplets [m]
130130

131131
bool no_ccn_at_init; // if true, no ccn / SD are put at the start of the simulation
132132

@@ -230,7 +230,8 @@ namespace libcloudphxx
230230
rlx_timescale(1),
231231
rlx_sd_per_bin(0),
232232
supstp_rlx(1),
233-
rd_min(0.),
233+
rd_min(-1), // negative means that rd_min will be automatically detected
234+
rd_max(-1),
234235
diag_incloud_time(false),
235236
no_ccn_at_init(false),
236237
open_side_walls(false),

src/impl/particles_impl_dist_analysis.ipp

Lines changed: 73 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,10 @@ namespace libcloudphxx
2020
const real_t dt
2121
)
2222
{
23-
// probing the spectrum to find rd_min-rd_max range
24-
// when analysing distro for source, multiplier takes into account that
25-
// the distribution is assumed to represent number of particles created per unit of time!
26-
// TODO: document that
27-
28-
// values to start the search
29-
real_t rd_min = config.rd_min_init, rd_max = config.rd_max_init;
30-
31-
bool found_optimal_range = false;
32-
while (!found_optimal_range)
23+
if(opts_init.rd_min >= 0 && opts_init.rd_max >= 0) // user-defined bin edges
3324
{
25+
real_t rd_min = opts_init.rd_min, rd_max = opts_init.rd_max;
26+
3427
multiplier = log(rd_max / rd_min)
3528
/ sd_conc
3629
* dt
@@ -41,62 +34,89 @@ namespace libcloudphxx
4134

4235
log_rd_min = log(rd_min);
4336
log_rd_max = log(rd_max);
37+
}
38+
else if (opts_init.rd_min < 0 && opts_init.rd_max < 0) // automatic detection of bin edges
39+
{
40+
// probing the spectrum to find rd_min-rd_max range
41+
// when analysing distro for source, multiplier takes into account that
42+
// the distribution is assumed to represent number of particles created per unit of time!
43+
// TODO: document that
44+
45+
// values to start the search
46+
real_t rd_min = config.rd_min_init, rd_max = config.rd_max_init;
47+
48+
bool found_optimal_range = false;
49+
while (!found_optimal_range)
50+
{
51+
multiplier = log(rd_max / rd_min)
52+
/ sd_conc
53+
* dt
54+
* (n_dims == 0
55+
? dv[0]
56+
: (opts_init.dx * opts_init.dy * opts_init.dz)
57+
);
4458

45-
impl::n_t
46-
n_min = n_of_lnrd_stp(log_rd_min) * multiplier,
47-
n_max = n_of_lnrd_stp(log_rd_max) * multiplier;
59+
log_rd_min = log(rd_min);
60+
log_rd_max = log(rd_max);
4861

49-
if (rd_min == config.rd_min_init && n_min != 0)
50-
throw std::runtime_error(detail::formatter() << "Initial dry radii distribution is non-zero (" << n_min << ") for rd_min_init (" << config.rd_min_init <<")");
51-
if (rd_max == config.rd_max_init && n_max != 0)
52-
throw std::runtime_error(detail::formatter() << "Initial dry radii distribution is non-zero (" << n_max << ") for rd_max_init (" << config.rd_max_init <<")");
62+
impl::n_t
63+
n_min = n_of_lnrd_stp(log_rd_min) * multiplier,
64+
n_max = n_of_lnrd_stp(log_rd_max) * multiplier;
5365

54-
if (n_min == 0) rd_min *= 1.01;
55-
else if (n_max == 0) rd_max /= 1.01;
56-
else found_optimal_range = true;
66+
if (rd_min == config.rd_min_init && n_min != 0)
67+
throw std::runtime_error(detail::formatter() << "Initial dry radii distribution is non-zero (" << n_min << ") for rd_min_init (" << config.rd_min_init <<")");
68+
if (rd_max == config.rd_max_init && n_max != 0)
69+
throw std::runtime_error(detail::formatter() << "Initial dry radii distribution is non-zero (" << n_max << ") for rd_max_init (" << config.rd_max_init <<")");
70+
71+
if (n_min == 0) rd_min *= 1.01;
72+
else if (n_max == 0) rd_max /= 1.01;
73+
else found_optimal_range = true;
74+
}
5775
}
58-
#if !defined(__NVCC__)
59-
using std::max;
60-
#endif
61-
log_rd_min = max(log_rd_min, real_t(log(opts_init.rd_min))); // user-defined lower limit for rd
76+
else assert(false && "opts_init.rd_min * opts_init.rd_max < 0");
6277
};
6378

6479
template <typename real_t, backend_t device>
6580
void particles_t<real_t, device>::impl::dist_analysis_const_multi(
6681
const common::unary_function<real_t> &n_of_lnrd_stp
6782
)
6883
{
69-
// TODO: add same sanity check as above
70-
// how does brent algorithm work for functions with multiple minima??
71-
std::pair<real_t, real_t> init_distr_max; // [ln(position of distribution's maximum), -function value at maximum]
72-
boost::uintmax_t n_iter = config.n_iter;
73-
init_distr_max = boost::math::tools::brent_find_minima(detail::eval_and_mul<real_t>(n_of_lnrd_stp, -1), log(config.rd_min_init), log(config.rd_max_init), 200, n_iter); // bits = 200 to make algorithm choose max precision available
84+
if(opts_init.rd_min >= 0 && opts_init.rd_max >= 0) // user-defined bin edges
85+
{
86+
log_rd_min = log(opts_init.rd_min);
87+
log_rd_max = log(opts_init.rd_max);
88+
}
89+
else if (opts_init.rd_min < 0 && opts_init.rd_max < 0) // automatic detection of bin edges
90+
{
91+
// TODO: add same sanity check as above
92+
// how does brent algorithm work for functions with multiple minima??
93+
std::pair<real_t, real_t> init_distr_max; // [ln(position of distribution's maximum), -function value at maximum]
94+
boost::uintmax_t n_iter = config.n_iter;
95+
init_distr_max = boost::math::tools::brent_find_minima(detail::eval_and_mul<real_t>(n_of_lnrd_stp, -1), log(config.rd_min_init), log(config.rd_max_init), 200, n_iter); // bits = 200 to make algorithm choose max precision available
7496

75-
real_t init_dist_bound_value = -init_distr_max.second / config.threshold; // value of the distribution at which we bind it
76-
n_iter = config.n_iter;
77-
// TODO: it could be written more clearly by creating an object detail::eval_and_oper<real_t>(*n_of_lnrd_stp, -init_dist_bound_value, 1), but for some reason it doesnt give the correct values
78-
log_rd_min =
79-
common::detail::toms748_solve(
80-
detail::eval_and_add<real_t>(n_of_lnrd_stp, -init_dist_bound_value),
81-
real_t(log(config.rd_min_init)), init_distr_max.first,
82-
detail::eval_and_add<real_t>(n_of_lnrd_stp, -init_dist_bound_value)(real_t(log(config.rd_min_init))),
83-
detail::eval_and_add<real_t>(n_of_lnrd_stp, -init_dist_bound_value)(init_distr_max.first),
84-
config.eps_tolerance, n_iter
85-
);
97+
real_t init_dist_bound_value = -init_distr_max.second / config.threshold; // value of the distribution at which we bind it
98+
n_iter = config.n_iter;
99+
// TODO: it could be written more clearly by creating an object detail::eval_and_oper<real_t>(*n_of_lnrd_stp, -init_dist_bound_value, 1), but for some reason it doesnt give the correct values
100+
log_rd_min =
101+
common::detail::toms748_solve(
102+
detail::eval_and_add<real_t>(n_of_lnrd_stp, -init_dist_bound_value),
103+
real_t(log(config.rd_min_init)), init_distr_max.first,
104+
detail::eval_and_add<real_t>(n_of_lnrd_stp, -init_dist_bound_value)(real_t(log(config.rd_min_init))),
105+
detail::eval_and_add<real_t>(n_of_lnrd_stp, -init_dist_bound_value)(init_distr_max.first),
106+
config.eps_tolerance, n_iter
107+
);
86108

87-
n_iter = config.n_iter;
88-
log_rd_max =
89-
common::detail::toms748_solve(
90-
detail::eval_and_add<real_t>(n_of_lnrd_stp, -init_dist_bound_value),
91-
init_distr_max.first, real_t(log(config.rd_max_init)),
92-
detail::eval_and_add<real_t>(n_of_lnrd_stp, -init_dist_bound_value)(init_distr_max.first),
93-
detail::eval_and_add<real_t>(n_of_lnrd_stp, -init_dist_bound_value)(real_t(log(config.rd_max_init))),
94-
config.eps_tolerance, n_iter
95-
);
96-
#if !defined(__NVCC__)
97-
using std::max;
98-
#endif
99-
log_rd_min = max(log_rd_min, real_t(log(opts_init.rd_min))); // user-defined lower limit for rd
109+
n_iter = config.n_iter;
110+
log_rd_max =
111+
common::detail::toms748_solve(
112+
detail::eval_and_add<real_t>(n_of_lnrd_stp, -init_dist_bound_value),
113+
init_distr_max.first, real_t(log(config.rd_max_init)),
114+
detail::eval_and_add<real_t>(n_of_lnrd_stp, -init_dist_bound_value)(init_distr_max.first),
115+
detail::eval_and_add<real_t>(n_of_lnrd_stp, -init_dist_bound_value)(real_t(log(config.rd_max_init))),
116+
config.eps_tolerance, n_iter
117+
);
118+
}
119+
else assert(false && "opts_init.rd_min * opts_init.rd_max < 0");
100120
}
101121
};
102122
};

0 commit comments

Comments
 (0)