Monte Carlo Integration Library 1.0
High-performance Monte Carlo methods for numerical integration and optimization
wind_farm_simulator.cpp
Go to the documentation of this file.
1
33#include <iostream>
34#include <vector>
35#include <cmath>
36#include <random>
37#include <fstream>
38#include <iomanip>
39#include <limits>
40#include <functional>
41#include <chrono>
42#include <cstdint>
43#include <array>
44#include <mutex>
45#include <sstream>
46#include <omp.h>
47
48// --- Montecarlo library headers ---
49#include "../montecarlo/rng/rng_global.hpp"
50#include "../montecarlo/rng/rng_factory.hpp"
51
52#include "../montecarlo/optimizers/PSO.hpp"
53#include "../montecarlo/optimizers/GA.hpp"
54#include "../montecarlo/optimizers/types.hpp"
55
56// IMPORTANT: include proposals BEFORE MHintegrator.hpp
57#include "../montecarlo/proposals/proposal.hpp"
58#include "../montecarlo/proposals/gaussianProposal.hpp"
59
60#include "../montecarlo/integrators/MHintegrator.hpp"
61
62#include "../montecarlo/domains/integration_domain.hpp"
63#include "../montecarlo/domains/hyperrectangle.hpp"
64#include "../montecarlo/geometry.hpp"
65
66// =============================================================================
67// CONFIGURATION CONSTANTS
68// =============================================================================
69
70constexpr size_t NUM_TURBINES = 15;
71
72constexpr double FARM_WIDTH = 1000.0;
73constexpr double FARM_HEIGHT = 1000.0;
74
75constexpr double MIN_TURBINE_DISTANCE = 50.0;
76constexpr double PROXIMITY_PENALTY = 1e8;
77
78// Weibull wind parameters
79constexpr double WEIBULL_SHAPE = 2.0;
80constexpr double WEIBULL_SCALE = 8.0;
81
82// Turbine model constants
83constexpr double POWER_COEFFICIENT = 0.4;
84constexpr double AIR_DENSITY = 1.225;
85constexpr double ROTOR_AREA = M_PI * 25.0 * 25.0;
86
87// --- MH integration configuration ---
88constexpr int MH_SAMPLES = 1500;
89constexpr size_t MH_BURN_IN = 400;
90constexpr size_t MH_THINNING = 2;
91constexpr size_t MH_SAMPLES_FOR_VOL = 2000;
92
93// Proposal sigmas (in physical coordinates v, theta)
94constexpr double PROPOSAL_SIGMA_V = 2.5; // m/s
95constexpr double PROPOSAL_SIGMA_THETA = 0.6; // rad
96
97// Wind integration bounds (physical)
98constexpr double WIND_SPEED_MIN = 0.0;
99constexpr double WIND_SPEED_MAX = 40.0;
100constexpr double WIND_THETA_MIN = 0.0;
101constexpr double WIND_THETA_MAX = 2.0 * M_PI;
102
103// Centers for mapping from centered domain coords to physical coords
104constexpr double WIND_SPEED_CENTER = 0.5 * (WIND_SPEED_MIN + WIND_SPEED_MAX); // 20
105constexpr double WIND_THETA_CENTER = 0.5 * (WIND_THETA_MIN + WIND_THETA_MAX); // pi
106
107// Progress printing cadence
108constexpr size_t PROGRESS_EVERY = 10;
109
110// =============================================================================
111// GLOBAL OUTPUT GUARDS (thread-safe console + redirect)
112// =============================================================================
113
114// Global mutex to keep console output readable under OpenMP
115static std::mutex g_print_mutex;
116
117// Global mutex to serialize std::cout/std::cerr redirection sections
118static std::mutex g_cout_redirect_mutex;
119
120// A streambuf that discards everything written to it ("/dev/null"-like).
121class NullBuffer final : public std::streambuf {
122public:
123 int overflow(int c) override { return c; }
124};
125
126// RAII redirector for any std::ostream (e.g., std::cout).
127// NOTE: It is NOT intrinsically thread-safe; protect usage with g_cout_redirect_mutex.
128class CoutRedirector final {
129public:
130 explicit CoutRedirector(std::ostream& os)
131 : os_(os), old_buf_(os.rdbuf())
132 {
133 os_.rdbuf(null_stream().rdbuf());
134 }
135
137 os_.rdbuf(old_buf_);
138 }
139
142
143private:
144 static std::ostream& null_stream() {
145 static NullBuffer nb;
146 static std::ostream ns(&nb);
147 return ns;
148 }
149
150 std::ostream& os_;
151 std::streambuf* old_buf_ = nullptr;
152};
153
154// =============================================================================
155// UTILITY: WIND + GEOMETRY
156// =============================================================================
157
158inline double turbineDistance(double x1, double y1, double x2, double y2) {
159 const double dx = x2 - x1;
160 const double dy = y2 - y1;
161 return std::sqrt(dx * dx + dy * dy);
162}
163
165 std::vector<double>& x,
166 std::vector<double>& y) {
167 const size_t n = coords.size() / 2;
168 x.resize(n);
169 y.resize(n);
170 for (size_t i = 0; i < n; ++i) {
171 x[i] = coords[2 * i];
172 y[i] = coords[2 * i + 1];
173 }
174}
175
176double computeProximityPenalty(const std::vector<double>& x,
177 const std::vector<double>& y) {
178 double penalty = 0.0;
179 const size_t n = x.size();
180
181 for (size_t i = 0; i < n; ++i) {
182 for (size_t j = i + 1; j < n; ++j) {
183 const double dist = turbineDistance(x[i], y[i], x[j], y[j]);
184 if (dist < MIN_TURBINE_DISTANCE) {
185 const double violation = MIN_TURBINE_DISTANCE - dist;
186 penalty += PROXIMITY_PENALTY * violation * violation;
187 }
188 }
189 }
190 return penalty;
191}
192
193inline double windPower(double wind_speed) {
194 return 0.5 * AIR_DENSITY * ROTOR_AREA * POWER_COEFFICIENT *
195 std::pow(wind_speed, 3.0);
196}
197
198inline double applyWakeEffect(double base_speed, double distance) {
199 if (distance < MIN_TURBINE_DISTANCE) {
200 return base_speed * 0.3;
201 }
202 const double wake_decay = 0.04;
203 const double recovery = 1.0 - 0.3 / (1.0 + wake_decay * distance / 50.0);
204 return base_speed * std::min(1.0, recovery);
205}
206
207// Weibull pdf (unnormalized OK for MH)
208inline double weibull_pdf(double v) {
209 if (v < 0.0) return 0.0;
210 const double k = WEIBULL_SHAPE;
211 const double l = WEIBULL_SCALE;
212 const double a = (k / l);
213 const double x = v / l;
214 return a * std::pow(x, k - 1.0) * std::exp(-std::pow(x, k));
215}
216
217// Map centered-domain point w -> physical (v,theta)
218inline void mapToPhysicalWind(const mc::geom::Point<2>& w, double& v, double& theta) {
219 v = w[0] + WIND_SPEED_CENTER;
220 theta = w[1] + WIND_THETA_CENTER;
221}
222
223// =============================================================================
224// DOMAIN BUILDER (HyperRectangle takes dims, centered at origin)
225// =============================================================================
226
228 // Domain extents (dims) for centered box:
229 // w0 in [-dv/2, +dv/2], w1 in [-dtheta/2, +dtheta/2]
230 std::array<double, 2> dims{
233 };
234 return new mc::domains::HyperRectangle<2>(dims);
235}
236
237// =============================================================================
238// POWER FOR GIVEN (v,theta) AND LAYOUT
239// =============================================================================
240
241static inline double farmPowerGivenWind(const std::vector<double>& x,
242 const std::vector<double>& y,
243 double wind_speed,
244 double wind_direction) {
245 const size_t n = x.size();
246 double sample_power = 0.0;
247
248 for (size_t i = 0; i < n; ++i) {
249 double turbine_wind = wind_speed;
250
251 for (size_t j = 0; j < n; ++j) {
252 if (i == j) continue;
253
254 const double dx = x[i] - x[j];
255 const double dy = y[i] - y[j];
256 const double dist = std::sqrt(dx * dx + dy * dy);
257
258 const double wind_proj = dx * std::cos(wind_direction) +
259 dy * std::sin(wind_direction);
260
261 if (wind_proj > 0.0 && dist < 500.0) {
262 turbine_wind = applyWakeEffect(turbine_wind, dist);
263 }
264 }
265
266 sample_power += windPower(turbine_wind);
267 }
268
269 return sample_power;
270}
271
272// =============================================================================
273// MH-BASED EXPECTATION ESTIMATION (silent volume spam)
274// =============================================================================
275
276static double estimateAveragePowerMH(const std::vector<double>& x,
277 const std::vector<double>& y,
278 std::uint32_t seed32) {
279 using Point2 = mc::geom::Point<2>;
281
283 Integrator2 mh(*domain);
284
285 // Target density p(w) = p(v(w),theta(w)) with theta uniform -> proportional to weibull(v)
286 auto p = [](const Point2& w) -> double {
287 double v, theta;
288 mapToPhysicalWind(w, v, theta);
289
290 (void)theta; // uniform -> constant
291 if (v < WIND_SPEED_MIN || v > WIND_SPEED_MAX) return 0.0;
292 return weibull_pdf(v);
293 };
294
295 // Initial point in centered coordinates: choose physical (v=WEIBULL_SCALE, theta=pi)
296 Point2 x0;
297 x0[0] = WEIBULL_SCALE - WIND_SPEED_CENTER; // shift to centered coords
298 x0[1] = M_PI - WIND_THETA_CENTER; // = 0
299
300 // deviation_ parameter: keep 1.0 unless your MH uses it internally
301 const double mh_deviation_param = 1.0;
302
303 mh.setConfig(MH_BURN_IN,
306 mh_deviation_param,
307 p,
308 x0);
309
310 // GaussianProposal samples in centered coordinates w
311 std::vector<double> mu{
313 M_PI - WIND_THETA_CENTER
314 };
315 std::vector<double> sigma{
318 };
319
320 mc::proposals::GaussianProposal<2> proposal(*domain, mu, sigma);
321
322 auto f = [&](const Point2& w) -> double {
323 double v, theta;
324 mapToPhysicalWind(w, v, theta);
325 return farmPowerGivenWind(x, y, v, theta);
326 };
327
328 double avg_power = 0.0;
329
330 // The "Volume: ... +- ..." spam originates inside MH/VolumeEstimator.
331 // We cannot change the library, so we redirect std::cout (and std::cerr if needed)
332 // ONLY while calling the MH integration.
333 {
334 std::lock_guard<std::mutex> lock(g_cout_redirect_mutex);
335
336 CoutRedirector mute_cout(std::cout);
337 CoutRedirector mute_cerr(std::cerr);
338
339 avg_power = mh.integrate(f, MH_SAMPLES, proposal, seed32);
340 }
341
342 delete domain;
343 return avg_power;
344}
345
346// =============================================================================
347// OBJECTIVE FUNCTION (PSO/GA unchanged)
348// =============================================================================
349
350inline std::uint64_t hashCoordsForSeed(const mc::optim::Coordinates& coords) {
351 std::uint64_t hash = 0;
352 for (size_t i = 0; i < coords.size(); ++i) {
353 hash ^= (static_cast<std::uint64_t>(std::hash<double>{}(coords[i]))
354 + 0x9e3779b97f4a7c15ULL + (hash << 6) + (hash >> 2));
355 }
356#ifdef _OPENMP
357 hash += static_cast<std::uint64_t>(omp_get_thread_num()) * 1000000ULL;
358#endif
359 return hash;
360}
361
362double windFarmObjective(const mc::optim::Coordinates& coords, std::uint64_t thread_seed) {
363 // Always guard against uncaught exceptions inside the objective.
364 // If something fails, return a large penalty to keep optimizers stable.
365 try {
366 std::vector<double> x, y;
367 extractTurbinePositions(coords, x, y);
368
369 const double penalty = computeProximityPenalty(x, y);
370 if (penalty > 0.0) return penalty;
371
372 const std::uint32_t seed32 = static_cast<std::uint32_t>(thread_seed);
373 const double avg_power = estimateAveragePowerMH(x, y, seed32);
374
375 if (!std::isfinite(avg_power)) {
376 return 1e12;
377 }
378
379 // Optimizers minimize -> maximize avg_power by returning negative
380 return -avg_power;
381 } catch (...) {
382 return 1e12;
383 }
384}
385
386// =============================================================================
387// OUTPUT AND VISUALIZATION
388// =============================================================================
389
390void writeResultsFile(const std::string& filename,
391 const std::vector<double>& x,
392 const std::vector<double>& y) {
393 std::ofstream out(filename);
394 if (!out.is_open()) {
395 std::lock_guard<std::mutex> lock(g_print_mutex);
396 std::cerr << "Error: Cannot create " << filename << "\n";
397 return;
398 }
399
400 out << "# Wind Farm Turbine Positions\n";
401 out << "# x_coord y_coord turbine_id\n";
402 for (size_t i = 0; i < x.size(); ++i) {
403 out << std::fixed << std::setprecision(2)
404 << x[i] << " " << y[i] << " " << (i + 1) << "\n";
405 }
406
407 std::lock_guard<std::mutex> lock(g_print_mutex);
408 std::cout << "[INFO] Results written to " << filename << "\n";
409}
410
411void writePlotScript(const std::string& filename,
412 const std::string& data_file,
413 const std::string& output_png) {
414 std::ofstream gp(filename);
415 if (!gp.is_open()) {
416 std::lock_guard<std::mutex> lock(g_print_mutex);
417 std::cerr << "Error: Cannot create " << filename << "\n";
418 return;
419 }
420
421 gp << "set terminal pngcairo size 1200,1000 enhanced font 'Arial,12'\n";
422 gp << "set output '" << output_png << "'\n\n";
423 gp << "set title 'Wind Farm Optimization Layout'\n";
424 gp << "set xlabel 'X Position (m)'\n";
425 gp << "set ylabel 'Y Position (m)'\n";
426 gp << "set grid\n";
427 gp << "set key outside right top\n";
428 gp << "set xrange [-50:" << (FARM_WIDTH + 50) << "]\n";
429 gp << "set yrange [-50:" << (FARM_HEIGHT + 50) << "]\n";
430 gp << "set size ratio 1\n\n";
431 gp << "set object 1 rect from 0,0 to " << FARM_WIDTH << "," << FARM_HEIGHT
432 << " fs empty border lc rgb 'black' lw 2\n\n";
433
434 gp << "plot '" << data_file << "' using 1:2 with points pt 9 ps 3 title 'Wind Turbines',\\\n"
435 " '" << data_file << "' using 1:2:3 with labels offset 0,1.5 notitle\n";
436
437 std::lock_guard<std::mutex> lock(g_print_mutex);
438 std::cout << "[INFO] Gnuplot script written to " << filename << "\n";
439}
440
441static double computeMinDistance(const std::vector<double>& x,
442 const std::vector<double>& y) {
443 double min_dist = std::numeric_limits<double>::max();
444 for (size_t i = 0; i < x.size(); ++i) {
445 for (size_t j = i + 1; j < x.size(); ++j) {
446 min_dist = std::min(min_dist, turbineDistance(x[i], y[i], x[j], y[j]));
447 }
448 }
449 return min_dist;
450}
451
452// =============================================================================
453// BENCH HARNESS (PSO/GA API unchanged)
454// =============================================================================
455
456struct RunResult {
457 std::string name;
459 std::vector<double> x, y;
460 double seconds = 0.0;
461
462 double best_avg_power_mw = 0.0;
463 double min_distance_m = 0.0;
464};
465
466template <typename OptimizerT>
467RunResult runOptimizer(const std::string& name,
468 OptimizerT& optimizer,
469 const mc::optim::Coordinates& lower_bounds,
470 const mc::optim::Coordinates& upper_bounds,
471 const std::string& results_file,
472 const std::string& plot_script,
473 const std::string& output_png)
474{
475 optimizer.setBounds(lower_bounds, upper_bounds);
476 optimizer.setMode(mc::optim::OptimizationMode::MINIMIZE);
477
478 optimizer.setObjectiveFunction([](const mc::optim::Coordinates& coords) -> mc::optim::Real {
479 return windFarmObjective(coords, hashCoordsForSeed(coords));
480 });
481
482 optimizer.setCallback([name](const mc::optim::Solution& best, size_t it) {
483 if (it % PROGRESS_EVERY == 0 || it == 1) {
484 const double power_mw = -best.value / 1e6;
485 std::lock_guard<std::mutex> lock(g_print_mutex);
486 std::cout << "[" << name << " | ITER " << std::setw(4) << it << "] "
487 << "Best power: " << std::fixed << std::setprecision(6)
488 << power_mw << " MW\n";
489 }
490 });
491
492 {
493 std::lock_guard<std::mutex> lock(g_print_mutex);
494 std::cout << "\n[INFO] Starting " << name << " optimization...\n\n";
495 }
496
497 const auto t0 = std::chrono::high_resolution_clock::now();
498 mc::optim::Solution best = optimizer.optimize();
499 const auto t1 = std::chrono::high_resolution_clock::now();
500
501 const double seconds =
502 std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0).count() / 1000.0;
503
504 std::vector<double> x, y;
506
507 writeResultsFile(results_file, x, y);
508 writePlotScript(plot_script, results_file, output_png);
509
510 RunResult rr;
511 rr.name = name;
512 rr.best = best;
513 rr.x = std::move(x);
514 rr.y = std::move(y);
515 rr.seconds = seconds;
516 rr.best_avg_power_mw = (-best.value) / 1e6;
518 return rr;
519}
520
521static void printFinalComparisonTable(const RunResult& pso_res, const RunResult& ga_res) {
522 const std::string winner = (ga_res.best_avg_power_mw > pso_res.best_avg_power_mw) ? "GA" : "PSO";
523
524 std::lock_guard<std::mutex> lock(g_print_mutex);
525
526 std::cout << "\n=== FINAL RESULTS (clean) ===\n";
527 std::cout << std::left
528 << std::setw(10) << "Method"
529 << std::right
530 << std::setw(12) << "Time(s)"
531 << std::setw(18) << "BestAvg(MW)"
532 << std::setw(18) << "MinDist(m)"
533 << "\n";
534
535 std::cout << std::string(10 + 12 + 18 + 18, '-') << "\n";
536
537 auto printRow = [](const RunResult& r) {
538 std::cout << std::left
539 << std::setw(10) << r.name
540 << std::right
541 << std::setw(12) << std::fixed << std::setprecision(3) << r.seconds
542 << std::setw(18) << std::fixed << std::setprecision(6) << r.best_avg_power_mw
543 << std::setw(18) << std::fixed << std::setprecision(2) << r.min_distance_m
544 << "\n";
545 };
546
547 printRow(pso_res);
548 printRow(ga_res);
549
550 std::cout << "\nWinner (power): " << winner << "\n";
551}
552
553// =============================================================================
554// MAIN
555// =============================================================================
556
557int main() {
558 {
559 std::lock_guard<std::mutex> lock(g_print_mutex);
560 std::cout << "\n=== WIND FARM: MH + PSO vs GA ===\n";
561 }
562
564 {
565 std::lock_guard<std::mutex> lock(g_print_mutex);
566 std::cout << "[INFO] Global RNG seed set to 42\n";
567 }
568
569 // Layout bounds
570 const size_t total_dims = 2 * NUM_TURBINES;
571 mc::optim::Coordinates lower_bounds(total_dims);
572 mc::optim::Coordinates upper_bounds(total_dims);
573
574 for (size_t i = 0; i < NUM_TURBINES; ++i) {
575 lower_bounds[2 * i] = 0.0;
576 upper_bounds[2 * i] = FARM_WIDTH;
577 lower_bounds[2 * i + 1] = 0.0;
578 upper_bounds[2 * i + 1] = FARM_HEIGHT;
579 }
580
581 // --- PSO (UNCHANGED API) ---
582 mc::optim::PSOConfig pso_cfg;
583 pso_cfg.population_size = 60;
584 pso_cfg.max_iterations = 150;
585 pso_cfg.inertia_weight = 0.6;
586 pso_cfg.cognitive_coeff = 1.8;
587 pso_cfg.social_coeff = 2.0;
588 mc::optim::PSO pso(pso_cfg);
589
590 // --- GA (UNCHANGED API) ---
591 mc::optim::GAConfig ga_cfg;
592 ga_cfg.population_size = 80;
593 ga_cfg.max_generations = 200;
594 ga_cfg.tournament_k = 3;
595 ga_cfg.crossover_rate = 0.9;
596 ga_cfg.mutation_rate = 0.10;
597 ga_cfg.mutation_sigma = 25.0; // meters
598 ga_cfg.elitism_count = 2;
599 mc::optim::GA ga(ga_cfg);
600
601 // Run both
602 RunResult pso_res = runOptimizer("PSO", pso, lower_bounds, upper_bounds,
603 "results_pso.dat", "plot_pso.gp", "wind_farm_layout_pso.png");
604
605 RunResult ga_res = runOptimizer("GA", ga, lower_bounds, upper_bounds,
606 "results_ga.dat", "plot_ga.gp", "wind_farm_layout_ga.png");
607
608 // Print final comparison table
609 printFinalComparisonTable(pso_res, ga_res);
610
611 {
612 std::lock_guard<std::mutex> lock(g_print_mutex);
613 std::cout << "\n[INFO] Plots:\n";
614 std::cout << " gnuplot plot_pso.gp -> wind_farm_layout_pso.png\n";
615 std::cout << " gnuplot plot_ga.gp -> wind_farm_layout_ga.png\n\n";
616 }
617
618 return 0;
619}
CoutRedirector(std::ostream &os)
CoutRedirector(const CoutRedirector &)=delete
CoutRedirector & operator=(const CoutRedirector &)=delete
int overflow(int c) override
Axis-aligned hyperrectangular domain.
Abstract base class for N-dimensional integration domains.
N-dimensional point representation.
Definition geometry.hpp:32
Metropolis-Hastings MCMC integrator for complex domains.
Genetic Algorithm optimizer.
Definition GA.hpp:46
Particle Swarm Optimization algorithm.
Definition PSO.hpp:40
std::vector< Real > Coordinates
A point in the N-dimensional search space.
Definition types.hpp:31
double Real
Scalar precision used across optimizers.
Definition types.hpp:26
bool set_global_seed(std::uint32_t s)
Set the global seed used by all library RNG components.
std::vector< double > y
mc::optim::Solution best
std::vector< double > x
Configuration parameters for GA.
Definition GA.hpp:21
size_t elitism_count
Number of top individuals copied unchanged to next generation.
Definition GA.hpp:38
size_t tournament_k
Tournament size for selection (k >= 2).
Definition GA.hpp:28
Real mutation_rate
Per-gene mutation probability.
Definition GA.hpp:33
size_t population_size
Size of the population.
Definition GA.hpp:23
Real crossover_rate
Probability of performing crossover in reproduction.
Definition GA.hpp:31
Real mutation_sigma
Mutation magnitude (scaled by coordinate span).
Definition GA.hpp:35
size_t max_generations
Number of generations to evolve.
Definition GA.hpp:25
Configuration parameters for PSO.
Definition PSO.hpp:21
size_t population_size
Number of particles in the swarm.
Definition PSO.hpp:23
Real social_coeff
Social coefficient (c2): scales attraction to global best.
Definition PSO.hpp:32
Real cognitive_coeff
Cognitive coefficient (c1): scales attraction to particle best.
Definition PSO.hpp:30
Real inertia_weight
Inertia weight (w): scales previous velocity.
Definition PSO.hpp:28
size_t max_iterations
Number of iterations to run the optimizer.
Definition PSO.hpp:25
Represents a candidate solution in the search space.
Definition types.hpp:51
Coordinates params
Parameter vector (coordinates in the search space).
Definition types.hpp:53
Real value
Evaluated objective value for params.
Definition types.hpp:55
constexpr double WIND_THETA_MAX
RunResult runOptimizer(const std::string &name, OptimizerT &optimizer, const mc::optim::Coordinates &lower_bounds, const mc::optim::Coordinates &upper_bounds, const std::string &results_file, const std::string &plot_script, const std::string &output_png)
static void printFinalComparisonTable(const RunResult &pso_res, const RunResult &ga_res)
constexpr double WIND_SPEED_MIN
constexpr double FARM_HEIGHT
constexpr size_t MH_BURN_IN
constexpr double WIND_SPEED_MAX
constexpr size_t MH_SAMPLES_FOR_VOL
void extractTurbinePositions(const mc::optim::Coordinates &coords, std::vector< double > &x, std::vector< double > &y)
constexpr double FARM_WIDTH
static double estimateAveragePowerMH(const std::vector< double > &x, const std::vector< double > &y, std::uint32_t seed32)
constexpr double PROPOSAL_SIGMA_V
double windPower(double wind_speed)
double computeProximityPenalty(const std::vector< double > &x, const std::vector< double > &y)
static std::mutex g_cout_redirect_mutex
constexpr double MIN_TURBINE_DISTANCE
constexpr double PROPOSAL_SIGMA_THETA
double weibull_pdf(double v)
constexpr size_t PROGRESS_EVERY
constexpr double WIND_SPEED_CENTER
void writeResultsFile(const std::string &filename, const std::vector< double > &x, const std::vector< double > &y)
constexpr double PROXIMITY_PENALTY
static double computeMinDistance(const std::vector< double > &x, const std::vector< double > &y)
constexpr size_t NUM_TURBINES
constexpr double WIND_THETA_MIN
constexpr double ROTOR_AREA
double turbineDistance(double x1, double y1, double x2, double y2)
constexpr size_t MH_THINNING
std::uint64_t hashCoordsForSeed(const mc::optim::Coordinates &coords)
constexpr double AIR_DENSITY
void writePlotScript(const std::string &filename, const std::string &data_file, const std::string &output_png)
static mc::domains::IntegrationDomain< 2 > * buildWindDomainOwned()
constexpr double WEIBULL_SHAPE
void mapToPhysicalWind(const mc::geom::Point< 2 > &w, double &v, double &theta)
constexpr double WIND_THETA_CENTER
constexpr double WEIBULL_SCALE
constexpr double POWER_COEFFICIENT
double windFarmObjective(const mc::optim::Coordinates &coords, std::uint64_t thread_seed)
static std::mutex g_print_mutex
int main()
constexpr int MH_SAMPLES
double applyWakeEffect(double base_speed, double distance)
static double farmPowerGivenWind(const std::vector< double > &x, const std::vector< double > &y, double wind_speed, double wind_direction)