7 #include "watersurface.h"
9 const double Sea::PHILLIPS_CONSTANT{0.0000003};
10 const double Sea::GRAVITATIONAL_CONSTANT{9.8};
12 Sea::Sea(WaterSurfacePtr surface) :
14 m_windDirection{1, 0},
16 m_randomGenerator{m_randomDevice()},
17 m_normalDistribution{0.0, 1.0}
19 m_fourierAmplitudes.resize(pow(m_surface->size(), 2));
20 generateFourierAmplitudes();
23 fftw_plan_with_nthreads(4);
25 m_fftwIn = (fftw_complex*)
26 fftw_malloc(sizeof(fftw_complex) * pow(m_surface->size(), 2));
27 m_fftwOut = (fftw_complex*)
28 fftw_malloc(sizeof(fftw_complex) * pow(m_surface->size(), 2));
29 m_fftwPlan = fftw_plan_dft_2d
30 (m_surface->size(), m_surface->size(), m_fftwIn, m_fftwOut,
31 FFTW_BACKWARD, FFTW_MEASURE);
33 m_startTime = std::chrono::system_clock::now();
38 fftw_destroy_plan(m_fftwPlan);
39 fftw_free(m_fftwIn); fftw_free(m_fftwOut);
42 double Sea::getRuntime() const
44 auto timeNow = std::chrono::system_clock::now();
46 std::chrono::duration_cast<std::chrono::milliseconds>(timeNow - m_startTime);
48 return durationMs.count() / 1000.0;
53 using namespace std::complex_literals;
55 const double runtime = getRuntime();
57 for (int m = -m_surface->size()/2; m < m_surface->size()/2; ++m) {
58 const int positiveM = (m + m_surface->size()) % m_surface->size();
60 for (int n = -m_surface->size()/2; n < m_surface->size()/2; ++n) {
61 const double k = sqrt(pow(spatialFrequencyForIndex(n), 2) +
62 pow(spatialFrequencyForIndex(m), 2));
63 const double omega = sqrt(GRAVITATIONAL_CONSTANT * k);
65 std::complex<double> amplitude =
66 fourierAmplitudeAt(n, m).first * exp(1i * omega * runtime) +
67 fourierAmplitudeAt(n, m).second * exp(-1i * omega * runtime);
69 const int positiveN = (n + m_surface->size()) % m_surface->size();
70 int fftwIndex = positiveM + positiveN * m_surface->size();
72 m_fftwIn[fftwIndex][0] = std::real(amplitude);
73 m_fftwIn[fftwIndex][1] = std::imag(amplitude);
77 fftw_execute(m_fftwPlan);
79 for (int y = 0; y < m_surface->size(); ++y) {
80 for (int x = 0; x < m_surface->size(); ++x) {
82 .setHeight(m_fftwOut[y + x * m_surface->size()][0]);
87 double Sea::phillipsSpectrum(double k_x, double k_y) const
89 const double k = sqrt(pow(k_x, 2) + pow(k_y, 2));
90 const double L = pow(m_windSpeed, 2) / GRAVITATIONAL_CONSTANT;
92 const double cosineFactor = pow((k_x / k) * m_windDirection[0] +
93 (k_y / k) * m_windDirection[1], 2);
95 return PHILLIPS_CONSTANT * exp(-1 / pow(k * L, 2)) / pow(k, 4) *
99 ComplexPair Sea::generateFourierAmplitude(double k_x, double k_y)
101 std::complex<double> cDist(m_normalDistribution(m_randomGenerator),
102 m_normalDistribution(m_randomGenerator));
104 return {cDist * sqrt(phillipsSpectrum(k_x, k_y)) / sqrt(2),
105 std::conj(cDist) * sqrt(phillipsSpectrum(-k_x, -k_y)) / sqrt(2)};
108 ComplexPair& Sea::fourierAmplitudeAt(int n, int m)
110 return m_fourierAmplitudes.at
111 (n + m_surface->size()/2 +
112 (m + m_surface->size()/2) * m_surface->size());
115 double Sea::spatialFrequencyForIndex(int n) const
117 return 2 * M_PI * n / m_surface->size();
120 void Sea::generateFourierAmplitudes()
122 for (int m = -m_surface->size()/2; m < m_surface->size()/2; ++m) {
123 for (int n = -m_surface->size()/2; n < m_surface->size()/2; ++n) {
124 fourierAmplitudeAt(n, m) =
125 generateFourierAmplitude(spatialFrequencyForIndex(n),
126 spatialFrequencyForIndex(m));
130 fourierAmplitudeAt(0, 0) = {0, 0};