49#include "../montecarlo/rng/rng_global.hpp"
50#include "../montecarlo/rng/rng_factory.hpp"
52#include "../montecarlo/optimizers/PSO.hpp"
53#include "../montecarlo/optimizers/GA.hpp"
54#include "../montecarlo/optimizers/types.hpp"
57#include "../montecarlo/proposals/proposal.hpp"
58#include "../montecarlo/proposals/gaussianProposal.hpp"
60#include "../montecarlo/integrators/MHintegrator.hpp"
62#include "../montecarlo/domains/integration_domain.hpp"
63#include "../montecarlo/domains/hyperrectangle.hpp"
64#include "../montecarlo/geometry.hpp"
131 : os_(os), old_buf_(os.rdbuf())
133 os_.rdbuf(null_stream().rdbuf());
144 static std::ostream& null_stream() {
146 static std::ostream ns(&nb);
151 std::streambuf* old_buf_ =
nullptr;
159 const double dx = x2 - x1;
160 const double dy = y2 - y1;
161 return std::sqrt(dx * dx + dy * dy);
165 std::vector<double>& x,
166 std::vector<double>& y) {
167 const size_t n = coords.size() / 2;
170 for (
size_t i = 0; i < n; ++i) {
171 x[i] = coords[2 * i];
172 y[i] = coords[2 * i + 1];
177 const std::vector<double>& y) {
178 double penalty = 0.0;
179 const size_t n = x.size();
181 for (
size_t i = 0; i < n; ++i) {
182 for (
size_t j = i + 1; j < n; ++j) {
195 std::pow(wind_speed, 3.0);
200 return base_speed * 0.3;
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);
209 if (v < 0.0)
return 0.0;
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));
230 std::array<double, 2> dims{
242 const std::vector<double>& y,
244 double wind_direction) {
245 const size_t n = x.size();
246 double sample_power = 0.0;
248 for (
size_t i = 0; i < n; ++i) {
249 double turbine_wind = wind_speed;
251 for (
size_t j = 0; j < n; ++j) {
252 if (i == j)
continue;
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);
258 const double wind_proj = dx * std::cos(wind_direction) +
259 dy * std::sin(wind_direction);
261 if (wind_proj > 0.0 && dist < 500.0) {
277 const std::vector<double>& y,
278 std::uint32_t seed32) {
283 Integrator2 mh(*domain);
286 auto p = [](
const Point2& w) ->
double {
301 const double mh_deviation_param = 1.0;
311 std::vector<double> mu{
315 std::vector<double> sigma{
322 auto f = [&](
const Point2& w) ->
double {
328 double avg_power = 0.0;
339 avg_power = mh.integrate(f,
MH_SAMPLES, proposal, seed32);
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));
357 hash +=
static_cast<std::uint64_t
>(omp_get_thread_num()) * 1000000ULL;
366 std::vector<double> x, y;
370 if (penalty > 0.0)
return penalty;
372 const std::uint32_t seed32 =
static_cast<std::uint32_t
>(thread_seed);
375 if (!std::isfinite(avg_power)) {
391 const std::vector<double>& x,
392 const std::vector<double>& y) {
393 std::ofstream out(filename);
394 if (!out.is_open()) {
396 std::cerr <<
"Error: Cannot create " << filename <<
"\n";
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";
408 std::cout <<
"[INFO] Results written to " << filename <<
"\n";
412 const std::string& data_file,
413 const std::string& output_png) {
414 std::ofstream gp(filename);
417 std::cerr <<
"Error: Cannot create " << filename <<
"\n";
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";
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";
432 <<
" fs empty border lc rgb 'black' lw 2\n\n";
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";
438 std::cout <<
"[INFO] Gnuplot script written to " << filename <<
"\n";
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]));
459 std::vector<double>
x,
y;
466template <
typename OptimizerT>
468 OptimizerT& optimizer,
471 const std::string& results_file,
472 const std::string& plot_script,
473 const std::string& output_png)
475 optimizer.setBounds(lower_bounds, upper_bounds);
484 const double power_mw = -best.
value / 1e6;
486 std::cout <<
"[" << name <<
" | ITER " << std::setw(4) << it <<
"] "
487 <<
"Best power: " << std::fixed << std::setprecision(6)
488 << power_mw <<
" MW\n";
494 std::cout <<
"\n[INFO] Starting " << name <<
" optimization...\n\n";
497 const auto t0 = std::chrono::high_resolution_clock::now();
499 const auto t1 = std::chrono::high_resolution_clock::now();
501 const double seconds =
502 std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0).count() / 1000.0;
504 std::vector<double> x, y;
526 std::cout <<
"\n=== FINAL RESULTS (clean) ===\n";
527 std::cout << std::left
528 << std::setw(10) <<
"Method"
530 << std::setw(12) <<
"Time(s)"
531 << std::setw(18) <<
"BestAvg(MW)"
532 << std::setw(18) <<
"MinDist(m)"
535 std::cout << std::string(10 + 12 + 18 + 18,
'-') <<
"\n";
538 std::cout << std::left
539 << std::setw(10) << r.name
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
550 std::cout <<
"\nWinner (power): " << winner <<
"\n";
560 std::cout <<
"\n=== WIND FARM: MH + PSO vs GA ===\n";
566 std::cout <<
"[INFO] Global RNG seed set to 42\n";
575 lower_bounds[2 * i] = 0.0;
577 lower_bounds[2 * i + 1] = 0.0;
603 "results_pso.dat",
"plot_pso.gp",
"wind_farm_layout_pso.png");
606 "results_ga.dat",
"plot_ga.gp",
"wind_farm_layout_ga.png");
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";
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.
Metropolis-Hastings MCMC integrator for complex domains.
Genetic Algorithm optimizer.
Particle Swarm Optimization algorithm.
std::vector< Real > Coordinates
A point in the N-dimensional search space.
double Real
Scalar precision used across optimizers.
bool set_global_seed(std::uint32_t s)
Set the global seed used by all library RNG components.
Configuration parameters for GA.
size_t elitism_count
Number of top individuals copied unchanged to next generation.
size_t tournament_k
Tournament size for selection (k >= 2).
Real mutation_rate
Per-gene mutation probability.
size_t population_size
Size of the population.
Real crossover_rate
Probability of performing crossover in reproduction.
Real mutation_sigma
Mutation magnitude (scaled by coordinate span).
size_t max_generations
Number of generations to evolve.
Configuration parameters for PSO.
size_t population_size
Number of particles in the swarm.
Real social_coeff
Social coefficient (c2): scales attraction to global best.
Real cognitive_coeff
Cognitive coefficient (c1): scales attraction to particle best.
Real inertia_weight
Inertia weight (w): scales previous velocity.
size_t max_iterations
Number of iterations to run the optimizer.
Represents a candidate solution in the search space.
Coordinates params
Parameter vector (coordinates in the search space).
Real value
Evaluated objective value for params.
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
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)