| 405 | } |
| 406 | |
| 407 | af::array generate_image(size_t width, size_t height, const Simulation& sim) { |
| 408 | const auto& ux = sim.ux; |
| 409 | const auto& uy = sim.uy; |
| 410 | const auto& boundaries = sim.set_boundaries; |
| 411 | auto velocity = sim.velocity; |
| 412 | |
| 413 | float image_scale = |
| 414 | static_cast<float>(width) / static_cast<float>(sim.grid_width - 1); |
| 415 | |
| 416 | // Relative Flow speed at each cell |
| 417 | auto val = af::sqrt(ux * ux + uy * uy) / velocity; |
| 418 | |
| 419 | af::replace(val, val != 0 || !boundaries, -1.0); |
| 420 | |
| 421 | // Scaling and interpolating flow speed to the window size |
| 422 | if (width != sim.grid_width || height != sim.grid_height) |
| 423 | val = |
| 424 | af::approx2(val, af::iota(width, af::dim4(1, height)) / image_scale, |
| 425 | af::iota(height, af::dim4(1, width)).T() / image_scale); |
| 426 | |
| 427 | // Flip image |
| 428 | val = val.T(); |
| 429 | |
| 430 | auto image = af::constant(0, height, width, 3); |
| 431 | auto image2 = image; |
| 432 | |
| 433 | // Add custom coloring |
| 434 | image(af::span, af::span, 0) = val * 2; |
| 435 | image(af::span, af::span, 1) = val * 2; |
| 436 | image(af::span, af::span, 2) = 1.0 - val * 2; |
| 437 | |
| 438 | image2(af::span, af::span, 0) = 1; |
| 439 | image2(af::span, af::span, 1) = -2 * val + 2; |
| 440 | image2(af::span, af::span, 2) = 0; |
| 441 | |
| 442 | auto tile_val = af::tile(val, 1, 1, 3); |
| 443 | af::replace(image, tile_val < 0.5, image2); |
| 444 | af::replace(image, tile_val >= 0, 0.0); |
| 445 | |
| 446 | return image; |
| 447 | } |
| 448 | |
| 449 | void lattice_boltzmann_cfd_demo() { |
| 450 | // Define the lattice for the simulation |