File indexing completed on 2026-06-23 08:35:27
0001
0002 #ifndef RIVET_Utils_HH
0003 #define RIVET_Utils_HH
0004
0005 #include "Rivet/Tools/RivetSTL.hh"
0006 #include "Rivet/Tools/TypeTraits.hh"
0007 #include "Rivet/Tools/PrettyPrint.hh"
0008 #include "Rivet/Tools/Exceptions.hh"
0009 #include <ostream>
0010 #include <cctype>
0011 #include <cerrno>
0012 #include <stdexcept>
0013 #include <numeric>
0014 #include <limits>
0015 #include <climits>
0016 #include <cfloat>
0017 #include <cmath>
0018 #include <sstream>
0019 #include <functional>
0020
0021
0022
0023
0024
0025 #ifndef DEPRECATED
0026 #if __GNUC__ && __cplusplus && RIVET_NO_DEPRECATION_WARNINGS == 0
0027 #define DEPRECATED(x) __attribute__((deprecated(x)))
0028 #else
0029 #define DEPRECATED(x)
0030 #endif
0031 #endif
0032
0033
0034 namespace Rivet {
0035
0036
0037
0038 static constexpr double DBL_NAN = std::numeric_limits<double>::quiet_NaN();
0039
0040
0041
0042
0043
0044
0045 struct bad_lexical_cast : public std::runtime_error {
0046 bad_lexical_cast(const std::string& what) : std::runtime_error(what) {}
0047 };
0048
0049
0050 template<typename T, typename U>
0051 T lexical_cast(const U& in) {
0052 try {
0053 std::stringstream ss;
0054 ss << in;
0055 T out;
0056 ss >> out;
0057 return out;
0058 } catch (const std::exception& e) {
0059 throw bad_lexical_cast(e.what());
0060 }
0061 }
0062
0063
0064
0065
0066 template <typename T>
0067 inline string to_str(const T& x) {
0068 return lexical_cast<string>(x);
0069 }
0070
0071
0072
0073
0074 template <typename T>
0075 inline string toString(const T& x) {
0076 return lexical_cast<string>(x);
0077 }
0078
0079
0080 inline string& replace_first(string& str, const string& patt, const string& repl) {
0081 if (!contains(str, patt)) return str;
0082 str.replace(str.find(patt), patt.size(), repl);
0083 return str;
0084 }
0085
0086
0087
0088
0089
0090
0091 inline string& replace_all(string& str, const string& patt, const string& repl) {
0092 if (!contains(str, patt)) return str;
0093 while (true) {
0094 string::size_type it = str.find(patt);
0095 if (it == string::npos) break;
0096 str.replace(it, patt.size(), repl);
0097 }
0098 return str;
0099 }
0100
0101
0102
0103 inline int nocase_cmp(const string& s1, const string& s2) {
0104 string::const_iterator it1 = s1.begin();
0105 string::const_iterator it2 = s2.begin();
0106 while ( (it1 != s1.end()) && (it2 != s2.end()) ) {
0107 if(::toupper(*it1) != ::toupper(*it2)) {
0108
0109 return (::toupper(*it1) < ::toupper(*it2)) ? -1 : 1;
0110 }
0111
0112 ++it1;
0113 ++it2;
0114 }
0115 size_t size1 = s1.size(), size2 = s2.size();
0116
0117 if (size1 == size2) return 0;
0118 return (size1 < size2) ? -1 : 1;
0119 }
0120
0121
0122
0123 inline bool nocase_equals(const string& s1, const string& s2) {
0124 return nocase_cmp(s1, s2) == 0;
0125 }
0126
0127
0128
0129 inline string toLower(const string& s) {
0130 string out = s;
0131 std::transform(out.begin(), out.end(), out.begin(), (int(*)(int)) std::tolower);
0132 return out;
0133 }
0134
0135
0136
0137 inline string toUpper(const string& s) {
0138 string out = s;
0139 std::transform(out.begin(), out.end(), out.begin(), (int(*)(int)) std::toupper);
0140 return out;
0141 }
0142
0143
0144
0145 inline bool startsWith(const string& s, const string& start) {
0146 if (s.length() < start.length()) return false;
0147 return s.substr(0, start.length()) == start;
0148 }
0149
0150
0151
0152 inline bool endsWith(const string& s, const string& end) {
0153 if (s.length() < end.length()) return false;
0154 return s.substr(s.length() - end.length()) == end;
0155 }
0156
0157
0158
0159 inline string strcat() { return ""; }
0160
0161 template<typename T, typename... Ts>
0162 inline string strcat(T value, Ts... fargs) {
0163 const string strthis = lexical_cast<string>(value);
0164 const string strnext = strcat(fargs...);
0165 return strnext.empty() ? strthis : strthis + strnext;
0166 }
0167
0168
0169
0170 template <typename T>
0171 inline string join(const vector<T>& v, const string& sep=" ") {
0172 string rtn;
0173 for (size_t i = 0; i < v.size(); ++i) {
0174 if (i != 0) rtn += sep;
0175 rtn += to_str(v[i]);
0176 }
0177 return rtn;
0178 }
0179
0180
0181 template <>
0182 inline string join(const vector<string>& v, const string& sep) {
0183 string rtn;
0184 for (size_t i = 0; i < v.size(); ++i) {
0185 if (i != 0) rtn += sep;
0186 rtn += v[i];
0187 }
0188 return rtn;
0189 }
0190
0191
0192 template <typename T>
0193 inline string join(const set<T>& s, const string& sep=" ") {
0194 string rtn;
0195 for (const T& x : s) {
0196 if (rtn.size() > 0) rtn += sep;
0197 rtn += to_str(x);
0198 }
0199 return rtn;
0200 }
0201
0202
0203 template <>
0204 inline string join(const set<string>& s, const string& sep) {
0205 string rtn;
0206 for (const string & x : s) {
0207 if (rtn.size() > 0) rtn += sep;
0208 rtn += x;
0209 }
0210 return rtn;
0211 }
0212
0213
0214 inline vector<string> split(const string& s, const string& sep) {
0215 vector<string> dirs;
0216 string tmp = s;
0217 while (true) {
0218 const size_t delim_pos = tmp.find(sep);
0219 if (delim_pos == string::npos) break;
0220 const string dir = tmp.substr(0, delim_pos);
0221 if (dir.length()) dirs.push_back(dir);
0222 tmp.replace(0, delim_pos+1, "");
0223 }
0224 if (tmp.length()) dirs.push_back(tmp);
0225 return dirs;
0226 }
0227
0228
0229 inline string lpad(const string& s, size_t width, const string& padchar=" ") {
0230 if (s.size() >= width) return s;
0231 return string(width - s.size(), padchar[0]) + s;
0232 }
0233
0234
0235 inline string rpad(const string& s, size_t width, const string& padchar=" ") {
0236 if (s.size() >= width) return s;
0237 return s + string(width - s.size(), padchar[0]);
0238 }
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250 inline vector<string> pathsplit(const string& path) {
0251 return split(path, ":");
0252 }
0253
0254
0255
0256
0257
0258 inline string pathjoin(const vector<string>& paths) {
0259 return join(paths, ":");
0260 }
0261
0262
0263 inline string operator / (const string& a, const string& b) {
0264
0265 const string anorm = (a.find("/") != string::npos) ? a.substr(0, a.find_last_not_of("/")+1) : a;
0266 const string bnorm = (b.find("/") != string::npos) ? b.substr(b.find_first_not_of("/")) : b;
0267 return anorm + "/" + bnorm;
0268 }
0269
0270
0271 inline string basename(const string& p) {
0272 if (!contains(p, "/")) return p;
0273 return p.substr(p.rfind("/")+1);
0274 }
0275
0276
0277 inline string dirname(const string& p) {
0278 if (!contains(p, "/")) return "";
0279 return p.substr(0, p.rfind("/"));
0280 }
0281
0282
0283 inline string file_stem(const string& f) {
0284 if (!contains(f, ".")) return f;
0285 return f.substr(0, f.rfind("."));
0286 }
0287
0288
0289 inline string file_extn(const string& f) {
0290 if (!contains(f, ".")) return "";
0291 return f.substr(f.rfind(".")+1);
0292 }
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302 template <typename CONTAINER,
0303 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0304 inline unsigned int count(const CONTAINER& c) {
0305
0306 unsigned int rtn = 0;
0307 for (const auto& x : c) if (bool(x)) rtn += 1;
0308 return rtn;
0309 }
0310
0311
0312
0313
0314
0315
0316
0317
0318 template <typename CONTAINER, typename FN,
0319
0320 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0321 inline unsigned int count(const CONTAINER& c, const FN& f) {
0322 return std::count_if(std::begin(c), std::end(c), f);
0323 }
0324
0325
0326
0327
0328 template <typename CONTAINER,
0329 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0330 inline bool any(const CONTAINER& c) {
0331
0332 for (const auto& x : c) if (bool(x)) return true;
0333 return false;
0334 }
0335
0336
0337
0338
0339
0340
0341
0342
0343 template <typename CONTAINER, typename FN,
0344
0345 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0346 inline bool any(const CONTAINER& c, const FN& f) {
0347 return std::any_of(std::begin(c), std::end(c), f);
0348 }
0349
0350
0351
0352
0353 template <typename CONTAINER,
0354 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0355 inline bool all(const CONTAINER& c) {
0356
0357 for (const auto& x : c) if (!bool(x)) return false;
0358 return true;
0359 }
0360
0361
0362
0363
0364
0365
0366
0367
0368 template <typename CONTAINER, typename FN,
0369
0370 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0371 inline bool all(const CONTAINER& c, const FN& f) {
0372 return std::all_of(std::begin(c), std::end(c), f);
0373 }
0374
0375
0376
0377 template <typename CONTAINER,
0378 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0379 inline bool none(const CONTAINER& c) {
0380
0381 for (const auto& x : c) if (bool(x)) return false;
0382 return true;
0383 }
0384
0385
0386
0387
0388
0389
0390
0391
0392 template <typename CONTAINER, typename FN,
0393
0394 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0395 inline bool none(const CONTAINER& c, const FN& f) {
0396 return std::none_of(std::begin(c), std::end(c), f);
0397 }
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410 template <typename CONTAINER1, typename CONTAINER2,
0411 typename FN = typename std::decay_t<CONTAINER2>::value_type(
0412 const typename std::decay_t<CONTAINER1>::value_type::ParticleBase&),
0413 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER1>> &&
0414 is_citerable_v<std::decay_t<CONTAINER2>> >>
0415 inline const CONTAINER2& transform(const CONTAINER1& in, CONTAINER2& out, FN&& f) {
0416 out.clear(); out.resize(in.size());
0417 std::transform(in.begin(), in.end(), out.begin(), std::forward<FN>(f));
0418 return out;
0419 }
0420
0421
0422
0423
0424 template <typename CONTAINER1, typename RTN,
0425 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER1>> >>
0426 inline std::vector<RTN> transform(const CONTAINER1& in,
0427 const std::function<RTN(typename CONTAINER1::value_type::ParticleBase)>& f) {
0428 std::vector<RTN> out;
0429 transform(in, out, f);
0430 return out;
0431 }
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441 template <typename CONTAINER1, typename T, typename FN,
0442 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER1>> >>
0443 inline T accumulate(const CONTAINER1& in, const T& init, const FN& f) {
0444 const T rtn = std::accumulate(in.begin(), in.end(), init, f);
0445 return rtn;
0446 }
0447
0448
0449
0450
0451
0452 template <typename CONTAINER,
0453 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0454 inline typename CONTAINER::value_type sum(const CONTAINER& c) {
0455 typename CONTAINER::value_type rtn;
0456 for (const auto& x : c) rtn += x;
0457 return rtn;
0458 }
0459
0460
0461
0462
0463 template <typename CONTAINER, typename T,
0464 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0465 inline T sum(const CONTAINER& c, const T& start) {
0466 T rtn = start;
0467 for (const auto& x : c) rtn += x;
0468 return rtn;
0469 }
0470
0471
0472 template <typename CONTAINER, typename T,
0473 typename FN = T(const typename std::decay_t<CONTAINER>::value_type::ParticleBase&),
0474 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0475 inline T sum(const CONTAINER& c, FN&& fn, const T& start=T()) {
0476 auto f = std::function(std::forward<FN>(fn));
0477 T rtn = start;
0478 for (const auto& x : c) rtn += fn(x);
0479 return rtn;
0480 }
0481
0482
0483
0484
0485
0486 template <typename CONTAINER, typename T,
0487 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0488 inline T& isum(const CONTAINER& c, T& out) {
0489 for (const auto& x : c) out += x;
0490 return out;
0491 }
0492
0493
0494
0495
0496 template <typename CONTAINER, typename FN, typename T,
0497
0498 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0499 inline T& isum(const CONTAINER& c, const FN& f, T& out) {
0500 for (const auto& x : c) out += f(x);
0501 return out;
0502 }
0503
0504
0505
0506
0507
0508
0509 template <typename CONTAINER, typename FN,
0510 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0511 inline CONTAINER& idiscard(CONTAINER& c, const FN& f) {
0512 const auto newend = std::remove_if(std::begin(c), std::end(c), f);
0513 c.erase(newend, c.end());
0514 return c;
0515 }
0516
0517
0518 template <typename CONTAINER,
0519 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0520 inline CONTAINER& idiscard(CONTAINER& c, const typename CONTAINER::value_type& y) {
0521 return idiscard(c, [&](typename CONTAINER::value_type& x){ return x == y; });
0522 }
0523
0524
0525 template <typename CONTAINER,
0526 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0527 inline CONTAINER& idiscard_if_any(CONTAINER& c, const CONTAINER& ys) {
0528 return idiscard(c, [&](typename CONTAINER::value_type& x){ return contains(ys, x); });
0529 }
0530
0531
0532
0533
0534
0535 template <typename CONTAINER, typename FN,
0536 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0537 inline CONTAINER discard(const CONTAINER& c, const FN& f) {
0538 CONTAINER rtn = c;
0539 return idiscard(rtn, f);
0540 }
0541
0542
0543 template <typename CONTAINER,
0544 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0545 inline CONTAINER discard(const CONTAINER& c, const typename CONTAINER::value_type& y) {
0546 return discard(c, [&](typename CONTAINER::value_type& x){ return x == y; });
0547 }
0548
0549
0550 template <typename CONTAINER,
0551 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0552 inline CONTAINER discard_if_any(const CONTAINER& c, const CONTAINER& ys) {
0553 return discard(c, [&](typename CONTAINER::value_type& x){ return contains(ys, x); });
0554 }
0555
0556
0557
0558
0559
0560
0561
0562 template <typename CONTAINER, typename FN,
0563
0564 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0565 inline CONTAINER& discard(const CONTAINER& c, const FN& f, CONTAINER& out) {
0566 out = discard(c, f);
0567 return out;
0568 }
0569
0570
0571 template <typename CONTAINER,
0572 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0573 inline CONTAINER& discard(const CONTAINER& c, const typename CONTAINER::value_type& y, CONTAINER& out) {
0574 return discard(c, [&](typename CONTAINER::value_type& x){ return x == y; }, out);
0575 }
0576
0577
0578 template <typename CONTAINER,
0579 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0580 inline CONTAINER& discard_if_any(const CONTAINER& c, const CONTAINER& ys, CONTAINER& out) {
0581 return discard(c, [&](typename CONTAINER::value_type& x){ return contains(ys, x); }, out);
0582 }
0583
0584
0585
0586
0587
0588
0589 template <typename CONTAINER, typename FN,
0590 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0591 inline CONTAINER& iselect(CONTAINER& c, const FN& f) {
0592 auto invf = [&](const typename CONTAINER::value_type& x){ return !f(x); };
0593 return idiscard(c, invf);
0594 }
0595
0596
0597
0598
0599 template <typename CONTAINER,
0600 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0601 inline CONTAINER& iselect_if_any(CONTAINER& c, const CONTAINER& ys) {
0602 return iselect(c, [&](typename CONTAINER::value_type& x){ return contains(ys, x); });
0603 }
0604
0605
0606
0607
0608
0609 template <typename CONTAINER, typename FN,
0610 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0611 inline CONTAINER select(const CONTAINER& c, const FN& f) {
0612 CONTAINER rtn = c;
0613 return iselect(rtn, f);
0614 }
0615
0616
0617
0618
0619 template <typename CONTAINER,
0620 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0621 inline CONTAINER select_if_any(const CONTAINER& c, const CONTAINER& ys) {
0622 return select(c, [&](typename CONTAINER::value_type& x){ return contains(ys, x); });
0623 }
0624
0625
0626
0627
0628
0629
0630
0631 template <typename CONTAINER, typename FN,
0632 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0633 inline CONTAINER& select(const CONTAINER& c, const FN& f, CONTAINER& out) {
0634 out = select(c, f);
0635 return out;
0636 }
0637
0638
0639
0640
0641 template <typename CONTAINER,
0642 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0643 inline CONTAINER& select_if_any(const CONTAINER& c, const CONTAINER& ys, CONTAINER& out) {
0644 return select(c, [&](typename CONTAINER::value_type& x){ return contains(ys, x); }, out);
0645 }
0646
0647
0648
0649
0650
0651
0652
0653 template <typename CONTAINER,
0654 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0655 inline CONTAINER slice(const CONTAINER& c, int i, int j) {
0656 CONTAINER rtn;
0657 const size_t off1 = (i >= 0) ? i : c.size() + i;
0658 const size_t off2 = (j >= 0) ? j : c.size() + j;
0659 if (off1 > c.size() || off2 > c.size()) throw RangeError("Attempting to slice beyond requested offsets");
0660 if (off2 < off1) throw RangeError("Requested offsets in invalid order");
0661 rtn.resize(off2 - off1);
0662 std::copy(c.begin()+off1, c.begin()+off2, rtn.begin());
0663 return rtn;
0664 }
0665
0666
0667
0668
0669 template <typename CONTAINER,
0670 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0671 inline CONTAINER slice(const CONTAINER& c, int i) {
0672 return slice(c, i, c.size());
0673 }
0674
0675
0676
0677
0678 template <typename CONTAINER,
0679 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0680 inline CONTAINER head(const CONTAINER& c, int n) {
0681
0682 if (n < 0) n = std::max(0, (int)c.size()+n);
0683 n = std::min(n, (int)c.size());
0684 return slice(c, 0, n);
0685 }
0686
0687
0688
0689
0690 template <typename CONTAINER,
0691 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0692 inline CONTAINER tail(const CONTAINER& c, int n) {
0693
0694 if (n < 0) n = std::max(0, (int)c.size()+n);
0695 n = std::min(n, (int)c.size());
0696 return slice(c, c.size()-n);
0697 }
0698
0699
0700 using std::min;
0701 using std::max;
0702
0703
0704 inline double min(const vector<double>& in, double errval=DBL_NAN) {
0705 const auto e = std::min_element(in.begin(), in.end());
0706 return e != in.end() ? *e : errval;
0707 }
0708
0709
0710 inline double max(const vector<double>& in, double errval=DBL_NAN) {
0711 const auto e = std::max_element(in.begin(), in.end());
0712 return e != in.end() ? *e : errval;
0713 }
0714
0715
0716 inline pair<double,double> minmax(const vector<double>& in, double errval=DBL_NAN) {
0717 const auto e = std::minmax_element(in.begin(), in.end());
0718 const double rtnmin = e.first != in.end() ? *e.first : errval;
0719 const double rtnmax = e.second != in.end() ? *e.first : errval;
0720 return std::make_pair(rtnmin, rtnmax);
0721 }
0722
0723
0724
0725 inline int min(const vector<int>& in, int errval=-1) {
0726 const auto e = std::min_element(in.begin(), in.end());
0727 return e != in.end() ? *e : errval;
0728 }
0729
0730
0731 inline int max(const vector<int>& in, int errval=-1) {
0732 const auto e = std::max_element(in.begin(), in.end());
0733 return e != in.end() ? *e : errval;
0734 }
0735
0736
0737 inline pair<int,int> minmax(const vector<int>& in, int errval=-1) {
0738 const auto e = std::minmax_element(in.begin(), in.end());
0739 const double rtnmin = e.first != in.end() ? *e.first : errval;
0740 const double rtnmax = e.second != in.end() ? *e.first : errval;
0741 return std::make_pair(rtnmin, rtnmax);
0742 }
0743
0744
0745
0746
0747
0748
0749
0750
0751
0752
0753
0754
0755 template <typename CONTAINER,
0756 typename FN = double(const typename std::decay_t<CONTAINER>::value_type::ParticleBase&),
0757 typename = isCIterable<CONTAINER>>
0758 inline int closestMatchIndex(const CONTAINER& c, FN&& fn,
0759 double target, double minval=-DBL_MAX, double maxval=DBL_MAX) {
0760 auto f = std::function(std::forward<FN>(fn));
0761 int ibest = -1;
0762 double best = DBL_NAN;
0763 for (size_t i = 0; i < c.size(); ++i) {
0764 const double val = f(c[i]);
0765 if (isnan(val)) continue;
0766 if (val < minval || val > maxval) continue;
0767 if (isnan(best) || fabs(val-target) < fabs(best-target)) {
0768 best = val;
0769 ibest = i;
0770 }
0771 }
0772 return ibest;
0773 }
0774
0775
0776
0777
0778
0779
0780
0781
0782
0783 template <typename CONTAINER1, typename CONTAINER2,
0784 typename FN = double(const typename std::decay_t<CONTAINER1>::value_type::ParticleBase&,
0785 const typename std::decay_t<CONTAINER2>::value_type::ParticleBase&),
0786 typename = isCIterable<CONTAINER1, CONTAINER2>>
0787 inline pair<int,int> closestMatchIndices(const CONTAINER1& c1, const CONTAINER2& c2, FN&& fn,
0788 double target, double minval=-DBL_MAX, double maxval=DBL_MAX) {
0789 auto f = std::function(std::forward<FN>(fn));
0790 pair<int,int> ijbest{-1,-1};
0791 double best = DBL_NAN;
0792 for (size_t i = 0; i < c1.size(); ++i) {
0793 for (size_t j = 0; j < c2.size(); ++j) {
0794 const double val = f(c1[i], c2[j]);
0795 if (isnan(val)) continue;
0796 if (val < minval || val > maxval) continue;
0797 if (isnan(best) || fabs(val-target) < fabs(best-target)) {
0798 best = val;
0799 ijbest = {i,j};
0800 }
0801 }
0802 }
0803 return ijbest;
0804 }
0805
0806
0807
0808
0809
0810
0811
0812
0813
0814 template <typename CONTAINER, typename T,
0815 typename FN = double(const typename std::decay_t<CONTAINER>::value_type::ParticleBase&, const std::decay_t<T>&),
0816 typename = isCIterable<CONTAINER>>
0817 inline int closestMatchIndex(const CONTAINER& c, const T& x, FN&& fn,
0818 double target, double minval=-DBL_MAX, double maxval=DBL_MAX) {
0819 pair<int,int> ijbest = closestMatchIndices(c, vector<T>{x}, std::forward<FN>(fn), target, minval, maxval);
0820 return ijbest.first;
0821 }
0822
0823
0824
0825
0826
0827
0828
0829
0830
0831 template <typename CONTAINER, typename T, typename FN, typename = isCIterable<CONTAINER>>
0832 inline int closestMatchIndex(const T& x, const CONTAINER& c, FN&& fn,
0833 double target, double minval=-DBL_MAX, double maxval=DBL_MAX) {
0834 return closestMatchIndex(c, x, std::forward<FN>(fn), target, minval, maxval);
0835 }
0836
0837
0838
0839
0840
0841
0842
0843
0844
0845 template <typename T>
0846 T getEnvParam(const std::string name, const T& fallback) {
0847 char* env = getenv(name.c_str());
0848 return env ? lexical_cast<T>(env) : fallback;
0849 }
0850
0851
0852
0853
0854
0855
0856 template<class T>
0857 vector<T> slice(const vector<T>& v, int startidx, int endidx) {
0858
0859 if (startidx < 0 || endidx <= startidx || endidx >= v.size())
0860 throw RangeError("Requested start or end indices incompatible with given vector");
0861
0862 auto start = v.begin() + startidx;
0863 auto end = v.begin() + endidx;
0864
0865 vector<T> output(endidx - startidx);
0866
0867 copy(start, end, output.begin());
0868
0869 return output;
0870 }
0871
0872
0873 }
0874
0875 #endif