diff options
author | sotech117 <michael_foiani@brown.edu> | 2024-04-09 03:14:17 -0400 |
---|---|---|
committer | sotech117 <michael_foiani@brown.edu> | 2024-04-09 03:14:17 -0400 |
commit | 7a8d0d8bc2572707c9d35006f30ea835c86954b0 (patch) | |
tree | dedb9a65c1698202ad485378b4186b667008abe5 /src/ocean/ocean.cpp | |
parent | 818324678bd5dca790c57048e5012d2937a4b5e5 (diff) |
first draft to generate waves
Diffstat (limited to 'src/ocean/ocean.cpp')
-rw-r--r-- | src/ocean/ocean.cpp | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/src/ocean/ocean.cpp b/src/ocean/ocean.cpp new file mode 100644 index 0000000..f70a553 --- /dev/null +++ b/src/ocean/ocean.cpp @@ -0,0 +1,259 @@ +// +// Created by Michael Foiani on 4/9/24. +// + +#include <iostream> +#include "ocean.h" + +// TODO: make these private instance variables + +ocean::ocean() +{ + initial_h = std::vector<std::pair<double, double>>(); + // initialize the initial height fields + for (int i = 0; i < N; i++) + { + initial_h.push_back(amplitude_0(i)); + } +} + +/* Maps the 1D k-index into it's 2D waveform vector */ +std::pair<double, double> ocean::k_index_to_k_vector + ( + int k_index + ) +{ + // get the x and z indices + int x = k_index % length; + int z = k_index / length; + + // calculate the k_x and k_z values, according to the length + double k_x = (2 * M_PI * x - N) / (double) length; + double k_z = (2 * M_PI * z - N) / (double) width; + + return std::make_pair(k_x, k_z); +} + +/* + * Randomly generates a complex number by + * importance sampling a Gaussian distribution + * with mean 0 and variance 1. + * + * Applies the Box-Muller transform to generate, + * citation: en.wikipedia.org/wiki/Box%E2%80%93Muller_transform + */ +std::pair<double, double> ocean::sample_complex_gaussian + () +{ + double uniform_1 = (double)rand() / (RAND_MAX); + double uniform_2 = (double)rand() / (RAND_MAX); + + // set a lower bound on zero to avoid undefined log(0) + if (uniform_1 == 0) + { + uniform_1 = 1e-10; + } + if (uniform_2 == 0) + { + uniform_2 = 1e-10; + } + + // real and imaginary parts of the complex number + double real = sqrt(-2 * log(uniform_1)) * cos(2 * M_PI * uniform_2); + double imag = sqrt(-2 * log(uniform_1)) * sin(2 * M_PI * uniform_2); + + return std::make_pair(real, imag); +} + +/* + * Generates the Phillips spectrum for a given k-index. + * See section 4.3 of the paper. + */ +double ocean::phillips_spectrum + ( + int k_index + ) +{ + // get the k_x, k_z values & amplitude of k + std::pair<double, double> k = k_index_to_k_vector(k_index); + double k_x = k.first; + double k_z = k.second; + double k_magnitude = sqrt(k_x * k_x + k_z * k_z); + + // calculate L, the max wave size from wind speed V + double L = (V * V) / 9.81; + // get the strength of k onto the wind direction + double k_dot_omega = k_x * omega_wind.first + k_z * omega_wind.second; + + // calculate certain parts of the Phillips formula + double k_dot_omega_squared = k_dot_omega * k_dot_omega; + double KL_squared = (k_magnitude * L) * (k_magnitude * L); + double k_fourth = k_magnitude * k_magnitude * k_magnitude * k_magnitude; + + double phillips = + A // numeric constant + * exp(-1 / KL_squared) + / (k_fourth) + * k_dot_omega_squared; + + // TODO: consider the small length check as described in the paper + return phillips; +} + +/* + * Generates the initial (i.e. t = 0) fourier amplitude. + * See section 4.4 of the paper. + */ +std::pair<double, double> ocean::amplitude_0 + ( + int k_index + ) +{ + std::pair<double, double> xi = sample_complex_gaussian(); + + double xi_real = xi.first; + double xi_imag = xi.second; + + double sqrt_phillips = sqrt(phillips_spectrum(k_index)); + + double real = (1 / sqrt(2)) * xi_real * sqrt_phillips; + double imag = (1 / sqrt(2)) * xi_imag * sqrt_phillips; + + return std::make_pair(real, imag); +} + +/* + * Maps the negative k-index from a given k-index, + * used for the complex conjugate in amplitude_t + */ +int ocean::k_index_to_negative_k_index + ( + int k_index + ) +{ + int x = k_index % length; + int z = k_index / length; + + int x_neg = length - x; + int z_neg = width - z; + + return z_neg * length + x_neg; +} + +/* + * Calculates the dispersion relation for a given k-index. + * See section 4.2 of the paper. + */ +double ocean::omega_dispersion + ( + double k_magnitude, + bool is_shallow + ) +{ + if (is_shallow) + { + double tanh_kD = tanh(D * k_magnitude); + return sqrt(9.81 * k_magnitude * tanh_kD); + } + else + { + return sqrt(9.81 * k_magnitude); + } +} + +std::pair<double, double> ocean::exp_complex + ( + std::pair<double, double> z + ) +{ + double real = exp(z.first) * cos(z.second); + double imag = exp(z.first) * sin(z.second); + + return std::make_pair(real, imag); +} + +/* + * Generates the fourier amplitude at time t. + * See section 4.4 of the paper. + */ +std::pair<double, double> ocean::amplitude_t + ( + double t, + int k_index + ) +{ + // get the initial height (and it's conjugate) + std::pair<double, double> h_0 = initial_h[k_index]; + std::pair<double, double> h_0_conjugate = initial_h[k_index_to_negative_k_index(k_index)]; + h_0_conjugate = std::make_pair(h_0_conjugate.first, -h_0_conjugate.second); + + // get dispersion from k + std::pair<double, double> k = k_index_to_k_vector(k_index); + double k_magnitude = sqrt(k.first * k.first + k.second * k.second); + double omega = omega_dispersion(k_magnitude); + + // calculate the complex exponential terms + double omega_t = omega * t; + std::pair<double, double> exp_positive = exp_complex(std::make_pair(0, omega_t)); + std::pair<double, double> exp_negative = exp_complex(std::make_pair(0, -omega_t)); + + // add the real and imaginary part together from both h_0 and h_0_conjugate + double real = + // h+0 real + h_0.first * exp_positive.first + - h_0.second * exp_positive.second + // h_0_conjugate real + + h_0_conjugate.first * exp_negative.first + - h_0_conjugate.second * exp_negative.second; + double imag = + // h_0 imaginary + h_0.first * exp_positive.second + + h_0.second * exp_positive.first + // h_0_conjugate imaginary + + h_0_conjugate.first * exp_negative.second + + h_0_conjugate.second * exp_negative.first; + + return std::make_pair(real, imag); +} + +std::vector<Eigen::Vector3f> ocean::get_vertices() +{ + std::vector<Eigen::Vector3f> vertices = std::vector<Eigen::Vector3f>(); + for (int i = 0; i < N; i++) + { + std::pair<double, double> k = k_index_to_k_vector(i); + double k_x = k.first; + double k_z = k.second; + + double amplitude = initial_h[i].first; + + std::cout << "k_x: " << k_x << " k_z: " << k_z << " amplitude: " << amplitude << std::endl; + + vertices.emplace_back(k_x, amplitude, k_z); + } + return vertices; +} + +std::vector<Eigen::Vector3i> ocean::get_faces() +{ + // connect the vertices into faces + std::vector<Eigen::Vector3i> faces = std::vector<Eigen::Vector3i>(); + for (int i = 0; i < N; i++) + { + int x = i % length; + int z = i / length; + + // connect the vertices into faces + if (x < length - 1 && z < width - 1) + { + int i1 = i; + int i2 = i + 1; + int i3 = i + length; + int i4 = i + length + 1; + + faces.emplace_back(i1, i2, i3); + faces.emplace_back(i2, i3, i4); + } + } + return faces; +} |