CoastalME (Coastal Modelling Environment)
Simulates the long-term behaviour of complex coastlines
Loading...
Searching...
No Matches
calc_waves.cpp
Go to the documentation of this file.
1
10
11/* ==============================================================================================================================
12 This file is part of CoastalME, the Coastal Modelling Environment.
13
14 CoastalME is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19==============================================================================================================================*/
20#include <assert.h>
21
22#include <cstdio>
23
24#include <cmath>
25using std::sin;
26using std::cos;
27using std::pow;
28using std::fmod;
29
30#include <string>
31using std::to_string;
32
33#include <iostream>
34using std::endl;
35using std::ios;
36
37#include <fstream>
38using std::ifstream;
39
40#include <algorithm>
41using std::reverse_copy;
42
43#include "cme.h"
44#include "coast.h"
45#include "simulation.h"
46#include "cshore/cshore.h"
47#include "2d_point.h"
48
49//===============================================================================================================================
51//===============================================================================================================================
53{
54 LogStream << endl << m_ulIter << ": Calculating waves" << endl;
55
56 // For each coastline, put a value for deep water wave height and direction at each coastline point
57 for (int nCoast = 0; nCoast < static_cast<int>(m_VCoast.size()); nCoast++)
58 {
59 int nDistFromPrevProfile = 0;
60 int nDistToNextProfile = 0;
61
62 double dPrevProfileDeepWaterWaveHeight = 0;
63 double dPrevProfileDeepWaterWaveAngle = 0;
64 double dPrevProfileDeepWaterWavePeriod = 0;
65 double dNextProfileDeepWaterWaveHeight = 0;
66 double dNextProfileDeepWaterWaveAngle = 0;
67 double dNextProfileDeepWaterWavePeriod = 0;
68 double dDist = 0;
69
70 for (int nPoint = 0; nPoint < m_VCoast[nCoast].nGetCoastlineSize(); nPoint++)
71 {
72 // We are going down-coast (i.e. along the coast in the direction of increasing coastline point numbers)
73 if (m_VCoast[nCoast].bIsProfileAtCoastPoint(nPoint))
74 {
75 // OK, a coastline-normal profile begins at this coastline point, so set the deep water wave values at this coastline point to be the values at the seaward end of the coastline normal
76 CGeomProfile const* pProfile = m_VCoast[nCoast].pGetProfileAtCoastPoint(nPoint);
77 // int nProfile = pProfile->nGetProfileID();
78
79 double const dThisDeepWaterWaveHeight = pProfile->dGetProfileDeepWaterWaveHeight();
80 double const dThisDeepWaterWaveAngle = pProfile->dGetProfileDeepWaterWaveAngle();
81 double const dThisDeepWaterWavePeriod = pProfile->dGetProfileDeepWaterWavePeriod();
82
83 m_VCoast[nCoast].SetCoastDeepWaterWaveHeight(nPoint, dThisDeepWaterWaveHeight);
84 m_VCoast[nCoast].SetCoastDeepWaterWaveAngle(nPoint, dThisDeepWaterWaveAngle);
85 m_VCoast[nCoast].SetCoastDeepWaterWavePeriod(nPoint, dThisDeepWaterWavePeriod);
86
87 // Reset for next time
88 nDistFromPrevProfile = 0;
89 dPrevProfileDeepWaterWaveHeight = dThisDeepWaterWaveHeight;
90 dPrevProfileDeepWaterWaveAngle = dThisDeepWaterWaveAngle;
91 dPrevProfileDeepWaterWavePeriod = dThisDeepWaterWavePeriod;
92
93 // Find the next profile
94 CGeomProfile const* pNextProfile = pProfile->pGetDownCoastAdjacentProfile();
95
96 if (pNextProfile == NULL)
97 {
98 // We are at the end of the coast
99 break;
100 }
101
102 // And the distance (in along-coast points) to the next profile
103 nDistToNextProfile = pNextProfile->nGetCoastPoint() - nPoint;
104 dDist = nDistToNextProfile;
105
106 // And the next profile's deep water wave values
107 dNextProfileDeepWaterWaveHeight = pNextProfile->dGetProfileDeepWaterWaveHeight();
108 dNextProfileDeepWaterWaveAngle = pNextProfile->dGetProfileDeepWaterWaveAngle();
109 dNextProfileDeepWaterWavePeriod = pNextProfile->dGetProfileDeepWaterWavePeriod();
110
111 // LogStream << m_ulIter << ": coast point = " << nPoint << " is start of profile " << pProfile->nGetProfileID() << ", next profile is " << pNextProfile->nGetProfileID() << ", which starts at coast piint " << pNextProfile->nGetCoastPoint() << ", dThisDeepWaterWaveHeight = " << dThisDeepWaterWaveHeight << ", dThisDeepWaterWaveAngle = " << dThisDeepWaterWaveAngle << " nDistToNextProfile = " << nDistToNextProfile << endl;
112 }
113 else
114 {
115 // This coast point is not the start of a coastline normal, so set the deep water wave values at this coastline point to be a weighted average of those from the up-coast and down-coast profiles
116 nDistFromPrevProfile++;
117 nDistToNextProfile--;
118
119 double const dPrevWeight = (dDist - nDistFromPrevProfile) / dDist;
120 double const dNextWeight = (dDist - nDistToNextProfile) / dDist;
121 double const dThisDeepWaterWaveHeight = (dPrevWeight * dPrevProfileDeepWaterWaveHeight) + (dNextWeight * dNextProfileDeepWaterWaveHeight);
122 double const dThisDeepWaterWaveAngle = dKeepWithin360((dPrevWeight * dPrevProfileDeepWaterWaveAngle) + (dNextWeight * dNextProfileDeepWaterWaveAngle));
123 double const dThisDeepWaterWavePeriod = (dPrevWeight * dPrevProfileDeepWaterWavePeriod) + (dNextWeight * dNextProfileDeepWaterWavePeriod);
124
125 m_VCoast[nCoast].SetCoastDeepWaterWaveHeight(nPoint, dThisDeepWaterWaveHeight);
126 m_VCoast[nCoast].SetCoastDeepWaterWaveAngle(nPoint, dThisDeepWaterWaveAngle);
127 m_VCoast[nCoast].SetCoastDeepWaterWavePeriod(nPoint, dThisDeepWaterWavePeriod);
128
129 // LogStream << m_ulIter << ": coast point = " << nPoint << " dThisDeepWaterWaveHeight = " << dThisDeepWaterWaveHeight << " dThisDeepWaterWaveAngle = " << dThisDeepWaterWaveAngle << " nDistFromPrevProfile = " << nDistFromPrevProfile << " nDistToNextProfile = " << nDistToNextProfile << endl;
130 }
131 }
132 }
133
134 return RTN_OK;
135}
136
137//===============================================================================================================================
142//===============================================================================================================================
143void CSimulation::GenerateSyntheticTransects(vector<TransectWaveData> const* pVRealTransects, vector<TransectWaveData>* pVAllTransects)
144{
145 // Start with all the real transects
146 *pVAllTransects = *pVRealTransects;
147
148 // If no spacing specified or spacing is too large, just return the real ones
150 return;
151
152 int const nNumRealTransects = static_cast<int>(pVRealTransects->size());
153 if (nNumRealTransects < 2)
154 return;
155
156 // ============================================================================
157 // OPTIMIZATION: Pre-compute external CRS positions for all transect start points
158 // This avoids redundant coordinate conversions (each transect appears in 2 pairs)
159 // ============================================================================
160 vector<double> VdTransectExtX(nNumRealTransects);
161 vector<double> VdTransectExtY(nNumRealTransects);
162
163 for (int i = 0; i < nNumRealTransects; i++)
164 {
165 TransectWaveData const& transect = (*pVRealTransects)[i];
166 if (!transect.VdX.empty())
167 {
168 VdTransectExtX[i] = dGridCentroidXToExtCRSX(static_cast<int>(transect.VdX[0]));
169 VdTransectExtY[i] = dGridCentroidYToExtCRSY(static_cast<int>(transect.VdY[0]));
170 }
171 else
172 {
173 VdTransectExtX[i] = 0.0;
174 VdTransectExtY[i] = 0.0;
175 }
176 }
177
178 // First pass: calculate distances and determine how many synthetic transects needed for each pair
179 vector<int> VnNumSyntheticsPerPair(nNumRealTransects - 1, 0);
180 int nTotalSynthetic = 0;
181
182 for (int nPair = 0; nPair < nNumRealTransects - 1; nPair++)
183 {
184 TransectWaveData const& transect1 = (*pVRealTransects)[nPair];
185 TransectWaveData const& transect2 = (*pVRealTransects)[nPair + 1];
186
187 // Only interpolate between transects on the same coast
188 if (transect1.nCoastID != transect2.nCoastID)
189 continue;
190
191 // Skip if either transect has no points
192 if (transect1.VdX.empty() || transect2.VdX.empty())
193 continue;
194
195 // Use pre-computed external CRS positions
196 double const dX1 = VdTransectExtX[nPair];
197 double const dY1 = VdTransectExtY[nPair];
198 double const dX2 = VdTransectExtX[nPair + 1];
199 double const dY2 = VdTransectExtY[nPair + 1];
200
201 // Calculate distance using pre-computed positions
202 double const dDX = dX2 - dX1;
203 double const dDY = dY2 - dY1;
204 double const dDistance = sqrt(dDX * dDX + dDY * dDY);
205
206 // Calculate number of synthetic transects needed: distance / spacing, rounded to nearest integer
207 // If distance <= spacing, we don't add any synthetic transects
208 int nNumSynthetics = 0;
209 if (dDistance > m_dSyntheticTransectSpacing)
210 {
211 nNumSynthetics = static_cast<int>(round(dDistance / m_dSyntheticTransectSpacing));
212 // Subtract 1 because we already have the two endpoints (real transects)
213 nNumSynthetics = std::max(0, nNumSynthetics - 1);
214 }
215
216 VnNumSyntheticsPerPair[nPair] = nNumSynthetics;
217 nTotalSynthetic += nNumSynthetics;
218 }
219
220 if (nTotalSynthetic <= 0)
221 {
222 LogStream << m_ulIter << ": No synthetic transects needed (all profile spacings <= " << m_dSyntheticTransectSpacing << " m)" << endl;
223 return;
224 }
225
226 // Pre-allocate space for synthetic transects
227 vector<TransectWaveData> VSyntheticTransects(nTotalSynthetic);
228
229 // Second pass: generate the synthetic transects
230 // Using OpenMP to parallelize - each thread handles one pair
231 // int nCurrentIndex = 0;
232
233 #pragma omp parallel for schedule(dynamic)
234 for (int nPair = 0; nPair < nNumRealTransects - 1; nPair++)
235 {
236 int const nNumSynthetics = VnNumSyntheticsPerPair[nPair];
237 if (nNumSynthetics == 0)
238 continue;
239
240 TransectWaveData const& transect1 = (*pVRealTransects)[nPair];
241 TransectWaveData const& transect2 = (*pVRealTransects)[nPair + 1];
242
243 // Calculate the starting index for this pair's synthetic transects
244 int nPairStartIndex = 0;
245 for (int i = 0; i < nPair; i++)
246 nPairStartIndex += VnNumSyntheticsPerPair[i];
247
248 // Create synthetic transects for this pair
249 for (int nSynth = 1; nSynth <= nNumSynthetics; nSynth++)
250 {
251 int const nSynthIndex = nPairStartIndex + (nSynth - 1);
252 TransectWaveData& synthTransect = VSyntheticTransects[nSynthIndex];
253
254 // Calculate interpolation weight (0 < alpha < 1)
255 double const dAlpha = static_cast<double>(nSynth) / (nNumSynthetics + 1);
256 double const dOneMinusAlpha = 1.0 - dAlpha;
257
258 // Set metadata for synthetic transect
259 synthTransect.nCoastID = transect1.nCoastID;
260 synthTransect.nProfileID = -1; // Mark as synthetic
261 synthTransect.bIsGridEdge = false;
262
263 // Interpolate points - use the minimum length to avoid extrapolation
264 size_t const nMinLength = std::min(transect1.VdX.size(), transect2.VdX.size());
265
266 // Reserve space for efficiency
267 synthTransect.VdX.reserve(nMinLength);
268 synthTransect.VdY.reserve(nMinLength);
269 synthTransect.VdHeightX.reserve(nMinLength);
270 synthTransect.VdHeightY.reserve(nMinLength);
271 synthTransect.VbBreaking.reserve(nMinLength);
272
273 // Interpolate each point along the transect
274 for (size_t i = 0; i < nMinLength; i++)
275 {
276 // Linear interpolation of position
277 synthTransect.VdX.push_back(dOneMinusAlpha * transect1.VdX[i] + dAlpha * transect2.VdX[i]);
278 synthTransect.VdY.push_back(dOneMinusAlpha * transect1.VdY[i] + dAlpha * transect2.VdY[i]);
279
280 // Linear interpolation of wave height components
281 synthTransect.VdHeightX.push_back(dOneMinusAlpha * transect1.VdHeightX[i] + dAlpha * transect2.VdHeightX[i]);
282 synthTransect.VdHeightY.push_back(dOneMinusAlpha * transect1.VdHeightY[i] + dAlpha * transect2.VdHeightY[i]);
283
284 // Breaking status: true if either parent transect has breaking at this point
285 synthTransect.VbBreaking.push_back(transect1.VbBreaking[i] || transect2.VbBreaking[i]);
286 }
287 }
288 }
289
290 // Append all synthetic transects to the output vector
291 pVAllTransects->insert(pVAllTransects->end(), VSyntheticTransects.begin(), VSyntheticTransects.end());
292
293 LogStream << m_ulIter << ": Generated " << nTotalSynthetic << " synthetic transects between " << nNumRealTransects << " real transects (target spacing: " << m_dSyntheticTransectSpacing << " m)" << endl;
294}
295
296//===============================================================================================================================
298//===============================================================================================================================
300{
301 // Set up vector to hold wave data for each transect/profile
302 vector<TransectWaveData> VAllTransects;
303 // DEBUG CODE ============================================================================================================
304 LogStream << m_ulIter << ":\t At start of nDoAllPropagateWaves()" << endl;
305 // DEBUG CODE ============================================================================================================
306
307 // Set up all-profile vectors to hold the wave attribute data at every profile point on all profiles
308 vector<bool> VbBreakingAll;
309
310 vector<double> VdXAll;
311 vector<double> VdYAll;
312 vector<double> VdHeightXAll;
313 vector<double> VdHeightYAll;
314
315 // Calculate wave properties for every coast
316 bool bSomeNonStartOrEndOfCoastProfiles = false;
317
318 for (int nCoast = 0; nCoast < static_cast<int>(m_VCoast.size()); nCoast++)
319 {
320 int const nCoastSize = m_VCoast[nCoast].nGetCoastlineSize();
321 int const nNumProfiles = m_VCoast[nCoast].nGetNumProfiles();
322
323 static bool bDownCoast = true;
324
325 // Calculate wave properties at every point along each valid profile, and for the cells under the profiles. Do this alternately in up-coast and down-coast sequence
326 for (int nn = 0; nn < nNumProfiles; nn++)
327 {
328 TransectWaveData transect;
329
330 CGeomProfile *pProfile;
331
332 if (bDownCoast)
333 pProfile = m_VCoast[nCoast].pGetProfileWithDownCoastSeq(nn);
334 else
335 pProfile = m_VCoast[nCoast].pGetProfileWithUpCoastSeq(nn);
336
337 int const nRet = nCalcWavePropertiesOnProfile(nCoast, nCoastSize, pProfile, &transect.VdX, &transect.VdY, &transect.VdHeightX, &transect.VdHeightY, &transect.VbBreaking);
338
339 if (nRet != RTN_OK)
340 {
341 if (nRet == RTN_ERR_CSHORE_ERROR)
342 {
343 // Abandon calculations on this profile, and flag the profile
344 pProfile->SetCShoreProblem(true);
345
346 // Move on to next profile
347 continue;
348 }
349 else
350 {
351 // A serious CShore error, so abort the run
352 return nRet;
353 }
354 }
355
356 // Are the waves off-shore? If so, do nothing more with this profile. The wave values for cells have already been given the off-shore value
357 if (transect.VbBreaking.empty())
358 continue;
359
360 // Is this a start of coast or end of coast profile?
361 if (! pProfile->bIsGridEdge())
362 {
363 // It is neither a start of coast or an end of coast profile, so set switch
364 bSomeNonStartOrEndOfCoastProfiles = true;
365 }
366
367 // Store metadata about this transect
368 transect.nCoastID = nCoast;
369 transect.nProfileID = pProfile->nGetProfileID();
370 transect.bIsGridEdge = pProfile->bIsGridEdge();
371
372 // Add this transect to the collection
373 VAllTransects.push_back(std::move(transect));
374 }
375
376 bDownCoast = ! bDownCoast;
377 }
378
379 // OK, do we have some profiles other than start of coast or end of coast profiles in the all-profile vectors? We need to check this, because GDALGridCreate() in nInterpolateWavePropertiesToWithinPolygonCells() does not work if we give it only a start-of-coast or an end-of-coast profile to work with TODO 006 Is this still true?
380 if (! bSomeNonStartOrEndOfCoastProfiles)
381 {
382 LogStream << m_ulIter << ":\t waves are on-shore only, for start and/or end of coast profiles" << endl;
383
384 return RTN_OK;
385 }
386
387 // We need to also send the deepwater points from the edge of the grid to nInterpolateWavePropertiesToWithinPolygonCells(), this is necessary to prevent GDALGridCreate() leaving holes in the interpolated grid when the polygons are far from regular
388 // Store deep water grid edge points separately (not as a transect)
389 vector<double> VdDeepWaterX;
390 vector<double> VdDeepWaterY;
391 vector<double> VdDeepWaterHeightX;
392 vector<double> VdDeepWaterHeightY;
393
394 double dDeepWaterWaveX;
395 double dDeepWaterWaveY;
396
398 {
399 // Just using the same value of deep water wave hehght and angle for all cells
400 dDeepWaterWaveX = m_dAllCellsDeepWaterWaveHeight * sin(m_dAllCellsDeepWaterWaveAngle * PI / 180),
401 dDeepWaterWaveY = m_dAllCellsDeepWaterWaveHeight * cos(m_dAllCellsDeepWaterWaveAngle * PI / 180);
402 }
403
404 for (int nX = 0; nX < m_nXGridSize; nX++)
405 {
406 if (m_pRasterGrid->m_Cell[nX][0].bIsInContiguousSea())
407 {
408 int const nPolyID = m_pRasterGrid->m_Cell[nX][0].nGetPolygonID();
409
410 if (nPolyID == INT_NODATA)
411 {
412 // Not in a polygon
413 VdDeepWaterX.push_back(nX);
414 VdDeepWaterY.push_back(0);
415
417 {
418 // Not using the same value of deep water height and angle for all cells, so get this cell's deep water height and angle values
419 dDeepWaterWaveX = m_pRasterGrid->m_Cell[nX][0].dGetCellDeepWaterWaveHeight() * sin(m_pRasterGrid->m_Cell[nX][0].dGetCellDeepWaterWaveAngle() * PI / 180);
420 dDeepWaterWaveY = m_pRasterGrid->m_Cell[nX][0].dGetCellDeepWaterWaveHeight() * cos(m_pRasterGrid->m_Cell[nX][0].dGetCellDeepWaterWaveAngle() * PI / 180);
421 }
422
423 VdDeepWaterHeightX.push_back(dDeepWaterWaveX);
424 VdDeepWaterHeightY.push_back(dDeepWaterWaveY);
425 }
426 }
427
428 if (m_pRasterGrid->m_Cell[nX][m_nYGridSize - 1].bIsInContiguousSea())
429 {
430 int const nPolyID = m_pRasterGrid->m_Cell[nX][m_nYGridSize - 1].nGetPolygonID();
431
432 if (nPolyID == INT_NODATA)
433 {
434 // Not in a polygon
435 VdDeepWaterX.push_back(nX);
436 VdDeepWaterY.push_back(m_nYGridSize - 1);
437
439 {
440 // Not using the same value of deep water height and angle for all cells, so get this cell's deep water height and angle values
441 dDeepWaterWaveX = m_pRasterGrid->m_Cell[nX][m_nYGridSize - 1].dGetCellDeepWaterWaveHeight() * sin(m_pRasterGrid->m_Cell[nX][m_nYGridSize - 1].dGetCellDeepWaterWaveAngle() * PI / 180);
442 dDeepWaterWaveY = m_pRasterGrid->m_Cell[nX][m_nYGridSize - 1].dGetCellDeepWaterWaveHeight() * cos(m_pRasterGrid->m_Cell[nX][m_nYGridSize - 1].dGetCellDeepWaterWaveAngle() * PI / 180);
443 }
444
445 VdDeepWaterHeightX.push_back(dDeepWaterWaveX);
446 VdDeepWaterHeightY.push_back(dDeepWaterWaveY);
447 }
448 }
449 }
450
451 // DEBUG CODE ============================================================================================================
452 LogStream << m_ulIter << ":\t starting loop" << endl;
453 // DEBUG CODE ============================================================================================================
454
455 for (int nY = 0; nY < m_nYGridSize; nY++)
456 {
457 if (m_pRasterGrid->m_Cell[0][nY].bIsInContiguousSea())
458 {
459 int const nPolyID = m_pRasterGrid->m_Cell[0][nY].nGetPolygonID();
460
461 if (nPolyID == INT_NODATA)
462 {
463 // Not in a polygon
464 VdDeepWaterX.push_back(0);
465 VdDeepWaterY.push_back(nY);
466
468 {
469 // Not using the same value of deep water height and angle for all cells, so get this cell's deep water height and angle values
470 dDeepWaterWaveX = m_pRasterGrid->m_Cell[0][nY].dGetCellDeepWaterWaveHeight() * sin(m_pRasterGrid->m_Cell[0][nY].dGetCellDeepWaterWaveAngle() * PI / 180);
471 dDeepWaterWaveY = m_pRasterGrid->m_Cell[0][nY].dGetCellDeepWaterWaveHeight() * cos(m_pRasterGrid->m_Cell[0][nY].dGetCellDeepWaterWaveAngle() * PI / 180);
472 }
473
474 VdDeepWaterHeightX.push_back(dDeepWaterWaveX);
475 VdDeepWaterHeightY.push_back(dDeepWaterWaveY);
476 }
477 }
478
479 if (m_pRasterGrid->m_Cell[m_nXGridSize - 1][nY].bIsInContiguousSea())
480 {
481 int const nPolyID = m_pRasterGrid->m_Cell[m_nXGridSize - 1][nY].nGetPolygonID();
482
483 if (nPolyID == INT_NODATA)
484 {
485 // Not in a polygon
486 VdDeepWaterX.push_back(m_nXGridSize - 1);
487 VdDeepWaterY.push_back(nY);
488
490 {
491 // Not using the same value of deep water height and angle for all cells, so get this cell's deep water height and angle values
492 dDeepWaterWaveX = m_pRasterGrid->m_Cell[m_nXGridSize - 1][nY].dGetCellDeepWaterWaveHeight() * sin(m_pRasterGrid->m_Cell[m_nXGridSize - 1][nY].dGetCellDeepWaterWaveAngle() * PI / 180);
493 dDeepWaterWaveY = m_pRasterGrid->m_Cell[m_nXGridSize - 1][nY].dGetCellDeepWaterWaveHeight() * cos(m_pRasterGrid->m_Cell[m_nXGridSize - 1][nY].dGetCellDeepWaterWaveAngle() * PI / 180);
494 }
495
496 VdDeepWaterHeightX.push_back(dDeepWaterWaveX);
497 VdDeepWaterHeightY.push_back(dDeepWaterWaveY);
498 }
499 }
500 }
501
502 // Are the waves off-shore for every profile? If so, do nothing more
503 // Check if any transect has breaking waves
504 bool bHasBreakingWaves = false;
505 for (const auto& transect : VAllTransects)
506 {
507 if (!transect.VbBreaking.empty())
508 {
509 bHasBreakingWaves = true;
510 break;
511 }
512 }
513
514 if (!bHasBreakingWaves)
515 {
516 LogStream << m_ulIter << ": waves off-shore for all profiles" << endl;
517 return RTN_OK;
518 }
519
520 // Generate synthetic transects to densify the point cloud for better interpolation
521 vector<TransectWaveData> VAllTransectsWithSynthetic;
522 GenerateSyntheticTransects(&VAllTransects, &VAllTransectsWithSynthetic);
523
524 // Store transects for potential debug output
525 m_VAllTransectsWithSynthetic = VAllTransectsWithSynthetic;
526
527 // Some waves are on-shore, so interpolate the wave attributes from all profile points to all within-polygon sea cells, also update the active zone status for each cell
528 int nRet = nInterpolateWavesToPolygonCells(&VAllTransectsWithSynthetic, &VdDeepWaterX, &VdDeepWaterY, &VdDeepWaterHeightX, &VdDeepWaterHeightY);
529
530 if (nRet != RTN_OK)
531 return nRet;
532
533 // // DEBUG CODE ===========================================================================================================
534 // string strOutFile = m_strOutPath;
535 // strOutFile += "sea_wave_height_CHECKPOINT_1_";
536 // strOutFile += to_string(m_ulIter);
537 // strOutFile += ".tif";
538 //
539 // GDALDriver* pDriver = GetGDALDriverManager()->GetDriverByName("gtiff");
540 // GDALDataset* pDataSet = pDriver->Create(strOutFile.c_str(), m_nXGridSize, m_nYGridSize, 1, GDT_Float64, m_papszGDALRasterOptions);
541 // pDataSet->SetProjection(m_strGDALBasementDEMProjection.c_str());
542 // pDataSet->SetGeoTransform(m_dGeoTransform);
543 //
544 // int nn = 0;
545 // double* pdRaster = new double[m_nXGridSize * m_nYGridSize];
546 // for (int nY = 0; nY < m_nYGridSize; nY++)
547 // {
548 // for (int nX = 0; nX < m_nXGridSize; nX++)
549 // {
550 // pdRaster[nn++] = m_pRasterGrid->m_Cell[nX][nY].dGetWaveHeight();
551 // }
552 // }
553 //
554 // GDALRasterBand* pBand = pDataSet->GetRasterBand(1);
555 // pBand->SetNoDataValue(m_dMissingValue);
556 // nRet = pBand->RasterIO(GF_Write, 0, 0, m_nXGridSize, m_nYGridSize, pdRaster, m_nXGridSize, m_nYGridSize, GDT_Float64, 0, 0, NULL);
557 //
558 // if (nRet == CE_Failure)
559 // return RTN_ERR_GRIDCREATE;
560 //
561 // GDALClose(pDataSet);
562 // delete[] pdRaster;
563 // // DEBUG CODE ===========================================================================================================
564
565 // // DEBUG CODE ===========================================================================================================
566 // strOutFile = m_strOutPath;
567 // strOutFile += "sea_wave_angle_CHECKPOINT_1_";
568 // strOutFile += to_string(m_ulIter);
569 // strOutFile += ".tif";
570 //
571 // pDriver = GetGDALDriverManager()->GetDriverByName("gtiff");
572 // pDataSet = pDriver->Create(strOutFile.c_str(), m_nXGridSize, m_nYGridSize, 1, GDT_Float64, m_papszGDALRasterOptions);
573 // pDataSet->SetProjection(m_strGDALBasementDEMProjection.c_str());
574 // pDataSet->SetGeoTransform(m_dGeoTransform);
575 //
576 // nn = 0;
577 // pdRaster = new double[m_nXGridSize * m_nYGridSize];
578 // for (int nY = 0; nY < m_nYGridSize; nY++)
579 // {
580 // for (int nX = 0; nX < m_nXGridSize; nX++)
581 // {
582 // pdRaster[nn++] = m_pRasterGrid->m_Cell[nX][nY].dGetWaveAngle();
583 // }
584 // }
585 //
586 // pBand = pDataSet->GetRasterBand(1);
587 // pBand->SetNoDataValue(m_dMissingValue);
588 // nRet = pBand->RasterIO(GF_Write, 0, 0, m_nXGridSize, m_nYGridSize, pdRaster, m_nXGridSize, m_nYGridSize, GDT_Float64, 0, 0, NULL);
589 //
590 // if (nRet == CE_Failure)
591 // return RTN_ERR_GRIDCREATE;
592 //
593 // GDALClose(pDataSet);
594 // delete[] pdRaster;
595 // // DEBUG CODE ===========================================================================================================
596
597 // Find any shadow zones and then modify waves in and adjacent to them
598 nRet = nDoAllShadowZones();
599 if (nRet != RTN_OK)
600 return nRet;
601
602 // Calculate the D50 for each polygon. Also fill in any artefactual 'holes' in active zone and wave property patterns
604
605 // // DEBUG CODE ===========================================================================================================
606 // strOutFile = m_strOutPath;
607 // strOutFile += "sea_wave_height_CHECKPOINT_2_";
608 // strOutFile += to_string(m_ulIter);
609 // strOutFile += ".tif";
610 //
611 // pDriver = GetGDALDriverManager()->GetDriverByName("gtiff");
612 // pDataSet = pDriver->Create(strOutFile.c_str(), m_nXGridSize, m_nYGridSize, 1, GDT_Float64, m_papszGDALRasterOptions);
613 // pDataSet->SetProjection(m_strGDALBasementDEMProjection.c_str());
614 // pDataSet->SetGeoTransform(m_dGeoTransform);
615 //
616 // nn = 0;
617 // pdRaster = new double[m_nXGridSize * m_nYGridSize];
618 // for (int nY = 0; nY < m_nYGridSize; nY++)
619 // {
620 // for (int nX = 0; nX < m_nXGridSize; nX++)
621 // {
622 // pdRaster[nn++] = m_pRasterGrid->m_Cell[nX][nY].dGetWaveHeight();
623 // }
624 // }
625 //
626 // pBand = pDataSet->GetRasterBand(1);
627 // pBand->SetNoDataValue(m_dMissingValue);
628 // nRet = pBand->RasterIO(GF_Write, 0, 0, m_nXGridSize, m_nYGridSize, pdRaster, m_nXGridSize, m_nYGridSize, GDT_Float64, 0, 0, NULL);
629 //
630 // if (nRet == CE_Failure)
631 // return RTN_ERR_GRIDCREATE;
632 //
633 // GDALClose(pDataSet);
634 // delete[] pdRaster;
635 // // DEBUG CODE ===========================================================================================================
636
637 // // DEBUG CODE ===========================================================================================================
638 // strOutFile = m_strOutPath;
639 // strOutFile += "sea_wave_angle_CHECKPOINT_2_";
640 // strOutFile += to_string(m_ulIter);
641 // strOutFile += ".tif";
642 //
643 // pDriver = GetGDALDriverManager()->GetDriverByName("gtiff");
644 // pDataSet = pDriver->Create(strOutFile.c_str(), m_nXGridSize, m_nYGridSize, 1, GDT_Float64, m_papszGDALRasterOptions);
645 // pDataSet->SetProjection(m_strGDALBasementDEMProjection.c_str());
646 // pDataSet->SetGeoTransform(m_dGeoTransform);
647 //
648 // nn = 0;
649 // pdRaster = new double[m_nXGridSize * m_nYGridSize];
650 // for (int nY = 0; nY < m_nYGridSize; nY++)
651 // {
652 // for (int nX = 0; nX < m_nXGridSize; nX++)
653 // {
654 // pdRaster[nn++] = m_pRasterGrid->m_Cell[nX][nY].dGetWaveAngle();
655 // }
656 // }
657 //
658 // pBand = pDataSet->GetRasterBand(1);
659 // pBand->SetNoDataValue(m_dMissingValue);
660 // nRet = pBand->RasterIO(GF_Write, 0, 0, m_nXGridSize, m_nYGridSize, pdRaster, m_nXGridSize, m_nYGridSize, GDT_Float64, 0, 0, NULL);
661 //
662 // if (nRet == CE_Failure)
663 // return RTN_ERR_GRIDCREATE;
664 //
665 // GDALClose(pDataSet);
666 // delete[] pdRaster;
667 // // DEBUG CODE ===========================================================================================================
668
669 // Modify the wave breaking properties (wave height, wave dir, breaking depth, breaking distance) for coastline points within the shadow zone
670 for (int nCoast = 0; nCoast < static_cast<int>(m_VCoast.size()); nCoast++)
671 {
672 int const nNumProfiles = m_VCoast[nCoast].nGetNumProfiles();
673
674 for (int nProfile = 0; nProfile < nNumProfiles; nProfile++)
676 }
677
678 // // DEBUG CODE ===========================================================================================================
679 // strOutFile = m_strOutPath;
680 // strOutFile += "sea_wave_height_CHECKPOINT_3_";
681 // strOutFile += to_string(m_ulIter);
682 // strOutFile += ".tif";
683 //
684 // pDriver = GetGDALDriverManager()->GetDriverByName("gtiff");
685 // pDataSet = pDriver->Create(strOutFile.c_str(), m_nXGridSize, m_nYGridSize, 1, GDT_Float64, m_papszGDALRasterOptions);
686 // pDataSet->SetProjection(m_strGDALBasementDEMProjection.c_str());
687 // pDataSet->SetGeoTransform(m_dGeoTransform);
688 //
689 // nn = 0;
690 // pdRaster = new double[m_nXGridSize * m_nYGridSize];
691 // for (int nY = 0; nY < m_nYGridSize; nY++)
692 // {
693 // for (int nX = 0; nX < m_nXGridSize; nX++)
694 // {
695 // pdRaster[nn++] = m_pRasterGrid->m_Cell[nX][nY].dGetWaveHeight();
696 // }
697 // }
698 //
699 // pBand = pDataSet->GetRasterBand(1);
700 // pBand->SetNoDataValue(m_dMissingValue);
701 // nRet = pBand->RasterIO(GF_Write, 0, 0, m_nXGridSize, m_nYGridSize, pdRaster, m_nXGridSize, m_nYGridSize, GDT_Float64, 0, 0, NULL);
702 //
703 // if (nRet == CE_Failure)
704 // return RTN_ERR_GRIDCREATE;
705 //
706 // GDALClose(pDataSet);
707 // delete[] pdRaster;
708 // // DEBUG CODE ===========================================================================================================
709
710 // // DEBUG CODE ===========================================================================================================
711 // strOutFile = m_strOutPath;
712 // strOutFile += "sea_wave_angle_CHECKPOINT_3_";
713 // strOutFile += to_string(m_ulIter);
714 // strOutFile += ".tif";
715 //
716 // pDriver = GetGDALDriverManager()->GetDriverByName("gtiff");
717 // pDataSet = pDriver->Create(strOutFile.c_str(), m_nXGridSize, m_nYGridSize, 1, GDT_Float64, m_papszGDALRasterOptions);
718 // pDataSet->SetProjection(m_strGDALBasementDEMProjection.c_str());
719 // pDataSet->SetGeoTransform(m_dGeoTransform);
720 //
721 // nn = 0;
722 // pdRaster = new double[m_nXGridSize * m_nYGridSize];
723 // for (int nY = 0; nY < m_nYGridSize; nY++)
724 // {
725 // for (int nX = 0; nX < m_nXGridSize; nX++)
726 // {
727 // pdRaster[nn++] = m_pRasterGrid->m_Cell[nX][nY].dGetWaveAngle();
728 // }
729 // }
730 //
731 // pBand = pDataSet->GetRasterBand(1);
732 // pBand->SetNoDataValue(m_dMissingValue);
733 // nRet = pBand->RasterIO(GF_Write, 0, 0, m_nXGridSize, m_nYGridSize, pdRaster, m_nXGridSize, m_nYGridSize, GDT_Float64, 0, 0, NULL);
734 //
735 // if (nRet == CE_Failure)
736 // return RTN_ERR_GRIDCREATE;
737 //
738 // GDALClose(pDataSet);
739 // delete[] pdRaster;
740 // // DEBUG CODE ===========================================================================================================
741
742 // Interpolate these wave properties for all remaining coastline points. Do this in along-coastline sequence
743 for (int nCoast = 0; nCoast < static_cast<int>(m_VCoast.size()); nCoast++)
744 {
745 int const nCoastSize = m_VCoast[nCoast].nGetCoastlineSize();
746 int const nNumProfiles = m_VCoast[nCoast].nGetNumProfiles();
747
748 // Interpolate these wave properties for all remaining coastline points. Do this in along-coastline sequence, but do not do this for the end-of-coastline profile (which is the final one)
749 for (int n = 0; n < nNumProfiles - 1; n++)
751
752 // And do the same for the coastline cells
754
755 // Calculate wave energy at breaking for every point on the coastline
756 for (int nCoastPoint = 0; nCoastPoint < nCoastSize; nCoastPoint++)
757 {
758 // Equation 4 from Walkden & Hall, 2005
759 double const dBreakingWaveHeight = m_VCoast[nCoast].dGetBreakingWaveHeight(nCoastPoint);
760 double const dCoastPointWavePeriod = m_VCoast[nCoast].dGetCoastDeepWaterWavePeriod(nCoastPoint);
761
762 // TODO 080 Why do we get -ve dBreakingWaveHeight here?
763 if (bFPIsEqual(dBreakingWaveHeight, DBL_NODATA, TOLERANCE))
764 {
765 m_VCoast[nCoast].SetBreakingWaveHeight(nCoastPoint, 0);
766 }
767
768 else
769 {
770 double const dErosiveWaveForce = pow(dBreakingWaveHeight, WALKDEN_HALL_PARAM_1) * pow(dCoastPointWavePeriod, WALKDEN_HALL_PARAM_2);
771
772 // Calculate total wave energy at this coast point during this timestep
773 double const dWaveEnergy = dErosiveWaveForce * m_dTimeStep * 3600;
774 m_VCoast[nCoast].SetWaveEnergyAtBreaking(nCoastPoint, dWaveEnergy);
775 }
776 }
777 }
778
779 return RTN_OK;
780}
781
782//===============================================================================================================================
784//===============================================================================================================================
785double CSimulation::dCalcWaveAngleToCoastNormal(double const dCoastAngle, double const dWaveAngle, int const nSeaHand)
786{
787 double dWaveToNormalAngle = 0;
788
789 if (nSeaHand == LEFT_HANDED)
790 // Left-handed coast
791 dWaveToNormalAngle = fmod((dWaveAngle - dCoastAngle + 360), 360) - 90;
792
793 else
794 // Right-handed coast
795 dWaveToNormalAngle = fmod((dWaveAngle - dCoastAngle + 360), 360) - 270;
796
797 if ((dWaveToNormalAngle >= 90) || (dWaveToNormalAngle <= -90))
798 dWaveToNormalAngle = DBL_NODATA;
799
800 return dWaveToNormalAngle;
801}
802
803//===============================================================================================================================
805//===============================================================================================================================
806int CSimulation::nCalcWavePropertiesOnProfile(int const nCoast, int const nCoastSize, CGeomProfile *pProfile, vector<double> *pVdX, vector<double> *pVdY, vector<double> *pVdHeightX, vector<double> *pVdHeightY, vector<bool> *pVbBreaking)
807{
808 // Only do this for profiles without problems. Still do start- and end-of-coast profiles however
809 if (! pProfile->bOKIncStartAndEndOfCoast())
810 {
811 // if (m_nLogFileDetail >= LOG_FILE_ALL)
812 // LogStream << m_ulIter << ": coast " << nCoast << ", profile " << nProfile << " has been marked invalid, will not calc wave properties on this profile" << endl;
813
814 return RTN_OK;
815 }
816
817 // Calculate some wave properties based on the wave period following Airy wave theory
818 double const dDeepWaterWavePeriod = pProfile->dGetProfileDeepWaterWavePeriod();
819
820 m_dC_0 = (m_dG * dDeepWaterWavePeriod) / (2 * PI); // Deep water (offshore) wave celerity (m/s)
821 m_dL_0 = m_dC_0 * dDeepWaterWavePeriod; // Deep water (offshore) wave length (m)
822
823 int const nSeaHand = m_VCoast[nCoast].nGetSeaHandedness();
824 int const nCoastPoint = pProfile->nGetCoastPoint();
825
826 // Get the flux orientation (the orientation of a line which is tangential to the coast) at adjacent coastline points. Note special treatment for the coastline end points
827 double const dFluxOrientationThis = m_VCoast[nCoast].dGetFluxOrientation(nCoastPoint);
828 double dFluxOrientationPrev = 0;
829 double dFluxOrientationNext = 0;
830
831 if (nCoastPoint == 0)
832 {
833 dFluxOrientationPrev = dFluxOrientationThis;
834 dFluxOrientationNext = m_VCoast[nCoast].dGetFluxOrientation(1);
835 }
836 else if (nCoastPoint == nCoastSize - 1)
837 {
838 dFluxOrientationPrev = m_VCoast[nCoast].dGetFluxOrientation(nCoastPoint - 2);
839 dFluxOrientationNext = dFluxOrientationThis;
840 }
841 else
842 {
843 dFluxOrientationPrev = m_VCoast[nCoast].dGetFluxOrientation(nCoastPoint - 1);
844 dFluxOrientationNext = m_VCoast[nCoast].dGetFluxOrientation(nCoastPoint + 1);
845 }
846
847 // Get the deep water wave orientation for this profile
848 double const dDeepWaterWaveAngle = pProfile->dGetProfileDeepWaterWaveAngle();
849
850 // Calculate the angle between the deep water wave direction and a normal to the coast tangent
851 double dWaveToNormalAngle = dCalcWaveAngleToCoastNormal(dFluxOrientationThis, dDeepWaterWaveAngle, nSeaHand);
852
853 // Are the waves off-shore?
854 if (bFPIsEqual(dWaveToNormalAngle, DBL_NODATA, TOLERANCE))
855 {
856 // They are so, do nothing (each cell under the profile has already been initialised with deep water wave height and wave direction)
857 // LogStream << m_ulIter << ": profile " << nProfile << " has sea to " << (m_VCoast[nCoast].nGetSeaHandedness() == RIGHT_HANDED ? "right" : "left") << " dWaveToNormalAngle = " << dWaveToNormalAngle << " which is off-shore" << endl;
858
859 return RTN_OK;
860 }
861
862 // LogStream << m_ulIter << ": profile = " << nProfile << " has sea to " << (m_VCoast[nCoast].nGetSeaHandedness() == RIGHT_HANDED ? "right" : "left") << " dWaveToNormalAngle = " << dWaveToNormalAngle << " which is " << (dWaveToNormalAngle < 0 ? "DOWN" : "UP") << "-coast" << endl;
863
864 // Calculate the angle between the deep water wave direction and a normal to the coast tangent for the previous coast point
865 double dWaveToNormalAnglePrev;
866
867 if (nCoastPoint > 0)
868 {
869 // Get the deep water wave orientation for the up-coast point
870 double const dPrevDeepWaterWaveAngle = m_VCoast[nCoast].dGetCoastDeepWaterWaveAngle(nCoastPoint - 1);
871
872 dWaveToNormalAnglePrev = dCalcWaveAngleToCoastNormal(dFluxOrientationPrev, dPrevDeepWaterWaveAngle, nSeaHand);
873 }
874 else
875 {
876 dWaveToNormalAnglePrev = dWaveToNormalAngle;
877 }
878
879 // if (dWaveToNormalAnglePrev == DBL_NODATA)
880 // LogStream << "\tPrevious profile, dWaveToNormalAnglePrev = " << dWaveToNormalAnglePrev << " which is off-shore" << endl;
881 // else
882 // LogStream << "\tPrevious profile, dWaveToNormalAnglePrev = " << dWaveToNormalAnglePrev << " which is " << (dWaveToNormalAnglePrev < 0 ? "DOWN" : "UP") << "-coast" << endl;
883
884 // Calculate the angle between the deep water wave direction and a normal to the coast tangent for the next coast point
885 double dWaveToNormalAngleNext;
886
887 if (nCoastPoint < nCoastSize - 1)
888 {
889 // Get the deep water wave orientation for the down-coast point
890 double const dNextDeepWaterWaveAngle = m_VCoast[nCoast].dGetCoastDeepWaterWaveAngle(nCoastPoint + 1);
891
892 dWaveToNormalAngleNext = dCalcWaveAngleToCoastNormal(dFluxOrientationNext, dNextDeepWaterWaveAngle, nSeaHand);
893 }
894 else
895 {
896 dWaveToNormalAngleNext = dWaveToNormalAngle;
897 }
898
899 // if (dWaveToNormalAngleNext == DBL_NODATA)
900 // LogStream << "\tNext profile, dWaveToNormalAngleNext = " << dWaveToNormalAngleNext << " which is off-shore" << endl;
901 // else
902 // LogStream << "\tNext profile, dWaveToNormalAngleNext = " << dWaveToNormalAngleNext << " which is " << (dWaveToNormalAngleNext < 0 ? "DOWN" : "UP") << "-coast" << endl;
903
904 // Following Ashton and Murray (2006), if we have high-angle waves then use the flux orientation of the previous (up-coast) profile, if transitioning from diffusive to antidiffusive use flux maximizing angle (45 degrees)
905 if ((dWaveToNormalAngle > 0) && (! bFPIsEqual(dWaveToNormalAnglePrev, DBL_NODATA, TOLERANCE)) && (dWaveToNormalAnglePrev > 0))
906 {
907 if (dWaveToNormalAngle > 45)
908 {
909 if (dWaveToNormalAnglePrev < 45)
910 {
911 dWaveToNormalAngle = 45;
912 // LogStream << "\tA1" << endl;
913 }
914 else
915 {
916 dWaveToNormalAngle = dWaveToNormalAnglePrev;
917 // LogStream << "\tA2" << endl;
918 }
919 }
920 }
921 else if ((dWaveToNormalAngle < 0) && (! bFPIsEqual(dWaveToNormalAngleNext, DBL_NODATA, TOLERANCE)) && (dWaveToNormalAngleNext < 0))
922 {
923 if (dWaveToNormalAngle < -45)
924 {
925 if (dWaveToNormalAngleNext > -45)
926 {
927 dWaveToNormalAngle = -45;
928 // LogStream << "\tB1" << endl;
929 }
930 else
931 {
932 dWaveToNormalAngle = dWaveToNormalAngleNext;
933 // LogStream << "\tB2" << endl;
934 }
935 }
936 }
937 else if ((dWaveToNormalAngle > 45) && (! bFPIsEqual(dWaveToNormalAnglePrev, DBL_NODATA, TOLERANCE)) && (dWaveToNormalAnglePrev > 0))
938 {
939 // The wave direction here has an up-coast (decreasing indices) component: so for high-angle waves use the orientation from the up-coast (previous) profile
940 // LogStream << "\tCCC" << endl;
941
942 dWaveToNormalAngle = dFluxOrientationPrev;
943 }
944 else if ((dWaveToNormalAngle < -45) && (! bFPIsEqual(dWaveToNormalAngleNext, DBL_NODATA, TOLERANCE)) && (dWaveToNormalAngleNext < 0))
945 {
946 // The wave direction here has a down-coast (increasing indices) component: so for high-angle waves use the orientation from the down-coast (next) profile
947 // LogStream << "\tDDD" << endl;
948
949 dWaveToNormalAngle = dFluxOrientationNext;
950 }
951
952 // Initialize the wave properties at breaking for this profile
953 bool bBreaking = false;
954
955 int const nProfileSize = pProfile->nGetNumCellsInProfile();
956 int nProfileBreakingDist = 0;
957
958 double dProfileBreakingWaveHeight = DBL_NODATA;
959 double dProfileBreakingWaveAngle = 0;
960 double dProfileBreakingDepth = 0;
961 double dProfileWaveHeight = DBL_NODATA;
962 double const dProfileDeepWaterWaveHeight = pProfile->dGetProfileDeepWaterWaveHeight();
963 double dProfileWaveAngle = DBL_NODATA;
964 double const dProfileDeepWaterWaveAngle = pProfile->dGetProfileDeepWaterWaveAngle();
965
966 vector<bool> VbWaveIsBreaking(nProfileSize, 0);
967
968 vector<double> VdWaveHeight(nProfileSize, 0);
969 vector<double> VdWaveSetupSurge(nProfileSize, 0);
970 // vector<double> VdStormSurge(nProfileSize, 0);
971 vector<double> const VdWaveSetupRunUp(nProfileSize, 0);
972 vector<double> VdWaveDirection(nProfileSize, 0);
973
975 {
976 // We are using CShore to propagate the waves
977 double const dCShoreTimeStep = 3600; // In seconds, not important because we are not using CShore to erode the profile, just to get the hydrodynamics
978 double const dSurgeLevel = CSHORE_SURGE_LEVEL;
979
980 // Set up vectors for the coastline-normal profile elevations. The length of this vector line is given by the number of cells 'under' the profile. Thus each point on the vector relates to a single cell in the grid. This assumes that all points on the profile vector are equally spaced (not quite true, depends on the orientation of the line segments which comprise the profile)
981 vector<double> VdProfileZ; // Initial (pre-erosion) elevation of both consolidated and unconsolidated sediment for cells 'under' the profile, in CShore units
982 vector<double> VdProfileDistXY; // Along-profile distance measured from the seaward limit, in CShore units
983 vector<double> VdProfileFrictionFactor; // Along-profile friction factor from seaward limit
984
985 // The elevation of each of these profile points is the elevation of the centroid of the cell that is 'under' the point. However we cannot always be confident that this is the 'true' elevation of the point on the vector since (unless the profile runs planview N-S or W-E) the vector does not always run exactly through the centroid of the cell
986 int nRet = nGetThisProfileElevationsForCShore(nCoast, pProfile, nProfileSize, &VdProfileDistXY, &VdProfileZ, &VdProfileFrictionFactor);
987
988 if (nRet != RTN_OK)
989 {
990 // Could not create the profile elevation vectors
991 LogStream << m_ulIter << ": \tcoast " << nCoast << " could not create CShore profile elevation vectors for profile " << pProfile->nGetProfileID() << endl;
992
993 return nRet;
994 }
995
996 // assert(static_cast<int>(VdProfileDistXY.size()) == nProfileSize);
997 // assert(static_cast<int>(VdProfileZ.size()) == nProfileSize);
998 // assert(static_cast<int>(VdProfileFrictionFactor.size()) == nProfileSize);
999
1000 if (VdProfileDistXY.empty())
1001 {
1002 // The profile elevation vector was created, but was not populated
1003 LogStream << m_ulIter << ": \tcoast " << nCoast << " could not populate CShore profile elevation vector for profile " << pProfile->nGetProfileID() << endl;
1004
1006 }
1007
1008 // Constrain the wave to normal angle to be between -80 and 80 degrees, this is a requirement of CShore
1009 dWaveToNormalAngle = tMax(dWaveToNormalAngle, -80.0);
1010 dWaveToNormalAngle = tMin(dWaveToNormalAngle, 80.0);
1011
1012 int const nProfileDistXYSize = static_cast<int>(VdProfileDistXY.size());
1013 vector<double> VdFreeSurfaceStd(nProfileDistXYSize, 0); // This is converted to Hrms by Hrms = sqr(8)*FreeSurfaceStd
1014 vector<double> VdSinWaveAngleRadians(nProfileDistXYSize, 0); // This is converted to deg by asin(VdSinWaveAngleRadians)*(180/pi)
1015 vector<double> VdFractionBreakingWaves(nProfileDistXYSize, 0); // Is 0 if no wave breaking, and 1 if all waves breaking
1016
1017 // Now define the other values that CShore requires
1018 int const nILine = 1; // This is the number of cross-shore lines i.e. the number of CoastalME profiles. Only one at a time, at present
1019 int const nIProfl = 0; // 0 for fixed bottom profile, 1 for profile evolution computation
1020 int const nIPerm = 0; // 0 for impermeable bottom, 1 for permeable bottom of stone structure
1021 int const nIOver = 0; // 0 for no wave overtopping and overflow on crest, 1 for wave overtopping and overflow
1022 int const nIWCInt = 0; // 0 for no wave/current interaction, 1 for wave/current interaction in frequency dispersion, momentum and wave action equations
1023 int const nIRoll = 0; // 0 for no roller effects, 1 for roller effects in governing equations
1024 int const nIWind = 0; // 0 for no wind effects, 1 for wind shear stresses on momentum equations
1025 int const nITide = 0; // 0 for no tidal effect on currents, 1 for longshore and cross-shore tidal currents
1026 int const nILab = 0; // 0 for field data set, 1 for laboratory data set
1027 int const nNWave = 1; // Number of waves at x = 0 starting from time = 0
1028 int const nNSurge = 1; // Number of water levels at x = 0 from time = 0
1029 double const dDX = VdProfileDistXY.back() / (static_cast<double>(VdProfileDistXY.size() - 1));
1030 double const dWaveInitTime = 0; // CShore wave start time
1031 double const dSurgeInitTime = 0; // CShore surge start time
1032
1033#if defined CSHORE_FILE_INOUT || CSHORE_BOTH
1034 // Move to the CShore folder
1035 nRet = chdir(CSHORE_DIR.c_str());
1036
1037 if (nRet != RTN_OK)
1038 return nRet;
1039
1040#endif
1041
1042#if defined CSHORE_FILE_INOUT
1043 // We are communicating with CShore using ASCII files, so create an input file for this profile which will be read by CShore
1044 nRet = nCreateCShoreInfile(nCoast, nProfile, nILine, nIProfl, nIPerm, nIOver, nIWCInt, nIRoll, nIWind, nITide, nILab, nNWave, nNSurge, dDX, dCShoreTimeStep, dWaveInitTime, dDeepWaterWavePeriod, dProfileDeepWaterWaveHeight, dWaveToNormalAngle, dSurgeInitTime, dSurgeLevel, &VdProfileDistXY, &VdProfileZ, &VdProfileFrictionFactor);
1045
1046 if (nRet != RTN_OK)
1047 return nRet;
1048
1049 // Set the error flag: this will be changed to 0 within CShore if CShore returns correctly
1050 nRet = -1;
1051
1052 // Run CShore for this profile
1053 CShore(&nRet);
1054 // CShore(&nRet, &m_ulIter, &nProfile, &nProfile);
1055
1056 // Check return code for error
1057 if (nRet != 0)
1058 {
1059 string strErr = to_string(m_ulIter) + ": \tcoast " + to_string(nCoast) + " profile " + to_string(pProfile->nGetProfileID()) + " profile length " + to_string(nOutSize) + " ";
1060
1061 switch (nRet)
1062 {
1063 case -1:
1064 strErr += "CShore WARNING 1: negative depth at the first node";
1065 break;
1066
1067 case 2:
1068 strErr += "CShore WARNING 2: negative value at end of landward marching computation";
1069 break;
1070
1071 case 3:
1072 strErr += "CShore WARNING 3: large energy gradients at the first node: small waves with short period at sea boundary";
1073 break;
1074
1075 case 4:
1076 strErr += "CShore WARNING 4: zero energy at the first node";
1077 break;
1078
1079 case 5:
1080 strErr += "CShore WARNING 5: at end of landward marching computation, insufficient water depth";
1081 break;
1082
1083 case 7:
1084 strErr += "CShore WARNING 7: did not reach convergence";
1085 break;
1086 }
1087
1088 strErr += "\n";
1089
1090 // OK, give up for this profile
1091 // LogStream << strErr;
1092 //
1093 // return RTN_ERR_CSHORE_ERROR;
1094 }
1095
1096 // Fetch the CShore results by reading files written by CShore
1097 string strOSETUP = "OSETUP";
1098 string strOYVELO = "OYVELO";
1099 string strOPARAM = "OPARAM";
1100
1101 nRet = nReadCShoreOutput(nProfile, &strOSETUP, 4, 4, &VdProfileDistXY, &VdFreeSurfaceStd);
1102
1103 if (nRet != RTN_OK)
1104 return nRet;
1105
1106 nRet = nReadCShoreOutput(nProfile, &strOYVELO, 4, 2, &VdProfileDistXY, &VdSinWaveAngleRadians);
1107
1108 if (nRet != RTN_OK)
1109 return nRet;
1110
1111 nRet = nReadCShoreOutput(nProfile, &strOPARAM, 4, 3, &VdProfileDistXY, &VdFractionBreakingWaves);
1112
1113 if (nRet != RTN_OK)
1114 return nRet;
1115
1116 // Read surge outputs
1117 // VdTSurg = {dSurgeInitTime, dCShoreTimeStep}, // Ditto
1118 // VdSWLin = {dSurgeLevel, dSurgeLevel}, // Ditto
1119
1120 // Clean up the CShore outputs
1121#ifdef _WIN32
1122 nRet = system("./clean.bat");
1123#else
1124
1126 {
1127 string strCommand = "./save_CShore_output.sh ";
1128 strCommand += to_string(m_ulIter);
1129 strCommand += " ";
1130 strCommand += to_string(nCoast);
1131 strCommand += " ";
1132 strCommand += to_string(nProfile);
1133
1134 nRet = system(strCommand.c_str());
1135
1136 if (nRet != RTN_OK)
1137 return nRet;
1138 }
1139
1140 nRet = system("./clean.sh");
1141#endif
1142
1143 if (nRet != RTN_OK)
1144 return nRet;
1145
1146 // And return to the CoastalME folder
1147 nRet = chdir(m_strCMEDir.c_str());
1148
1149 if (nRet != RTN_OK)
1150 return nRet;
1151
1152#endif
1153
1154#if defined CSHORE_ARG_INOUT || CSHORE_BOTH
1155 // We are communicating with CShore by passing arguments
1156 int nOutSize = 0; // CShore will return the size of the output vectors
1157
1158 // Set the error flag: this will be changed within CShore if there is a problem
1159 nRet = 0;
1160
1161 vector<double> VdInitTime = {dWaveInitTime, dCShoreTimeStep}; // Size is nNwave+1, value 1 is for the start of the CShore run, value 2 for end of CShore run
1162 vector<double> VdTPIn = {dDeepWaterWavePeriod, dDeepWaterWavePeriod}; // Ditto
1163 vector<double> VdHrmsIn = {dProfileDeepWaterWaveHeight, dProfileDeepWaterWaveHeight}; // Ditto
1164 vector<double> VdWangIn = {dWaveToNormalAngle, dWaveToNormalAngle}; // Ditto
1165 vector<double> VdTSurg = {dSurgeInitTime, dCShoreTimeStep}; // Ditto
1166 vector<double> VdSWLin = {dSurgeLevel, dSurgeLevel}; // Ditto
1167 vector<double> VdFPInp = VdProfileFrictionFactor; // Set the value for wave friction at every point of the normal profile
1168 vector<double> VdXYDistFromCShoreOut(CSHOREARRAYOUTSIZE, 0); // Output from CShore
1169 vector<double> VdFreeSurfaceStdOut(CSHOREARRAYOUTSIZE, 0); // Ditto
1170 vector<double> VdWaveSetupSurgeOut(CSHOREARRAYOUTSIZE, 0); // Ditto
1171 // vector<double> VdStormSurgeOut(CSHOREARRAYOUTSIZE, 0); // Ditto
1172 vector<double> const VdWaveSetupRunUpOut(CSHOREARRAYOUTSIZE, 0); // Ditto
1173 vector<double> VdSinWaveAngleRadiansOut(CSHOREARRAYOUTSIZE, 0); // Ditto
1174 vector<double> VdFractionBreakingWavesOut(CSHOREARRAYOUTSIZE, 0); // Ditto
1175
1176 // Call CShore using the argument-passing wrapper
1177 // long lIter = static_cast<long>(m_ulIter); // Bodge to get round compiler 'invalid conversion' error
1178
1179 CShoreWrapper(&nILine, /* In_ILINE */
1180 &nIProfl, /* In_IPROFL */
1181 &nIPerm, /* In_IPERM */
1182 &nIOver, /* In_IOVER */
1183 &nIWCInt, /* In_IWCINT */
1184 &nIRoll, /* In_IROLL */
1185 &nIWind, /* In_IWIND */
1186 &nITide, /* In_ITIDE */
1187 &nILab, /* In_ILAB */
1188 &nNWave, /* In_NWAVE */
1189 &nNSurge, /* In_NSURG */
1190 &dDX, /* In_DX */
1191 &m_dBreakingWaveHeightDepthRatio, /* In_GAMMA */
1192 &VdInitTime[0], /* In_TWAVE */
1193 &VdTPIn[0], /* In_TPIN */
1194 &VdHrmsIn[0], /* In_HRMSIN */
1195 &VdWangIn[0], /* In_WANGIN */
1196 &VdTSurg[0], /* In_TSURG */
1197 &VdSWLin[0], /* In_SWLIN */
1198 &nProfileDistXYSize, /* In_NBINP */
1199 &VdProfileDistXY[0], /* In_XBINP */
1200 &VdProfileZ[0], /* In_ZBINP */
1201 &VdFPInp[0], /* In_FBINP */
1202 &nRet, /* Out_IError */
1203 &nOutSize, /* Out_nOutSize */
1204 &VdXYDistFromCShoreOut[0], /* Out_XYDist */
1205 &VdFreeSurfaceStdOut[0], /* Out_FreeSurfaceStd */
1206 &VdWaveSetupSurgeOut[0], /* Out_WaveSetupSurge */
1207 &VdSinWaveAngleRadiansOut[0], /* Out_SinWaveAngleRadians */
1208 &VdFractionBreakingWavesOut[0]); /* Out_FractionBreakingWaves */
1209
1210 // OK, now check for warnings and errors
1211 if (nOutSize < 2)
1212 {
1213 // CShore sometimes returns only one row of results, which contains data only for the seaward point of the profile. This happens when all other (more coastward) points give an invalid result during CShore's calculations. This is a problem. We don't want to abandon the simulation just because of this, so instead we just put some dummy data into the second row, and carry on with these two rows. The profile will get ignored later, since it is too small to be useful
1215 LogStream << m_ulIter << ": " << WARN << "for coast " << nCoast << " profile " << pProfile->nGetProfileID() << ", only " << nOutSize << " CShore output rows, abandoning this profile" << endl;
1216
1217 // // Set dummy data in the second row
1218 // VdXYDistFromCShoreOut[1] = 1e-5; // Dummy data, must not be the same as VdXYDistFromCShoreOut[0] tho', or get crash in linear interpolation routine
1219 // VdFreeSurfaceStdOut[1] = VdFreeSurfaceStdOut[0];
1220 // VdSinWaveAngleRadiansOut[1] = VdSinWaveAngleRadiansOut[0];
1221 // VdFractionBreakingWavesOut[1] = VdFractionBreakingWavesOut[0];
1222 // VdWaveSetupSurgeOut[1] = VdWaveSetupSurgeOut[0];
1223 // // VdStormSurgeOut[1] = VdStormSurgeOut[0];
1224 // // VdWaveSetupRunUpOut[1] = VdWaveSetupRunUpOut[0];
1225 //
1226 // // And increase the expected number of rows
1227 // nOutSize = 2;
1228
1229 return RTN_ERR_CSHORE_ERROR;
1230 }
1231
1232 if (nRet != 0)
1233 {
1234 string strErr = to_string(m_ulIter) + ": \tcoast " + to_string(nCoast) + " profile " + to_string(pProfile->nGetProfileID()) + " profile length " + to_string(nOutSize) + " ";
1235
1236 switch (nRet)
1237 {
1238 case -1:
1239 strErr += "CShore WARNING 1: negative depth at the first node";
1240 break;
1241
1242 case 2:
1243 strErr += "CShore WARNING 2: negative value at end of landward marching computation";
1244 break;
1245
1246 case 3:
1247 strErr += "CShore WARNING 3: large energy gradients at the first node: small waves with short period at sea boundary";
1248 break;
1249
1250 case 4:
1251 strErr += "CShore WARNING 4: zero energy at the first node";
1252 break;
1253
1254 case 5:
1255 strErr += "CShore WARNING 5: at end of landward marching computation, insufficient water depth";
1256 break;
1257
1258 case 7:
1259 strErr += "CShore WARNING 7: did not reach convergence";
1260 break;
1261 }
1262
1263 // OK, give up for this profile
1264 LogStream << m_ulIter << ": " << strErr << endl;
1265 return RTN_ERR_CSHORE_ERROR;
1266 }
1267
1268 // LogStream << m_ulIter << ": interpolating profile " << nProfile << endl;
1269
1270 // All OK, so interpolate the CShore output, and convert from the CShore convention (cross-shore distance has its origin at the seaward end) to the CoastalME convention (origin at the shoreline)
1271 InterpolateCShoreOutput(&VdProfileDistXY, nOutSize, nProfileSize, &VdXYDistFromCShoreOut, &VdFreeSurfaceStdOut, &VdWaveSetupSurgeOut, &VdSinWaveAngleRadiansOut, &VdFractionBreakingWavesOut, &VdFreeSurfaceStd, &VdWaveSetupSurge, &VdSinWaveAngleRadians, &VdFractionBreakingWaves);
1272#endif
1273
1274#if defined CSHORE_BOTH
1275#if !defined _WIN32
1276
1278 {
1279 string strCommand = "./save_CShore_output.sh ";
1280 strCommand += to_string(m_ulIter);
1281 strCommand += " ";
1282 strCommand += to_string(nCoast);
1283 strCommand += " ";
1284 strCommand += to_string(nProfile);
1285
1286 nRet = system(strCommand.c_str());
1287
1288 if (nRet != RTN_OK)
1289 return nRet;
1290 }
1291
1292#endif
1293
1294 // Return to the CoastalME folder
1295 nRet = chdir(m_strCMEDir.c_str());
1296
1297 if (nRet != RTN_OK)
1298 return nRet;
1299
1300#endif
1301
1302 // Do more safety checks, then convert the CShore output to wave height and wave direction, and update wave profile attributes
1303 for (int nProfilePoint = (nProfileSize - 1); nProfilePoint >= 0; nProfilePoint--)
1304 {
1305 int const nX = pProfile->pPtiGetCellInProfile(nProfilePoint)->nGetX();
1306 int const nY = pProfile->pPtiGetCellInProfile(nProfilePoint)->nGetY();
1307
1308 // Safety check
1309 if (nProfilePoint > static_cast<int>(VdFreeSurfaceStd.size()) - 1)
1310 continue;
1311
1312 // Safety check: deal with NaN values
1313 if (isnan(VdFreeSurfaceStd[nProfilePoint]))
1314 VdFreeSurfaceStd[nProfilePoint] = 0;
1315
1316 VdWaveHeight[nProfilePoint] = sqrt(8) * VdFreeSurfaceStd[nProfilePoint];
1317
1318 // Another safety check: deal with NaN values
1319 if (isnan(VdSinWaveAngleRadians[nProfilePoint]))
1320 {
1321 VdSinWaveAngleRadians[nProfilePoint] = 0;
1322 VdWaveHeight[nProfilePoint] = 0;
1323 }
1324
1325 // More safety checks: constrain to the interval -1 to +1 to keep asin() happy
1326 if (VdSinWaveAngleRadians[nProfilePoint] < -1)
1327 VdSinWaveAngleRadians[nProfilePoint] = -1;
1328
1329 if (VdSinWaveAngleRadians[nProfilePoint] > 1)
1330 VdSinWaveAngleRadians[nProfilePoint] = 1;
1331
1332 double const dAlpha = asin(VdSinWaveAngleRadians[nProfilePoint]) * (180 / PI);
1333
1334 if (nSeaHand == LEFT_HANDED)
1335 VdWaveDirection[nProfilePoint] = dKeepWithin360(dAlpha + 90 + dFluxOrientationThis);
1336 else
1337 VdWaveDirection[nProfilePoint] = dKeepWithin360(dAlpha + 270 + dFluxOrientationThis);
1338
1339 // Yet another safety check: deal with NaN values
1340 if (isnan(VdFractionBreakingWaves[nProfilePoint]))
1341 {
1342 VdFractionBreakingWaves[nProfilePoint] = 0;
1343 VdWaveHeight[nProfilePoint] = 0;
1344 }
1345
1346 // if ((VdFractionBreakingWaves[nProfilePoint] >= 0.10) && (! bBreaking)) // Sometimes is possible that waves break again
1347 if ((VdFractionBreakingWaves[nProfilePoint] >= 0.10) && (m_dDepthOfClosure >= m_pRasterGrid->m_Cell[nX][nY].dGetSeaDepth()) && (! bBreaking))
1348 {
1349 bBreaking = true;
1350 // assert(VdWaveHeight[nProfilePoint] >= 0);
1351 dProfileBreakingWaveHeight = VdWaveHeight[nProfilePoint];
1352 dProfileBreakingWaveAngle = VdWaveDirection[nProfilePoint];
1353 dProfileBreakingDepth = m_pRasterGrid->m_Cell[nX][nY].dGetSeaDepth(); // Water depth for the cell 'under' this point in the profile
1354 nProfileBreakingDist = nProfilePoint + 1; // At the nearest point nProfilePoint = 0, so, plus one
1355
1356 // LogStream << m_ulIter << ": \tcoast " << nCoast << " CShore breaking at [" << nX << "][" << nY << "] = {" << dGridCentroidXToExtCRSX(nX) << ", " << dGridCentroidYToExtCRSY(nY) << "} nProfile = " << nProfile << ", nProfilePoint = " << nProfilePoint << ", dBreakingWaveHeight = " << dBreakingWaveHeight << ", dBreakingWaveAngle = " << dBreakingWaveAngle << ", dProfileBreakingDepth = " << dProfileBreakingDepth << ", nProfileBreakingDist = " << nProfileBreakingDist << endl;
1357 }
1358
1359 VbWaveIsBreaking[nProfilePoint] = bBreaking;
1360 }
1361
1362 if (dProfileBreakingWaveHeight >= dProfileDeepWaterWaveHeight)
1363 dProfileBreakingWaveHeight = DBL_NODATA; // Checking poorly conditioned profiles problems for CShore
1364 }
1366 {
1367 // We are using COVE's linear wave theory to propagate the waves
1368 double const dDepthLookupMax = m_dWaveDepthRatioForWaveCalcs * dProfileDeepWaterWaveHeight;
1369
1370 // Go landwards along the profile, calculating wave height and wave angle for every inundated point on the profile (don't do point zero, this is on the coastline) until the waves start to break after breaking wave height is assumed to decrease linearly to zero at the shoreline and wave angle is equalt to wave angle at breaking
1371 for (int nProfilePoint = (nProfileSize - 1); nProfilePoint >= 0; nProfilePoint--)
1372 {
1373 int const nX = pProfile->pPtiGetCellInProfile(nProfilePoint)->nGetX();
1374 int const nY = pProfile->pPtiGetCellInProfile(nProfilePoint)->nGetY();
1375
1376 // Safety check
1377 if (! m_pRasterGrid->m_Cell[nX][nY].bIsInContiguousSea())
1378 continue;
1379
1380 double const dSeaDepth = m_pRasterGrid->m_Cell[nX][nY].dGetSeaDepth(); // Water depth for the cell 'under' this point in the profile
1381
1382 if (dSeaDepth > dDepthLookupMax)
1383 {
1384 // Sea depth is too large relative to wave height to feel the bottom, so do nothing since each cell under the profile has already been initialised with deep water wave height and wave direction
1385 dProfileWaveHeight = dProfileDeepWaterWaveHeight;
1386 dProfileWaveAngle = dProfileDeepWaterWaveAngle;
1387 }
1388 else
1389 {
1390 if (! bBreaking)
1391 {
1392 // Start calculating wave properties using linear wave theory
1393 double const dL = m_dL_0 * sqrt(tanh((2 * PI * dSeaDepth) / m_dL_0)); // Wavelength (m) in intermediate-shallow waters
1394 double const dC = m_dC_0 * tanh((2 * PI * dSeaDepth) / dL); // Wave speed (m/s) set by dSeaDepth, dL and m_dC_0
1395 double const dk = 2 * PI / dL; // Wave number (1/m)
1396 double const dn = ((2 * dSeaDepth * dk) / (sinh(2 * dSeaDepth * dk)) + 1) / 2; // Shoaling factor
1397 double const dKs = sqrt(m_dC_0 / (dn * dC * 2)); // Shoaling coefficient
1398 double const dAlpha = (180 / PI) * asin((dC / m_dC_0) * sin((PI / 180) * dWaveToNormalAngle)); // Calculate angle between wave direction and the normal to the coast tangent
1399 double const dKr = sqrt(cos((PI / 180) * dWaveToNormalAngle) / cos((PI / 180) * dAlpha)); // Refraction coefficient
1400 dProfileWaveHeight = dProfileDeepWaterWaveHeight * dKs * dKr; // Calculate wave height, based on the previous (more seaward) wave height
1401
1402 if (nSeaHand == LEFT_HANDED)
1403 dProfileWaveAngle = dKeepWithin360(dAlpha + 90 + dFluxOrientationThis);
1404
1405 else
1406 dProfileWaveAngle = dKeepWithin360(dAlpha + 270 + dFluxOrientationThis);
1407
1408 // Test to see if the wave breaks at this depth
1409 if (dProfileWaveHeight < (dSeaDepth * m_dBreakingWaveHeightDepthRatio))
1410 {
1411 dProfileBreakingWaveHeight = dProfileWaveHeight;
1412 dProfileBreakingWaveAngle = dProfileWaveAngle;
1413 }
1414 }
1415 else
1416 {
1417 // It does
1418 bBreaking = true;
1419
1420 // Wave has already broken
1421 dProfileWaveAngle = dProfileBreakingWaveAngle; // Wave orientation remains equal to wave orientation at breaking
1422
1423 dProfileWaveHeight = dProfileBreakingWaveHeight * (nProfilePoint / nProfileBreakingDist); // Wave height decreases linearly to zero at shoreline
1424 // dProfileWaveHeight = dSeaDepth * m_dBreakingWaveHeightDepthRatio; // Wave height is limited by depth
1425 dProfileBreakingDepth = dSeaDepth;
1426 nProfileBreakingDist = nProfilePoint;
1427 }
1428 }
1429
1430 // Save current wave attributes
1431 VdWaveDirection[nProfilePoint] = dProfileWaveAngle;
1432 VdWaveHeight[nProfilePoint] = dProfileWaveHeight;
1433 VbWaveIsBreaking[nProfilePoint] = bBreaking;
1434 }
1435 }
1436
1437 // Go landwards along the profile, fetching the calculated wave height and wave angle for every inundated point on this profile
1438 for (int nProfilePoint = (nProfileSize - 1); nProfilePoint >= 0; nProfilePoint--)
1439 {
1440 int nX = pProfile->pPtiGetCellInProfile(nProfilePoint)->nGetX();
1441 int nY = pProfile->pPtiGetCellInProfile(nProfilePoint)->nGetY();
1442
1443 // Safety check
1444 if (! m_pRasterGrid->m_Cell[nX][nY].bIsInContiguousSea())
1445 continue;
1446
1447 // Get the wave attributes calculated for this profile: wave height, wave angle, and whether is in the active zone
1448 double const dWaveHeight = VdWaveHeight[nProfilePoint];
1449 double const dWaveAngle = VdWaveDirection[nProfilePoint];
1450
1451 bBreaking = VbWaveIsBreaking[nProfilePoint];
1452
1453 // And store the wave properties for this point in the all-profiles vectors
1454 pVdX->push_back(nX);
1455 pVdY->push_back(nY);
1456 pVdHeightX->push_back(dWaveHeight * sin(dWaveAngle * PI / 180));
1457 pVdHeightY->push_back(dWaveHeight * cos(dWaveAngle * PI / 180));
1458 pVbBreaking->push_back(bBreaking);
1459 }
1460
1461 // Obtain the profile nodes near the coast
1462 int const nX = pProfile->pPtiGetCellInProfile(nProfileSize - 2)->nGetX();
1463 int const nY = pProfile->pPtiGetCellInProfile(nProfileSize - 2)->nGetY();
1464 int const nX1 = pProfile->pPtiGetCellInProfile(nProfileSize - 1)->nGetX();
1465 int const nY1 = pProfile->pPtiGetCellInProfile(nProfileSize - 1)->nGetY();
1466
1467 // Calculate the horizontal distance between the profile points
1468 double dXDist = tAbs(dGridCentroidXToExtCRSX(nX1) - dGridCentroidXToExtCRSX(nX));
1469 double dYDist = tAbs(dGridCentroidYToExtCRSY(nY1) - dGridCentroidYToExtCRSY(nY));
1470
1471 // Safety check
1472 if (bFPIsEqual(dXDist, 0.0, TOLERANCE))
1473 dXDist = 1e-3;
1474
1475 // Safety check
1476 if (bFPIsEqual(dYDist, 0.0, TOLERANCE))
1477 dYDist = 1e-3;
1478
1479 double const dDiffProfileDistXY = hypot(dXDist, dYDist);
1480
1481 // Compute the beach slope
1482 double const dtanBeta = tan(tAbs(m_pRasterGrid->m_Cell[nX1][nY1].dGetSeaDepth() - m_pRasterGrid->m_Cell[nX][nY].dGetSeaDepth()) / dDiffProfileDistXY);
1483
1484 // Compute the wave run-up using NIELSEN & HANSLOW (1991) & DHI (2004)
1485 int nValidPointsWaveHeight = 0;
1486 int nValidPointsWaveSetup = 0;
1487
1488 for (int nPoint = 0; nPoint < static_cast<int>(VdWaveHeight.size()); nPoint++)
1489 {
1490 if (VdWaveHeight[nPoint] > 1e-4)
1491 nValidPointsWaveHeight += 1;
1492 else
1493 break;
1494 }
1495
1496 nValidPointsWaveHeight -= 1;
1497
1498 for (int nPoint = 0; nPoint < static_cast<int>(VdWaveSetupSurge.size()); nPoint++)
1499 {
1500 if (tAbs(VdWaveSetupSurge[nPoint]) < 1) // limiting the absolute value of setup + surge if cshore run fails
1501 nValidPointsWaveSetup += 1;
1502 else
1503 break;
1504 }
1505
1506 nValidPointsWaveSetup -= 1;
1507
1508 double dWaveHeight = 0;
1509
1510 // Safety checks
1511 if ((nValidPointsWaveHeight >= 0) && (! bFPIsEqual(VdWaveHeight[nValidPointsWaveHeight], DBL_NODATA, TOLERANCE)))
1512 dWaveHeight = VdWaveHeight[nValidPointsWaveHeight];
1513
1514 // TODO 060 Remove the following 'magic numbers'
1515 double dRunUp = 0;
1516
1518 {
1519 // Compute the run-up using Nielsen, P. & Hanslow, D. J. 1991. Wave Runup Distributions on Natural Beaches. Journal of Coastal Research, 7, 1139-1152. *** & DHI (2004) ???
1520 dRunUp = 0.36 * pow(9.81, 0.5) * dtanBeta * pow(dWaveHeight, 0.5) * dDeepWaterWavePeriod;
1521 }
1523 {
1524 // Compute the run-up using Mase, H. 1989. Random Wave Runup Height on Gentle Slope. Journal of Waterway, Port, Coastal, and Ocean Engineering, 115, 649-661.
1525 double const dS0 = 2 * PI * dWaveHeight / (9.81 * dDeepWaterWavePeriod * dDeepWaterWavePeriod);
1526 dRunUp = 1.86 * dWaveHeight * pow(pow(dtanBeta / dS0, 0.5), 0.71);
1527 }
1529 {
1530 // Compute the run-up using Stockdon, H. F., Holman, R. A., Howd, P. A. & Sallenger JR, A. H. 2006. Empirical parameterization of setup, swash, and runup. Coastal Engineering, 53, 573-588. This version coded by Tom Ashby
1531 double const dS0 = 2 * PI * dWaveHeight / (9.81 * dDeepWaterWavePeriod * dDeepWaterWavePeriod);
1532 dRunUp = 1.1 * ((0.35 * dtanBeta * pow((1.0 / dS0) * dWaveHeight * dWaveHeight, 0.5)) + (0.5 * pow((1.0 / dS0) * dWaveHeight * dWaveHeight * (0.563 * dtanBeta * dtanBeta + 0.004), 0.5)));
1533
1534 // double const dS0 = 2 * PI * dWaveHeight / (9.81 * dDeepWaterWavePeriod * dDeepWaterWavePeriod);
1535 // dRunUp = 1.1 * ((0.35 * dWaveHeight * (pow((1 / dS0) * dWaveHeight * dWaveHeight, 0.5))) + (((((1 / dS0) * dWaveHeight * dWaveHeight) * (0.563 * dWaveHeight * dWaveHeight + 0.0004)), 0.5)) / 2);
1536 // double const dH0OverL0 = (1 / dS0) * dWaveHeight;
1537 // double const dTmp1 = 0.35 * dWaveHeight * pow(dH0OverL0, 0.5);
1538 // double const dTmp2 = pow(dH0OverL0 * ((0.563 * dWaveHeight * dWaveHeight) + 0.0004), 0.5);
1539 // dRunUp = 1.1 * (dTmp1 + (dTmp2 / 2));
1540 }
1541
1542 if ((tAbs(dRunUp) < 1e-4) || (isnan(dRunUp)))
1543 dRunUp = 0;
1544
1545 double dWaveSetupSurge = 0;
1546
1547 // Safety checks
1548 if ((nValidPointsWaveSetup >= 0) && (! bFPIsEqual(VdWaveSetupSurge[nValidPointsWaveSetup], DBL_NODATA, TOLERANCE)))
1549 dWaveSetupSurge = VdWaveSetupSurge[nValidPointsWaveSetup];
1550
1551 if ((tAbs(dWaveSetupSurge) < 1e-4) || (isnan(dWaveSetupSurge)))
1552 dWaveSetupSurge = 0;
1553
1554 // Update wave attributes along the coastline object. Wave height at the coast is always calculated (i.e. whether or not waves are breaking)
1555 // cout << "Wave Height at the coast is " << VdWaveHeight[nProfileSize - 1] << endl;
1556 m_VCoast[nCoast].SetCoastWaveHeight(nCoastPoint, dWaveHeight);
1557 m_VCoast[nCoast].SetWaveSetupSurge(nCoastPoint, dWaveSetupSurge);
1558 m_VCoast[nCoast].SetRunUp(nCoastPoint, dRunUp);
1559
1560 if (nProfileBreakingDist > 0)
1561 {
1562 // This coast point is in the active zone, so set breaking wave height, breaking wave angle, and depth of breaking for the coast point
1563 m_VCoast[nCoast].SetBreakingWaveHeight(nCoastPoint, dProfileBreakingWaveHeight);
1564 m_VCoast[nCoast].SetBreakingWaveAngle(nCoastPoint, dProfileBreakingWaveAngle);
1565 m_VCoast[nCoast].SetDepthOfBreaking(nCoastPoint, dProfileBreakingDepth);
1566 m_VCoast[nCoast].SetBreakingDistance(nCoastPoint, nProfileBreakingDist);
1567
1568 // LogStream << m_ulIter << ": nProfile = " << nProfile << ", nCoastPoint = " << nCoastPoint << " in active zone, dBreakingWaveHeight = " << dBreakingWaveHeight << endl;
1569 }
1570
1571 else
1572 {
1573 // This coast point is not in the active zone, so breaking wave height, breaking wave angle, and depth of breaking are all meaningless
1574 m_VCoast[nCoast].SetBreakingWaveHeight(nCoastPoint, DBL_NODATA);
1575 m_VCoast[nCoast].SetBreakingWaveAngle(nCoastPoint, DBL_NODATA);
1576 m_VCoast[nCoast].SetDepthOfBreaking(nCoastPoint, DBL_NODATA);
1577 m_VCoast[nCoast].SetBreakingDistance(nCoastPoint, INT_NODATA);
1578
1579 // LogStream << m_ulIter << ": nProfile = " << nProfile << ", nCoastPoint = " << nCoastPoint << " NOT in active zone" << endl;
1580 }
1581
1582 return RTN_OK;
1583}
1584
1585#if defined CSHORE_FILE_INOUT
1586//===============================================================================================================================
1588//===============================================================================================================================
1589int CSimulation::nCreateCShoreInfile(int const nCoast, int const nProfile, int const nILine, int const nIProfl, int const nIPerm, int const nIOver, int const nIWcint, int const nIRoll, int const nIWind, int const nITide, int const nILab, int const nWave, int const nSurge, double const dX, double const dTimestep, double const dWaveInitTime, double const dWavePeriod, double const dHrms, double const dWaveAngle, double const dSurgeInitTime, double const dSurgeLevel, vector<double> const *pVdXdist, vector<double> const *pVdBottomElevation, vector<double> const *pVdWaveFriction)
1590{
1591 // Create the CShore input file
1592 ofstream CShoreOutStream;
1593 CShoreOutStream.open(CSHORE_INFILE.c_str(), ios::out | ios::app);
1594
1595 if (CShoreOutStream.fail())
1596 {
1597 // Error, cannot open file for writing
1598 LogStream << m_ulIter << ": " << ERR << "cannot write to CShore input file '" << CSHORE_INFILE << "'" << endl;
1600 }
1601
1602 // And write to the file
1603 CShoreOutStream << 3 << endl; // Number of comment lines
1604 CShoreOutStream << "------------------------------------------------------------" << endl;
1605 CShoreOutStream << "CShore input file created by CoastalME for iteration " << m_ulIter << ", coast " << nCoast << ", profile " << nProfile << endl;
1606 CShoreOutStream << "------------------------------------------------------------" << endl;
1607 CShoreOutStream << nILine << " -> ILINE" << endl;
1608 CShoreOutStream << nIProfl << " -> IPROFL" << endl;
1609 CShoreOutStream << nIPerm << " -> IPERM" << endl;
1610 CShoreOutStream << nIOver << " -> IOVER" << endl;
1611 CShoreOutStream << nIWcint << " -> IWCINT" << endl;
1612 CShoreOutStream << nIRoll << " -> IROLL" << endl;
1613 CShoreOutStream << nIWind << " -> IWIND" << endl;
1614 CShoreOutStream << nITide << " -> ITIDE" << endl;
1615 CShoreOutStream << fixed;
1616 CShoreOutStream << setw(11) << setprecision(4) << dX << " -> DX" << endl;
1617 CShoreOutStream << setw(11) << m_dBreakingWaveHeightDepthRatio << " -> GAMMA" << endl;
1618 CShoreOutStream << setw(11) << nILab << " -> ILAB" << endl;
1619 CShoreOutStream << setw(11) << nWave << " -> NWAVE" << endl;
1620 CShoreOutStream << setw(11) << nSurge << " -> NSURGE" << endl;
1621
1622 // Line 18 of infile
1623 CShoreOutStream << setw(11) << setprecision(2) << dWaveInitTime; // TWAVE(1) in CShore
1624 CShoreOutStream << setw(11) << setprecision(4) << dWavePeriod; // TPIN(1) in CShore
1625 CShoreOutStream << setw(11) << dHrms; // HRMS(1) in CShore
1626 CShoreOutStream << setw(11) << dWaveAngle << endl; // WANGIN(1) in CShore
1627
1628 // Line 19 of infile
1629 CShoreOutStream << setw(11) << setprecision(2) << dTimestep; // TWAVE(2) in CShore
1630 CShoreOutStream << setw(11) << setprecision(4) << dWavePeriod; // TPIN(2) in CShore
1631 CShoreOutStream << setw(11) << dHrms; // HRMS(2) in CShore
1632 CShoreOutStream << setw(11) << dWaveAngle << endl; // WANGIN(2) in CShore
1633
1634 // Line 20 of infile
1635 CShoreOutStream << setw(11) << setprecision(2) << dSurgeInitTime; // TSURG(1) in CShore
1636 CShoreOutStream << setw(11) << setprecision(4) << dSurgeLevel << endl; // SWLIN(1) in CShore
1637
1638 // Line 21 of infile
1639 CShoreOutStream << setw(11) << setprecision(2) << dTimestep; // TSURG(2) in CShore
1640 CShoreOutStream << setw(11) << setprecision(4) << dSurgeLevel << endl; // SWLIN(2) in CShore
1641
1642 // Line 22 of infile
1643 CShoreOutStream << setw(8) << pVdXdist->size() << " -> NBINP" << endl;
1644
1645 CShoreOutStream << fixed << setprecision(4);
1646
1647 for (unsigned int i = 0; i < pVdXdist->size(); i++)
1648 // These are BINP(J,1), ZBINP(J,1), FBINP(J-1,1) in CShore
1649 CShoreOutStream << setw(11) << pVdXdist->at(i) << setw(11) << pVdBottomElevation->at(i) << setw(11) << pVdWaveFriction->at(i) << endl;
1650
1651 CShoreOutStream << endl;
1652
1653 // File written, so close it
1654 CShoreOutStream.close();
1655
1656 return RTN_OK;
1657}
1658#endif
1659
1660//===============================================================================================================================
1662//===============================================================================================================================
1663int CSimulation::nGetThisProfileElevationsForCShore(int const nCoast, CGeomProfile *pProfile, int const nProfSize, vector<double> *VdDistXY, vector<double> *VdVZ, vector<double> *VdFricF)
1664{
1665 bool bIsBehindIntervention = false;
1666
1667 int nX1 = 0;
1668 int nY1 = 0;
1669
1670 double dXDist;
1671 double dYDist;
1672 double dProfileDistXY = 0;
1673 double dProfileFricFact;
1674 double dPrevDist = -1;
1675
1676 for (int i = nProfSize - 1; i >= 0; i--)
1677 {
1678 int const nX = pProfile->pPtiVGetCellsInProfile()->at(i).nGetX();
1679 int const nY = pProfile->pPtiVGetCellsInProfile()->at(i).nGetY();
1680
1681 // Calculate the horizontal distance relative to the most seaward point
1682 if (i == nProfSize - 1)
1683 dProfileDistXY = 0;
1684 else
1685 {
1688 dProfileDistXY = dProfileDistXY + hypot(dXDist, dYDist);
1689 }
1690
1691 // Before we store the X-Y distance, must check that it is not the same as the previously-stored distance (if it is, we get zero-divide errors in CShore). If they are the same, add on a small distance
1692 if (bFPIsEqual(dProfileDistXY, dPrevDist, TOLERANCE))
1693 dProfileDistXY += 0.1; // TODO 084 Improve this
1694
1695 // Update the cell indexes, the initial cell is now the previous one
1696 nX1 = nX;
1697 nY1 = nY;
1698
1699 // Get the number of the highest layer with non-zero thickness
1700 int const nTopLayer = m_pRasterGrid->m_Cell[nX][nY].nGetTopNonZeroLayerAboveBasement();
1701
1702 // Safety checks
1703 if (nTopLayer == INT_NODATA)
1704 return RTN_ERR_NO_TOP_LAYER;
1705
1706 if (nTopLayer == NO_NONZERO_THICKNESS_LAYERS)
1707 // TODO 009 We are down to basement, decide what to do
1708 return RTN_OK;
1709
1710 // Get the elevation for both consolidated and unconsolidated sediment (including any talus) on this cell
1711 double const dTopElev = m_pRasterGrid->m_Cell[nX][nY].dGetAllSedTopElevIncTalus() + m_pRasterGrid->m_Cell[nX][nY].dGetInterventionHeight();
1712 double const VdProfileZ = dTopElev - m_dThisIterSWL;
1713
1714 // Check that landward elevation is greater than SWL
1715 if (i == 0)
1716 {
1717 if (VdProfileZ < 0)
1718 {
1719 VdVZ->push_back(0.1); // TODO 053 Set it to a small +ve elevation (compared with SWL). However there must be a better way of doing this
1720
1721 // Could not create the profile elevation vectors
1722 LogStream << m_ulIter << ": " << WARN << "coast " << nCoast << " profile " << pProfile->nGetProfileID() << " elevation at the landward end is " << dTopElev << " m. This is lower than this-iteration SWL (" << m_dThisIterSWL << " m). For CShore, changing the landward elevation for profile " << pProfile->nGetProfileID() << " to " << m_dThisIterSWL + 0.1 << "m" << endl;
1723 }
1724
1725 else
1726 {
1727 VdVZ->push_back(VdProfileZ);
1728 }
1729 }
1730
1731 else
1732 {
1733 VdVZ->push_back(VdProfileZ);
1734 }
1735
1736 // Now store the X-Y plane distance from the start of the profile
1737 VdDistXY->push_back(dProfileDistXY);
1738
1739 // Get the landform type at each point along the profile
1740 double const dInterventionHeight = m_pRasterGrid->m_Cell[nX][nY].dGetInterventionHeight();
1741
1742 // Modify default friction factor if a structural intervention is found, otherwise use the default
1743 if (dInterventionHeight > 0 || bIsBehindIntervention)
1744 {
1745 // Use an arbitrarily high value if structure is present
1746 dProfileFricFact = 100 * CSHORE_FRICTION_FACTOR;
1747 bIsBehindIntervention = true;
1748 }
1749
1750 else
1751 dProfileFricFact = CSHORE_FRICTION_FACTOR;
1752
1753 // Store the friction factor
1754 VdFricF->push_back(dProfileFricFact);
1755
1756 // For next time round
1757 dPrevDist = dProfileDistXY;
1758 }
1759
1760 return RTN_OK;
1761}
1762
1763#if defined CSHORE_FILE_INOUT
1764//===============================================================================================================================
1766//===============================================================================================================================
1767int CSimulation::nReadCShoreOutput(int const nProfile, string const *strCShoreFilename, int const nExpectedColumns, int const nCShorecolumn, vector<double> const *pVdProfileDistXYCME, vector<double> *pVdInterpolatedValues)
1768{
1769 // Read in the first column (contains XY distance relative to seaward limit) and CShore column from the CShore output file
1770 ifstream InStream;
1771 InStream.open(strCShoreFilename->c_str(), ios::in);
1772
1773 // Did it open OK?
1774 if (!InStream.is_open())
1775 {
1776 // Error: cannot open CShore file for input
1777 LogStream << m_ulIter << ": " << ERR << "for profile " << nProfile << ", cannot open " << *strCShoreFilename << " for input" << endl;
1778
1780 }
1781
1782 // Opened OK, so set up the vectors to hold the CShore output data
1783 vector<double> VdXYDistCShore;
1784 vector<double> VdValuesCShore;
1785
1786 // And read in the data
1787 int n = -1;
1788 int nExpectedRows = 0;
1789 string strLineIn;
1790
1791 while (getline(InStream, strLineIn))
1792 {
1793 n++;
1794
1795 if (n == 0)
1796 {
1797 // Read in the header line
1798 vector<string> VstrItems = VstrSplit(&strLineIn, SPACE);
1799
1800 if (! bIsStringValidInt(VstrItems[1]))
1801 {
1802 string strErr = ERR + "invalid integer for number of expected rows '" + VstrItems[1] + "' in " + *strCShoreFilename + "\n";
1803 cerr << strErr;
1804 LogStream << strErr;
1805
1807 }
1808
1809 // Get the number of expected rows
1810 nExpectedRows = stoi(VstrItems[1]);
1811 }
1812
1813 else
1814 {
1815 // Read in a data line
1816 vector<string> VstrItems = VstrSplit(&strLineIn, SPACE);
1817
1818 int nCols = static_cast<int>(VstrItems.size());
1819
1820 if (nCols != nExpectedColumns)
1821 {
1822 // Error: did not read the expected number of CShore output columns
1823 LogStream << m_ulIter << ": " << ERR << "for profile " << nProfile << ", expected " << nExpectedColumns << " CShore output columns but read " << nCols << " columns from header section of file " << *strCShoreFilename << endl;
1824
1826 }
1827
1828 // Number of columns is OK
1829 VdXYDistCShore.push_back(strtod(VstrItems[0].c_str(), NULL));
1830 VdValuesCShore.push_back(strtod(VstrItems[nCShorecolumn - 1].c_str(), NULL));
1831 }
1832 }
1833
1834 // Check that we have read nExpectedRows from the file
1835 int nReadRows = static_cast<int>(VdXYDistCShore.size());
1836
1837 if (nReadRows != nExpectedRows)
1838 {
1839 // Error: did not get nExpectedRows CShore output rows
1840 LogStream << m_ulIter << ": " << ERR << "for profile " << nProfile << ", expected " << nExpectedRows << " CShore output rows, but read " << nReadRows << " rows from file " << *strCShoreFilename << endl;
1841
1843 }
1844
1845 if (nReadRows < 2)
1846 {
1847 // CShore sometimes returns only one row, which contains data for the seaward point of the profile. This happens when all other (more coastward) points give an invalid result during CShore's calculations. This is a problem. We don't want to abandon the simulation just because of this, so instead we just duplicate the row, so that the profile will later get marked as invalid
1849 LogStream << m_ulIter << ": " << WARN << "for profile " << nProfile << ", only " << nReadRows << " CShore output rows in file " << *strCShoreFilename << endl;
1850
1851 // Duplicate the data
1852 VdXYDistCShore.push_back(VdXYDistCShore[0]);
1853 VdValuesCShore.push_back(VdValuesCShore[0]);
1854
1855 // And increase the expected number of rows
1856 nReadRows++;
1857 }
1858
1859 // The output is OK, so change the origin of the across-shore distance from the CShore convention to the one used here (i.e. with the origin at the shoreline)
1860 vector<double> VdXYDistCShoreTmp(nReadRows, 0);
1861
1862 for (int i = 0; i < nReadRows; i++)
1863 VdXYDistCShoreTmp[i] = VdXYDistCShore[nReadRows - 1] - VdXYDistCShore[i];
1864
1865 // Reverse the XY-distance and value vectors (i.e. first point is at the shoreline and must be in strictly ascending order)
1866 reverse(VdXYDistCShoreTmp.begin(), VdXYDistCShoreTmp.end());
1867
1868 // Similarly, reverse the CShore output
1869 reverse(VdValuesCShore.begin(), VdValuesCShore.end());
1870
1871 // Using a simple linear interpolation approach
1872 vector<double> VdDistXYCopy(pVdProfileDistXYCME->begin(), pVdProfileDistXYCME->end());
1873
1874 // assertVdXYDistCShoreTmp.size() == VdValuesCShore.size());
1875 *pVdInterpolatedValues = VdInterpolateCShoreProfileOutput(&VdXYDistCShoreTmp, &VdValuesCShore, &VdDistXYCopy);
1876
1877 return RTN_OK;
1878}
1879#endif
1880
1881#if defined CSHORE_ARG_INOUT || CSHORE_BOTH
1882//===============================================================================================================================
1884//===============================================================================================================================
1885void CSimulation::InterpolateCShoreOutput(vector<double> const *pVdProfileDistXYCME, int const nOutSize, int const nProfileSize, vector<double> *pVdXYDistFromCShore, vector<double> *pVdFreeSurfaceStdCShore, vector<double> *pVdWaveSetupSurgeCShore, vector<double> *pVdSinWaveAngleRadiansCShore, vector<double> *pVdFractionBreakingWavesCShore, vector<double> *pVdFreeSurfaceStdCME, vector<double> *pVdWaveSetupSurgeCME, vector<double> *pVdSinWaveAngleRadiansCME, vector<double> *pVdFractionBreakingWavesCME)
1886{
1887 // // DEBUG CODE ========================================================================================================
1888 // LogStream << m_ulIter << ": nOutSize = " << nOutSize << " nProfileSize = " << nProfileSize << " pVdProfileDistXYCME->size() = " << pVdProfileDistXYCME->size() << " pVdXYDistFromCShore->size() = " << pVdXYDistFromCShore->size() << endl;
1889 // // DEBUG CODE ========================================================================================================
1890
1891 // Sometimes the profile length returned from CShore is shorter than the CoastalME profile length
1892 bool bTooShort = false;
1893 int nTooShort = 0;
1894
1895 if (nOutSize < nProfileSize)
1896 {
1897 bTooShort = true;
1898 nTooShort = nProfileSize - nOutSize - 1;
1899
1900 // LogStream << m_ulIter << ": CShore PROFILE IS TOO SHORT" << endl;
1901 }
1902
1903 // // DEBUG CODE ========================================================================================================
1904 // for (int n = 0; n < static_cast<int>(pVdProfileDistXYCME->size()); n++)
1905 // LogStream << "pVdProfileDistXYCME[" << n << "] = " << pVdProfileDistXYCME->at(n) << endl;
1906 //
1907 // LogStream << endl;
1908 //
1909 // LogStream << "ORIGINAL" << endl;
1910 // for (int n = 0; n < nOutSize; n++)
1911 // LogStream << "pVdXYDistFromCShore[" << n << "] = " << pVdXYDistFromCShore->at(n) << " pVdFreeSurfaceStdCShore[" << n << "] = " << pVdFreeSurfaceStdCShore->at(n) << " pVdWaveSetupSurgeCShore[" << n << "] = " << pVdWaveSetupSurgeCShore->at(n) << " pVdSinWaveAngleRadiansCShore[" << n << "] = " << pVdSinWaveAngleRadiansCShore->at(n) << " pVdFractionBreakingWavesCShore[" << n << "] = " << pVdFractionBreakingWavesCShore->at(n) << endl;
1912 //
1913 // LogStream << endl;
1914 // // DEBUG CODE ========================================================================================================
1915
1916 if (bTooShort)
1917 {
1918 // Add extrapolated value(s) to the end of the valid part of each profile vector so that we have nProfileSize valid values
1919 double dLastDiff = pVdXYDistFromCShore->at(nOutSize - 1) - pVdXYDistFromCShore->at(nOutSize - 2);
1920
1921 for (int n = 0; n < nTooShort; n++)
1922 pVdXYDistFromCShore->at(nOutSize + n) = pVdXYDistFromCShore->at(nOutSize - 1 + n) + dLastDiff;
1923
1924 for (int n = 0; n < nTooShort; n++)
1925 pVdFreeSurfaceStdCShore->at(nOutSize + n) = pVdFreeSurfaceStdCShore->at(nOutSize - 1);
1926
1927 for (int n = 0; n < nTooShort; n++)
1928 pVdWaveSetupSurgeCShore->at(nOutSize + n) = pVdWaveSetupSurgeCShore->at(nOutSize - 1);
1929
1930 // TODO 007 Do same for pVdStormSurgeCShore and pVdWaveSetupRunUpCShore ?
1931
1932 for (int n = 0; n < nTooShort; n++)
1933 pVdSinWaveAngleRadiansCShore->at(nOutSize + n) = pVdSinWaveAngleRadiansCShore->at(nOutSize - 1);
1934
1935 dLastDiff = pVdFractionBreakingWavesCShore->at(nOutSize - 1) - pVdFractionBreakingWavesCShore->at(nOutSize - 2);
1936
1937 for (int n = 0; n < nTooShort; n++)
1938 pVdFractionBreakingWavesCShore->at(nOutSize + n) = tMin(pVdFractionBreakingWavesCShore->at(nOutSize - 1 + n) + dLastDiff, 1.0);
1939
1940 // // DEBUG CODE ========================================================================================================
1941 // LogStream << "EXTENDED" << endl;
1942 // for (int n = 0; n < nProfileSize; n++)
1943 // LogStream << "pVdXYDistFromCShore[" << n << "] = " << pVdXYDistFromCShore->at(n) << " pVdFreeSurfaceStdCShore[" << n << "] = " << pVdFreeSurfaceStdCShore->at(n) << " pVdWaveSetupSurgeCShore[" << n << "] = " << pVdWaveSetupSurgeCShore->at(n) << " pVdSinWaveAngleRadiansCShore[" << n << "] = " << pVdSinWaveAngleRadiansCShore->at(n) << " pVdFractionBreakingWavesCShore[" << n << "] = " << pVdFractionBreakingWavesCShore->at(n) << " " << (n > (nOutSize-1) ? "EXTRAPOLATED" : "") << endl;
1944 //
1945 // LogStream << endl;
1946 // // DEBUG CODE ========================================================================================================
1947 }
1948
1949 vector<double> VdXYDistCShoreTmp(nProfileSize);
1950 copy(pVdXYDistFromCShore->begin(), pVdXYDistFromCShore->begin() + nProfileSize, begin(VdXYDistCShoreTmp));
1951
1952 // The CShore cross-shore distance has its origin at the seaward end, but the CoastalME convention has its origin at the shoreline. So we mst reverse the other vectors to conform with the CoastalMEME convention
1953 vector<double> VdFreeSurfaceStdCShoreTmp(nProfileSize);
1954 reverse_copy(pVdFreeSurfaceStdCShore->begin(), pVdFreeSurfaceStdCShore->begin() + nProfileSize, begin(VdFreeSurfaceStdCShoreTmp));
1955
1956 vector<double> VdWaveSetupSurgeCShoreTmp(nProfileSize);
1957 reverse_copy(pVdWaveSetupSurgeCShore->begin(), pVdWaveSetupSurgeCShore->begin() + nProfileSize, begin(VdWaveSetupSurgeCShoreTmp));
1958
1959 vector<double> VdSinWaveAngleRadiansCShoreTmp(nProfileSize);
1960 reverse_copy(pVdSinWaveAngleRadiansCShore->begin(), pVdSinWaveAngleRadiansCShore->begin() + nProfileSize, begin(VdSinWaveAngleRadiansCShoreTmp));
1961
1962 vector<double> VdFractionBreakingWavesCShoreTmp(nProfileSize);
1963 reverse_copy(pVdFractionBreakingWavesCShore->begin(), pVdFractionBreakingWavesCShore->begin() + nProfileSize, begin(VdFractionBreakingWavesCShoreTmp));
1964
1965 // // DEBUG CODE ========================================================================================================
1966 // LogStream << "REVERSED" << endl;
1967 // for (int n = 0; n < nProfileSize; n++)
1968 // LogStream << "VdXYDistCShoreTmp[" << n << "] = " << VdXYDistCShoreTmp.at(n) << " VdFreeSurfaceStdCShoreTmp[" << n << "] = " << VdFreeSurfaceStdCShoreTmp.at(n) << " VdWaveSetupSurgeCShoreTmp[" << n << "] = " << VdWaveSetupSurgeCShoreTmp.at(n) << " VdSinWaveAngleRadiansCShoreTmp[" << n << "] = " << VdSinWaveAngleRadiansCShoreTmp.at(n) << " VdFractionBreakingWavesCShoreTmp[" << n << "] = " << VdFractionBreakingWavesCShoreTmp.at(n) << endl;
1969 //
1970 // LogStream << endl;
1971 // // DEBUG CODE ========================================================================================================
1972
1973 // Finally we linearly interpolate the CShore output vectors to each point on the CoastalME profile. Input parameters x_old, y_old, x_new and the routine returns y_new
1974 *pVdFreeSurfaceStdCME = VdInterpolateCShoreProfileOutput(&VdXYDistCShoreTmp, pVdFreeSurfaceStdCShore, pVdProfileDistXYCME); // was &VdDistXYCopy);
1975 *pVdWaveSetupSurgeCME = VdInterpolateCShoreProfileOutput(&VdXYDistCShoreTmp, pVdWaveSetupSurgeCShore, pVdProfileDistXYCME);
1976 // *pVdStormSurgeCME = VdInterpolateCShoreProfileOutput(&VdXYDistCShoreTmp, pVdStormSurgeCShore, pVdProfileDistXYCME);
1977 // *pVdWaveSetupRunUpCME = VdInterpolateCShoreProfileOutput(&VdXYDistCShoreTmp, pVdWaveSetupRunUpCShore, pVdProfileDistXYCME);
1978 *pVdSinWaveAngleRadiansCME = VdInterpolateCShoreProfileOutput(&VdXYDistCShoreTmp, pVdSinWaveAngleRadiansCShore, pVdProfileDistXYCME);
1979 *pVdFractionBreakingWavesCME = VdInterpolateCShoreProfileOutput(&VdXYDistCShoreTmp, pVdFractionBreakingWavesCShore, pVdProfileDistXYCME);
1980
1981 // LogStream << "INTERPOLATED" << endl;
1982 // for (int n = 0; n < nProfileSize; n++)
1983 // LogStream << "pVdProfileDistXYCME[" << n << "] = " << pVdProfileDistXYCME->at(n) << " pVdFreeSurfaceStdCME[" << n << "] = " << pVdFreeSurfaceStdCME->at(n) << " pVdWaveSetupSurgeCME[" << n << "] = " << pVdWaveSetupSurgeCME->at(n) << " pVdSinWaveAngleRadiansCME[" << n << "] = " << pVdSinWaveAngleRadiansCME->at(n) << " pVdFractionBreakingWavesCME[" << n << "] = " << pVdFractionBreakingWavesCME->at(n) << endl;
1984 //
1985 // LogStream << "================================================ " << endl;
1986}
1987#endif
1988
1989//===============================================================================================================================
1991//===============================================================================================================================
1993{
1994 CGeomProfile *pProfile = m_VCoast[nCoast].pGetProfile(nProfile);
1995
1996 // Only do this for profiles without problems, including the start and end-of-coast profile
1997 if (! pProfile->bOKIncStartAndEndOfCoast())
1998 return;
1999
2000 bool bModfiedWaveHeightisBreaking = false;
2001 bool bProfileIsinShadowZone = false;
2002 int const nThisCoastPoint = pProfile->nGetCoastPoint();
2003 int const nProfileSize = pProfile->nGetNumCellsInProfile();
2004 int nThisBreakingDist = m_VCoast[nCoast].nGetBreakingDistance(nThisCoastPoint);
2005 double dThisBreakingWaveHeight = m_VCoast[nCoast].dGetBreakingWaveHeight(nThisCoastPoint); // This could be DBL_NODATA
2006 double dThisBreakingWaveAngle = m_VCoast[nCoast].dGetBreakingWaveAngle(nThisCoastPoint);
2007 double dThisBreakingDepth = m_VCoast[nCoast].dGetDepthOfBreaking(nThisCoastPoint);
2008
2009 // Traverse the profile landwards, checking if any profile cell is within the shadow zone
2010 for (int nProfilePoint = (nProfileSize - 1); nProfilePoint >= 0; nProfilePoint--)
2011 {
2012 int const nX = pProfile->pPtiGetCellInProfile(nProfilePoint)->nGetX();
2013 int const nY = pProfile->pPtiGetCellInProfile(nProfilePoint)->nGetY();
2014
2015 // If there is any cell profile within the shadow zone and waves are breaking then modify wave breaking properties otherwise continue
2016 if (m_pRasterGrid->m_Cell[nX][nY].bIsinAnyShadowZone())
2017 {
2018 bProfileIsinShadowZone = true;
2019
2020 // Check if the new wave height is breaking
2021 double const dWaveHeight = m_pRasterGrid->m_Cell[nX][nY].dGetWaveHeight();
2022
2023 // Check that wave height at the given point is lower than maximum real wave height. If breaking wave height is expected that no good wave height are obtained, so, do not take it
2024 if (dWaveHeight > (m_dDepthOfClosure * m_dBreakingWaveHeightDepthRatio) && (! bModfiedWaveHeightisBreaking) && (! bFPIsEqual(dThisBreakingWaveHeight, DBL_NODATA, TOLERANCE)))
2025 {
2026 // It is breaking
2027 bModfiedWaveHeightisBreaking = true;
2028
2029 dThisBreakingWaveHeight = m_dDepthOfClosure * m_dBreakingWaveHeightDepthRatio;
2030 dThisBreakingWaveAngle = m_pRasterGrid->m_Cell[nX][nY].dGetWaveAngle();
2031 dThisBreakingDepth = m_dDepthOfClosure;
2032 nThisBreakingDist = nProfilePoint;
2033 }
2034 }
2035 }
2036
2037 // Update breaking wave properties along coastal line object (Wave height, dir, distance). TODO 010 Update the active zone cells
2038 if (bProfileIsinShadowZone && bModfiedWaveHeightisBreaking) // Modified wave height is still breaking
2039 {
2040 // This coast point is in the active zone, so set breaking wave height, breaking wave angle, and depth of breaking for the coast point TODO 007 Where does the 0.78 come from? TODO 011 Should it be an input variable or a named constant?
2041 if (dThisBreakingWaveHeight > dThisBreakingDepth * 0.78)
2042 {
2043 dThisBreakingWaveHeight = dThisBreakingDepth * 0.78; // Likely CShore output wave height is not adequately reproduced due to input profile and wave properties. TODO 007 Finish surge and runup stuff. Does something need to be changed then?
2044 }
2045
2046 // assert(dThisBreakingWaveHeight >= 0);
2047 m_VCoast[nCoast].SetBreakingWaveHeight(nThisCoastPoint, dThisBreakingWaveHeight);
2048 m_VCoast[nCoast].SetBreakingWaveAngle(nThisCoastPoint, dThisBreakingWaveAngle);
2049 m_VCoast[nCoast].SetDepthOfBreaking(nThisCoastPoint, dThisBreakingDepth);
2050 m_VCoast[nCoast].SetBreakingDistance(nThisCoastPoint, nThisBreakingDist);
2051
2052 // LogStream << m_ulIter << ": nProfile = " << nProfile << ", nCoastPoint = " << nCoastPoint << " in active zone, dBreakingWaveHeight = " << dBreakingWaveHeight << endl;
2053 }
2054
2055 else if (bProfileIsinShadowZone && (! bModfiedWaveHeightisBreaking))
2056 {
2057 // This coast point is no longer in the active zone
2058 m_VCoast[nCoast].SetBreakingWaveHeight(nThisCoastPoint, DBL_NODATA);
2059 m_VCoast[nCoast].SetBreakingWaveAngle(nThisCoastPoint, DBL_NODATA);
2060 m_VCoast[nCoast].SetDepthOfBreaking(nThisCoastPoint, DBL_NODATA);
2061 m_VCoast[nCoast].SetBreakingDistance(nThisCoastPoint, INT_NODATA);
2062
2063 // LogStream << m_ulIter << ": nProfile = " << nProfile << ", nCoastPoint = " << nCoastPoint << " NOT in active zone" << endl;
2064 }
2065
2066 return;
2067}
2068
2069//===============================================================================================================================
2071//===============================================================================================================================
2072void CSimulation::InterpolateWavePropertiesBetweenProfiles(int const nCoast, int const nCount)
2073{
2074 CGeomProfile *pProfile = m_VCoast[nCoast].pGetProfileWithDownCoastSeq(nCount);
2075
2076 // Only do this for profiles without problems, including the start-of-coast profile (but not the end-of-coast profile)
2077 // if (! pProfile->bOKIncStartOfCoast())
2078 // return;
2079
2080 int const nThisCoastPoint = pProfile->nGetCoastPoint();
2081
2082 // For the breaking wave stuff, to go into the in-between coastline points
2083 int const nThisBreakingDist = m_VCoast[nCoast].nGetBreakingDistance(nThisCoastPoint);
2084 double const dThisBreakingWaveHeight = m_VCoast[nCoast].dGetBreakingWaveHeight(nThisCoastPoint); // This could be DBL_NODATA
2085 double const dThisBreakingWaveAngle = m_VCoast[nCoast].dGetBreakingWaveAngle(nThisCoastPoint);
2086 double const dThisBreakingDepth = m_VCoast[nCoast].dGetDepthOfBreaking(nThisCoastPoint);
2087 double const dThisWaveSetupSurge = m_VCoast[nCoast].dGetWaveSetupSurge(nThisCoastPoint);
2088 // double dThisStormSurge = m_VCoast[nCoast].dGetStormSurge(nThisCoastPoint);
2089 double const dThisRunUp = m_VCoast[nCoast].dGetRunUp(nThisCoastPoint);
2090
2091 // Get the next profile along the coast, in the down-coast direction. If this next profile has a problem, go to the one after that, etc
2092 CGeomProfile const *pTmpProfile = pProfile;
2093 CGeomProfile *pNextProfile;
2094
2095 while (true)
2096 {
2097 pNextProfile = pTmpProfile->pGetDownCoastAdjacentProfile();
2098
2099 if (pNextProfile->bOKIncStartAndEndOfCoast())
2100 {
2101 // The next profile is OK
2102 break;
2103 }
2104
2105 // The next profile is not OK, so prepare to the one after that
2106 pTmpProfile = pNextProfile;
2107
2108 if (pTmpProfile->bEndOfCoast())
2109 {
2110 // Uh-oh, we've reached the down-coast end of the coast without finding an OK down-coast profile. So give up
2111 return;
2112 }
2113 }
2114
2115 // The next profile is OK
2116 int const nNextCoastPoint = pNextProfile->nGetCoastPoint();
2117 int const nDistBetween = nNextCoastPoint - nThisCoastPoint;
2118
2119 // Safety check
2120 if (nDistBetween <= 0)
2121 // Nothing to do
2122 return;
2123
2124 int const nNextBreakingDist = m_VCoast[nCoast].nGetBreakingDistance(nNextCoastPoint);
2125 double const dNextBreakingWaveHeight = m_VCoast[nCoast].dGetBreakingWaveHeight(nNextCoastPoint); // This could be DBL_NODATA
2126 double const dNextBreakingWaveAngle = m_VCoast[nCoast].dGetBreakingWaveAngle(nNextCoastPoint);
2127 double const dNextBreakingDepth = m_VCoast[nCoast].dGetDepthOfBreaking(nNextCoastPoint);
2128 double const dNextWaveSetupSurge = m_VCoast[nCoast].dGetWaveSetupSurge(nNextCoastPoint);
2129 double const dNextRunUp = m_VCoast[nCoast].dGetRunUp(nNextCoastPoint);
2130
2131 // OK, fill coast point between profiles for setupsurge and runup
2132 for (int n = nThisCoastPoint; n <= nNextCoastPoint; n++)
2133 {
2134 // Fill first wave setup and surge
2135 int const nDist = n - nThisCoastPoint;
2136 double const dThisWeight = (nDistBetween - nDist) / static_cast<double>(nDistBetween);
2137 double const dNextWeight = 1 - dThisWeight;
2138 double dWaveSetupSurge = 0;
2139 double dRunUp = 0;
2140
2141 dWaveSetupSurge = (dThisWeight * dThisWaveSetupSurge) + (dNextWeight * dNextWaveSetupSurge);
2142 m_VCoast[nCoast].SetWaveSetupSurge(n, dWaveSetupSurge);
2143
2144 dRunUp = (dThisWeight * dThisRunUp) + (dNextWeight * dNextRunUp);
2145 m_VCoast[nCoast].SetRunUp(n, dRunUp);
2146 }
2147
2148 // int const nNextProfile = pNextProfile->nGetProfileID();
2149
2150 // If both this profile and the next profile are not in the active zone, then do no more
2151 if ((bFPIsEqual(dThisBreakingWaveHeight, DBL_NODATA, TOLERANCE)) && (bFPIsEqual(dNextBreakingWaveHeight, DBL_NODATA, TOLERANCE)))
2152 {
2153 // if (m_nLogFileDetail >= LOG_FILE_HIGH_DETAIL)
2154 // LogStream << m_ulIter << ": both profile " << pProfile->nGetProfileID() << " at coast point " << nThisCoastPoint << ", and profile " << nNextProfile << " at coast point " << nNextCoastPoint << ", are not in the active zone" << endl;
2155
2156 // Set the breaking wave height, breaking wave angle, and depth of breaking to DBL_NODATA
2157 for (int n = nThisCoastPoint; n < nNextCoastPoint; n++)
2158 {
2159 m_VCoast[nCoast].SetBreakingWaveHeight(nThisCoastPoint, DBL_NODATA);
2160 m_VCoast[nCoast].SetBreakingWaveAngle(nThisCoastPoint, DBL_NODATA);
2161 m_VCoast[nCoast].SetDepthOfBreaking(nThisCoastPoint, DBL_NODATA);
2162 m_VCoast[nCoast].SetBreakingDistance(nThisCoastPoint, DBL_NODATA);
2163 }
2164
2165 return;
2166 }
2167
2168 // OK, at least one of the two profiles is in the active zone
2169 if (bFPIsEqual(dThisBreakingWaveHeight, DBL_NODATA, TOLERANCE))
2170 {
2171 // The next profile must be in the active zone, so use values from the next profile
2172 for (int n = nThisCoastPoint; n < nNextCoastPoint; n++)
2173 {
2174 // Set the breaking wave height, breaking wave angle, and depth of breaking for this coast point TODO 056 This assert sometimes fails: why?
2175 // assert(dNextBreakingWaveHeight >= 0);
2176 m_VCoast[nCoast].SetBreakingWaveHeight(n, dNextBreakingWaveHeight);
2177 m_VCoast[nCoast].SetBreakingWaveAngle(n, dNextBreakingWaveAngle);
2178 m_VCoast[nCoast].SetDepthOfBreaking(n, dNextBreakingDepth);
2179 m_VCoast[nCoast].SetBreakingDistance(n, nNextBreakingDist);
2180 }
2181
2182 return;
2183 }
2184
2185 if (bFPIsEqual(dNextBreakingWaveHeight, DBL_NODATA, TOLERANCE))
2186 {
2187 // This profile must be in the active zone, so use values from this profile
2188 for (int n = nThisCoastPoint + 1; n <= nNextCoastPoint; n++)
2189 {
2190 // Set the breaking wave height, breaking wave angle, and depth of breaking for this coast point TODO 056 This assert sometimes fails: why?
2191 // assert(dThisBreakingWaveHeight >= 0);
2192 m_VCoast[nCoast].SetBreakingWaveHeight(n, dThisBreakingWaveHeight);
2193 m_VCoast[nCoast].SetBreakingWaveAngle(n, dThisBreakingWaveAngle);
2194 m_VCoast[nCoast].SetDepthOfBreaking(n, dThisBreakingDepth);
2195 m_VCoast[nCoast].SetBreakingDistance(n, nThisBreakingDist);
2196 }
2197
2198 return;
2199 }
2200
2201 // The values for both this profile point and the next profile point are fine, so do a weighted interpolation between this profile and the next profile
2202 for (int n = nThisCoastPoint + 1; n < nNextCoastPoint; n++)
2203 {
2204 int const nDist = n - nThisCoastPoint;
2205
2206 double dBreakingWaveHeight = DBL_NODATA;
2207 double dBreakingWaveAngle = DBL_NODATA;
2208 double dBreakingDepth = DBL_NODATA;
2209 double dBreakingDist = DBL_NODATA;
2210
2211 if ((dNextBreakingDepth > 0) && (dThisBreakingDepth > 0))
2212 {
2213 double const dThisWeight = (nDistBetween - nDist) / static_cast<double>(nDistBetween);
2214 double const dNextWeight = 1 - dThisWeight;
2215
2216 dBreakingWaveHeight = (dThisWeight * dThisBreakingWaveHeight) + (dNextWeight * dNextBreakingWaveHeight),
2217 dBreakingWaveAngle = (dThisWeight * dThisBreakingWaveAngle) + (dNextWeight * dNextBreakingWaveAngle),
2218 dBreakingDepth = (dThisWeight * dThisBreakingDepth) + (dNextWeight * dNextBreakingDepth),
2219 dBreakingDist = (dThisWeight * nThisBreakingDist) + (dNextWeight * nNextBreakingDist);
2220 }
2221
2222 else if (dNextBreakingDepth > 0)
2223 {
2224 dBreakingWaveHeight = dNextBreakingWaveHeight,
2225 dBreakingWaveAngle = dNextBreakingWaveAngle,
2226 dBreakingDepth = dNextBreakingDepth,
2227 dBreakingDist = nNextBreakingDist;
2228 }
2229
2230 else if (dThisBreakingDepth > 0)
2231 {
2232 dBreakingWaveHeight = dThisBreakingWaveHeight,
2233 dBreakingWaveAngle = dThisBreakingWaveAngle,
2234 dBreakingDepth = dThisBreakingDepth,
2235 dBreakingDist = nThisBreakingDist;
2236 }
2237
2238 // Set the breaking wave height, breaking wave angle, and depth of breaking for this coast point TODO 056 This assert sometimes fails: why?
2239 // assert(dBreakingWaveHeight >= 0);
2240 m_VCoast[nCoast].SetBreakingWaveHeight(n, dBreakingWaveHeight);
2241 m_VCoast[nCoast].SetBreakingWaveAngle(n, dBreakingWaveAngle);
2242 m_VCoast[nCoast].SetDepthOfBreaking(n, dBreakingDepth);
2243 m_VCoast[nCoast].SetBreakingDistance(n, nRound(dBreakingDist));
2244 }
2245}
2246
2247//===============================================================================================================================
2249//===============================================================================================================================
2251{
2252 int const nCoastPoints = m_VCoast[nCoast].nGetCoastlineSize();
2253
2254 // Initialize all vectors pairs (x,y) for each variable
2255 vector<int> nVCoastWaveHeightX;
2256 vector<double> dVCoastWaveHeightY;
2257
2258 // Search all coast points for non NaN values and store them into temporary variables for later interporlation
2259 for (int n = 0; n < nCoastPoints; n++)
2260 {
2261 double const dCoastWaveHeight = m_VCoast[nCoast].dGetCoastWaveHeight(n);
2262
2263 if (! bFPIsEqual(dCoastWaveHeight, DBL_NODATA, TOLERANCE))
2264 {
2265 nVCoastWaveHeightX.push_back(n);
2266 dVCoastWaveHeightY.push_back(dCoastWaveHeight);
2267 }
2268 }
2269
2270 // Interpolate all coast points. Check first that x,y have more than 3 points and are both of equal size
2271 if ((nVCoastWaveHeightX.size() >= 3) && (nVCoastWaveHeightX.size() == dVCoastWaveHeightY.size()))
2272 {
2273 for (int n = 0; n < nCoastPoints; n++)
2274 {
2275 double const dInterpCoastWaveHeight = dGetInterpolatedValue(&nVCoastWaveHeightX, &dVCoastWaveHeightY, n, false);
2276 m_VCoast[nCoast].SetCoastWaveHeight(n, dInterpCoastWaveHeight);
2277 }
2278 }
2279
2280 else
2281 {
2282 for (int n = 0; n < nCoastPoints; n++)
2283 {
2284 m_VCoast[nCoast].SetCoastWaveHeight(n, 0);
2285 }
2286 }
2287}
2288
2289//===============================================================================================================================
2291//===============================================================================================================================
2293{
2294 int const nCoastSize = m_VCoast[nCoast].nGetCoastlineSize();
2295
2296 for (int nCoastPoint = 0; nCoastPoint < nCoastSize; nCoastPoint++)
2297 {
2298 double dXDiff;
2299 double dYDiff;
2300
2301 if (nCoastPoint == 0)
2302 {
2303 // For the point at the start of the coastline: use the straight line from 'this' point to the next point
2304 CGeom2DPoint const PtThis = *m_VCoast[nCoast].pPtGetCoastlinePointExtCRS(nCoastPoint); // In external CRS
2305 CGeom2DPoint const PtAfter = *m_VCoast[nCoast].pPtGetCoastlinePointExtCRS(nCoastPoint + 1); // In external CRS
2306
2307 dXDiff = PtAfter.dGetX() - PtThis.dGetX();
2308 dYDiff = PtAfter.dGetY() - PtThis.dGetY();
2309 }
2310
2311 else if (nCoastPoint == nCoastSize - 1)
2312 {
2313 // For the point at the end of the coastline: use the straight line from the point before to 'this' point
2314 CGeom2DPoint const PtBefore = *m_VCoast[nCoast].pPtGetCoastlinePointExtCRS(nCoastPoint - 1); // In external CRS
2315 CGeom2DPoint const PtThis = *m_VCoast[nCoast].pPtGetCoastlinePointExtCRS(nCoastPoint); // In external CRS
2316
2317 dXDiff = PtThis.dGetX() - PtBefore.dGetX();
2318 dYDiff = PtThis.dGetY() - PtBefore.dGetY();
2319 }
2320
2321 else
2322 {
2323 // For coastline points not at the start or end of the coast: start with a straight line which links the coastline points before and after 'this' coastline point
2324 CGeom2DPoint const PtBefore = *m_VCoast[nCoast].pPtGetCoastlinePointExtCRS(nCoastPoint - 1); // In external CRS
2325 CGeom2DPoint const PtAfter = *m_VCoast[nCoast].pPtGetCoastlinePointExtCRS(nCoastPoint + 1); // In external CRS
2326
2327 dXDiff = PtAfter.dGetX() - PtBefore.dGetX();
2328 dYDiff = PtAfter.dGetY() - PtBefore.dGetY();
2329 }
2330
2331 // Calculate angle between line and north point, measured clockwise (the azimuth)
2332 if (bFPIsEqual(dYDiff, 0.0, TOLERANCE))
2333 {
2334 // The linking line runs either W-E or E-W
2335 if (dXDiff > 0)
2336 // It runs W to E
2337 m_VCoast[nCoast].SetFluxOrientation(nCoastPoint, 90);
2338
2339 else
2340 // It runs E to W
2341 m_VCoast[nCoast].SetFluxOrientation(nCoastPoint, 270);
2342 }
2343
2344 else if (bFPIsEqual(dXDiff, 0.0, TOLERANCE))
2345 {
2346 // The linking line runs N-S or S-N
2347 if (dYDiff > 0)
2348 // It runs S to N
2349 m_VCoast[nCoast].SetFluxOrientation(nCoastPoint, 0);
2350
2351 else
2352 // It runs N to S
2353 m_VCoast[nCoast].SetFluxOrientation(nCoastPoint, 180);
2354 }
2355
2356 else
2357 {
2358 // The linking line runs neither W-E nor N-S so we have to work a bit harder to find the angle between it and the azimuth
2359 double dAzimuthAngle;
2360
2361 if (dXDiff > 0)
2362 dAzimuthAngle = (180 / PI) * (PI * 0.5 - atan(dYDiff / dXDiff));
2363
2364 else
2365 dAzimuthAngle = (180 / PI) * (PI * 1.5 - atan(dYDiff / dXDiff));
2366
2367 m_VCoast[nCoast].SetFluxOrientation(nCoastPoint, dAzimuthAngle);
2368 }
2369
2370 // LogStream << m_ulIter << ": nCoastPoint = " << nCoastPoint << " FluxOrientation = " << m_VCoast[nCoast].dGetFluxOrientation(nCoastPoint) << endl;
2371 }
2372}
2373
2374//===============================================================================================================================
2376//===============================================================================================================================
2378{
2379 // Get the total number of polygons, all coasts
2380 int nTotPolygonAllCoasts = 0;
2381 for (int nCoast = 0; nCoast < static_cast<int>(m_VCoast.size()); nCoast++)
2382 nTotPolygonAllCoasts += m_VCoast[nCoast].nGetNumPolygons();
2383
2384 // Vectors for D50 stuff
2385 vector<int> VnPolygonD50Count(nTotPolygonAllCoasts, 0);
2386 vector<double> VdPolygonD50(nTotPolygonAllCoasts, 0);
2387
2388 for (int nX = 0; nX < m_nXGridSize; nX++)
2389 {
2390 for (int nY = 0; nY < m_nYGridSize; nY++)
2391 {
2392 if (m_pRasterGrid->m_Cell[nX][nY].bIsInContiguousSea())
2393 {
2394 // This is a sea cell, first get polygon ID
2395 int const nPolyID = m_pRasterGrid->m_Cell[nX][nY].nGetPolygonID();
2396
2397 // Is it in the active zone?
2398 bool const bActive = m_pRasterGrid->m_Cell[nX][nY].bIsInActiveZone();
2399
2400 if (bActive)
2401 {
2402 // It is in the active zone. Does it have unconsolidated sediment on it? Test this using the UnconD50 value: if dGetUnconsD50() returns DBL_NODATA, there is no unconsolidated sediment
2403 double const dTmpd50 = m_pRasterGrid->m_Cell[nX][nY].dGetUnconsD50();
2404
2405 if (! bFPIsEqual(dTmpd50, DBL_NODATA, TOLERANCE))
2406 {
2407 // It does have unconsolidated sediment, so which polygon is this cell in?
2408 if (nPolyID != INT_NODATA)
2409 {
2410 VnPolygonD50Count[nPolyID]++;
2411 VdPolygonD50[nPolyID] += dTmpd50;
2412 }
2413 }
2414 }
2415
2416 // // Now fill in wave calc holes
2417 // if (m_pRasterGrid->m_Cell[nX][nY].dGetWaveHeight() == 0)
2418 // {
2419 // if (nID == INT_NODATA)
2420 // m_pRasterGrid->m_Cell[nX][nY].SetWaveHeight(m_dAllCellsDeepWaterWaveHeight);
2421 // }
2422 //
2423 // if (m_pRasterGrid->m_Cell[nX][nY].dGetWaveAngle() == 0)
2424 // {
2425 // if (nID == INT_NODATA)
2426 // m_pRasterGrid->m_Cell[nX][nY].SetWaveAngle(m_dAllCellsDeepWaterWaveAngle);
2427 // }
2428
2429 // Next look at the cell's N-S and W-E neighbours
2430 int nXTmp;
2431 int nYTmp;
2432 int nActive = 0;
2433 int nShadow = 0;
2434 int nShadowNum = 0;
2435 int nDownDrift = 0;
2436 int nDownDriftNum = 0;
2437 int nCoast = 0;
2438 int nRead = 0;
2439 double dWaveHeight = 0;
2440 double dWaveAngle = 0;
2441
2442 // North
2443 nXTmp = nX;
2444 nYTmp = nY - 1;
2445
2446 if (bIsWithinValidGrid(nXTmp, nYTmp))
2447 {
2448 if (m_pRasterGrid->m_Cell[nXTmp][nYTmp].bIsInContiguousSea())
2449 {
2450 nRead++;
2451 dWaveHeight += m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetWaveHeight();
2452 dWaveAngle += (m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetWaveAngle());
2453
2454 if (m_pRasterGrid->m_Cell[nXTmp][nYTmp].bIsInActiveZone())
2455 nActive++;
2456
2457 int nTmp = m_pRasterGrid->m_Cell[nXTmp][nYTmp].nGetShadowZoneNumber();
2458
2459 if (nTmp != 0)
2460 {
2461 nShadow++;
2462 nShadowNum = nTmp;
2463 }
2464
2465 nTmp = m_pRasterGrid->m_Cell[nXTmp][nYTmp].nGetDownDriftZoneNumber();
2466
2467 if (nTmp > 0)
2468 {
2469 nDownDrift++;
2470 nDownDriftNum = nTmp;
2471 }
2472 }
2473
2474 else
2475 nCoast++;
2476 }
2477
2478 // East
2479 nXTmp = nX + 1;
2480 nYTmp = nY;
2481
2482 if (bIsWithinValidGrid(nXTmp, nYTmp))
2483 {
2484 if (m_pRasterGrid->m_Cell[nXTmp][nYTmp].bIsInContiguousSea())
2485 {
2486 nRead++;
2487 dWaveHeight += m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetWaveHeight();
2488 dWaveAngle += (m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetWaveAngle());
2489
2490 if (m_pRasterGrid->m_Cell[nXTmp][nYTmp].bIsInActiveZone())
2491 nActive++;
2492
2493 int nTmp = m_pRasterGrid->m_Cell[nXTmp][nYTmp].nGetShadowZoneNumber();
2494
2495 if (nTmp != 0)
2496 {
2497 nShadow++;
2498 nShadowNum = nTmp;
2499 }
2500
2501 nTmp = m_pRasterGrid->m_Cell[nXTmp][nYTmp].nGetDownDriftZoneNumber();
2502
2503 if (nTmp > 0)
2504 {
2505 nDownDrift++;
2506 nDownDriftNum = nTmp;
2507 }
2508 }
2509
2510 else
2511 nCoast++;
2512 }
2513
2514 // South
2515 nXTmp = nX;
2516 nYTmp = nY + 1;
2517
2518 if (bIsWithinValidGrid(nXTmp, nYTmp))
2519 {
2520 if (m_pRasterGrid->m_Cell[nXTmp][nYTmp].bIsInContiguousSea())
2521 {
2522 nRead++;
2523 dWaveHeight += m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetWaveHeight();
2524 dWaveAngle += (m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetWaveAngle());
2525
2526 if (m_pRasterGrid->m_Cell[nXTmp][nYTmp].bIsInActiveZone())
2527 nActive++;
2528
2529 int nTmp = m_pRasterGrid->m_Cell[nXTmp][nYTmp].nGetShadowZoneNumber();
2530
2531 if (nTmp != 0)
2532 {
2533 nShadow++;
2534 nShadowNum = nTmp;
2535 }
2536
2537 nTmp = m_pRasterGrid->m_Cell[nXTmp][nYTmp].nGetDownDriftZoneNumber();
2538
2539 if (nTmp > 0)
2540 {
2541 nDownDrift++;
2542 nDownDriftNum = nTmp;
2543 }
2544 }
2545
2546 else
2547 nCoast++;
2548 }
2549
2550 // West
2551 nXTmp = nX - 1;
2552 nYTmp = nY;
2553
2554 if (bIsWithinValidGrid(nXTmp, nYTmp))
2555 {
2556 if (m_pRasterGrid->m_Cell[nXTmp][nYTmp].bIsInContiguousSea())
2557 {
2558 nRead++;
2559 dWaveHeight += m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetWaveHeight();
2560 dWaveAngle += (m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetWaveAngle());
2561
2562 if (m_pRasterGrid->m_Cell[nXTmp][nYTmp].bIsInActiveZone())
2563 nActive++;
2564
2565 int nTmp = m_pRasterGrid->m_Cell[nXTmp][nYTmp].nGetShadowZoneNumber();
2566
2567 if (nTmp != 0)
2568 {
2569 nShadow++;
2570 nShadowNum = nTmp;
2571 }
2572
2573 nTmp = m_pRasterGrid->m_Cell[nXTmp][nYTmp].nGetDownDriftZoneNumber();
2574
2575 if (nTmp > 0)
2576 {
2577 nDownDrift++;
2578 nDownDriftNum = nTmp;
2579 }
2580 }
2581
2582 else
2583 nCoast++;
2584 }
2585
2586 if (nRead > 0)
2587 {
2588 // Calculate the average of neighbours
2589 dWaveHeight /= nRead;
2590 dWaveAngle /= nRead;
2591 dWaveAngle = dKeepWithin360(dWaveAngle);
2592
2593 // If this sea cell has four active-zone neighbours, then it must also be in the active zone: give it wave height and orientation which is the average of its neighbours
2594 if (nActive == 4)
2595 {
2596 m_pRasterGrid->m_Cell[nX][nY].SetInActiveZone(true);
2597 m_pRasterGrid->m_Cell[nX][nY].SetWaveHeight(dWaveHeight);
2598 m_pRasterGrid->m_Cell[nX][nY].SetWaveAngle(dWaveAngle);
2599 }
2600
2601 // If this sea cell has a wave height which is the same as its deep-water wave height, but its neighbours have a different average wave height, then give it the average of its neighbours
2602 double const dDeepWaterWaveHeight = m_pRasterGrid->m_Cell[nX][nY].dGetCellDeepWaterWaveHeight();
2603
2604 if ((bFPIsEqual(m_pRasterGrid->m_Cell[nX][nY].dGetWaveHeight(), dDeepWaterWaveHeight, TOLERANCE)) && (! bFPIsEqual(dDeepWaterWaveHeight, dWaveHeight, TOLERANCE)))
2605 {
2606 m_pRasterGrid->m_Cell[nX][nY].SetWaveHeight(dWaveHeight);
2607 }
2608
2609 // If this sea cell has a wave orientation which is the same as its deep-water wave orientation, but its neighbours have a different average wave orientation, then give it the average of its neighbours
2610 double const dDeepWaterWaveAngle = m_pRasterGrid->m_Cell[nX][nY].dGetCellDeepWaterWaveAngle();
2611
2612 if ((bFPIsEqual(m_pRasterGrid->m_Cell[nX][nY].dGetWaveAngle(), dDeepWaterWaveAngle, TOLERANCE)) && (! bFPIsEqual(dDeepWaterWaveAngle, dWaveAngle, TOLERANCE)))
2613 {
2614 m_pRasterGrid->m_Cell[nX][nY].SetWaveAngle(dWaveAngle);
2615 }
2616
2617 // Is this sea cell is not already marked as in a shadow zone (note could be marked as in a shadow zone but not yet processed: a -ve number)?
2618 int const nShadowZoneCode = m_pRasterGrid->m_Cell[nX][nY].nGetShadowZoneNumber();
2619
2620 if (nShadowZoneCode <= 0)
2621 {
2622 // If the cell has four neighbours which are all in a shadow zone, or four neighbours some of which are shadow zone and the remainder downdrift zone, or four neighbours some of which are shadow zone and the remainder coast; then it should also be in the shadow zone: give it the average of its neighbours
2623 if ((nShadow == 4) || (nShadow + nDownDrift == 4) || (nShadow + nCoast == 4))
2624 {
2625 m_pRasterGrid->m_Cell[nX][nY].SetShadowZoneNumber(nShadowNum);
2626 m_pRasterGrid->m_Cell[nX][nY].SetWaveHeight(dWaveHeight);
2627 m_pRasterGrid->m_Cell[nX][nY].SetWaveAngle(dWaveAngle);
2628 }
2629 }
2630
2631 // If this sea cell is not marked as in a downdrift zone but has four neighbours which are in a downdrift zone, then it should also be in the downdrift zone: give it the average of its neighbours
2632 int const nDownDriftZoneCode = m_pRasterGrid->m_Cell[nX][nY].nGetDownDriftZoneNumber();
2633
2634 if ((nDownDriftZoneCode == 0) && (nDownDrift == 4))
2635 {
2636 m_pRasterGrid->m_Cell[nX][nY].SetDownDriftZoneNumber(nDownDriftNum);
2637 m_pRasterGrid->m_Cell[nX][nY].SetWaveHeight(dWaveHeight);
2638 m_pRasterGrid->m_Cell[nX][nY].SetWaveAngle(dWaveAngle);
2639 }
2640 }
2641 }
2642 }
2643 }
2644
2645 // Calculate the average d50 for every polygon
2646 for (int nCoast = 0; nCoast < static_cast<int>(m_VCoast.size()); nCoast++)
2647 {
2648 for (int nPoly = 0; nPoly < m_VCoast[nCoast].nGetNumPolygons(); nPoly++)
2649 {
2650 CGeomCoastPolygon* pPolygon = m_VCoast[nCoast].pGetPolygon(nPoly);
2651 int const nPolyID = pPolygon->nGetPolygonCoastID();
2652
2653 if (VnPolygonD50Count[nPolyID] > 0)
2654 VdPolygonD50[nPolyID] /= VnPolygonD50Count[nPolyID];
2655
2656 pPolygon->SetAvgUnconsD50(VdPolygonD50[nPolyID]);
2657 }
2658 }
2659}
Contains CGeom2DPoint definitions.
int nGetY(void) const
Returns the CGeom2DIPoint object's integer Y coordinate.
Definition 2di_point.cpp:51
int nGetX(void) const
Returns the CGeom2DIPoint object's integer X coordinate.
Definition 2di_point.cpp:45
Geometry class used to represent 2D point objects with floating-point coordinates.
Definition 2d_point.h:25
double dGetY(void) const
Returns the CGeom2DPoint object's double Y coordinate.
Definition 2d_point.cpp:51
double dGetX(void) const
Returns the CGeom2DPoint object's double X coordinate.
Definition 2d_point.cpp:45
Geometry class used for coast polygon objects.
int nGetPolygonCoastID(void) const
Get the coast ID, this is the same as the down-coast sequence of polygons.
void SetAvgUnconsD50(double const)
Set the average d50 for unconsolidated sediment on this polygon.
Geometry class used to represent coast profile objects.
Definition profile.h:33
double dGetProfileDeepWaterWaveAngle(void) const
Returns the deep-water wave orientation for this profile.
Definition profile.cpp:589
double dGetProfileDeepWaterWaveHeight(void) const
Returns the deep-water wave height for this profile.
Definition profile.cpp:577
int nGetProfileID(void) const
Returns the profile's this-coast ID.
Definition profile.cpp:74
int nGetCoastPoint(void) const
Returns the coast point at which the profile starts.
Definition profile.cpp:80
CGeomProfile * pGetDownCoastAdjacentProfile(void) const
Returns the down-coast adjacent profile, returns NULL if there is no down-coast adjacent profile.
Definition profile.cpp:488
CGeom2DIPoint * pPtiGetCellInProfile(int const)
Returns a single cell (grid CRS) in the profile.
Definition profile.cpp:518
bool bIsGridEdge(void) const
Returns true if this is a start-of-coast or an end-of-coast profile.
Definition profile.cpp:122
int nGetNumCellsInProfile(void) const
Returns the number of cells in the profile.
Definition profile.cpp:539
void SetCShoreProblem(bool const)
Sets a switch to indicate whether this profile has a CShore problem.
Definition profile.cpp:131
bool bOKIncStartAndEndOfCoast(void) const
Returns true if this is a problem-free profile (however it could be a start-of-coast or an end-of-coa...
Definition profile.cpp:262
vector< CGeom2DIPoint > * pPtiVGetCellsInProfile(void)
Returns all cells (grid CRS) in the profile.
Definition profile.cpp:512
bool bEndOfCoast(void) const
Returns the switch to indicate whether this is an end-of-coast profile.
Definition profile.cpp:116
double dGetProfileDeepWaterWavePeriod(void) const
Returns the deep-water wave period for this profile.
Definition profile.cpp:601
int m_nLogFileDetail
The level of detail in the log file output. Can be LOG_FILE_LOW_DETAIL, LOG_FILE_MIDDLE_DETAIL,...
Definition simulation.h:588
double m_dAllCellsDeepWaterWaveHeight
Deep water wave height (m) for all sea cells.
Definition simulation.h:768
double m_dSyntheticTransectSpacing
Approximate minimum spacing (m) between wave transects (real and synthetic) for wave interpolation de...
Definition simulation.h:843
void InterpolateCShoreOutput(vector< double > const *, int const, int const, vector< double > *, vector< double > *, vector< double > *, vector< double > *, vector< double > *, vector< double > *, vector< double > *, vector< double > *, vector< double > *)
double m_dG
Gravitational acceleration (m**2/sec)
Definition simulation.h:825
double m_dThisIterSWL
The still water level for this timestep (this includes tidal changes and any long-term SWL change)
Definition simulation.h:726
CGeomRasterGrid * m_pRasterGrid
Pointer to the raster grid object.
int nCalcWavePropertiesOnProfile(int const, int const, CGeomProfile *, vector< double > *, vector< double > *, vector< double > *, vector< double > *, vector< bool > *)
Calculates wave properties along a coastline-normal profile using either the COVE linear wave theory ...
int m_nXGridSize
The size of the grid in the x direction.
Definition simulation.h:477
double m_dL_0
Deep water wave length (m)
Definition simulation.h:759
ofstream LogStream
vector< CRWCoast > m_VCoast
The coastline objects.
bool m_bSingleDeepWaterWaveValues
Do we have just a point source for (i.e. only a single measurement of) deep water wave values.
Definition simulation.h:387
vector< TransectWaveData > m_VAllTransectsWithSynthetic
Storage for wave transect points (real and synthetic) for debug output.
int m_nYGridSize
The size of the grid in the y direction.
Definition simulation.h:480
int nDoAllShadowZones(void)
Finds wave shadow zones and modifies waves in and near them. Note that where up-coast and down-coast ...
static double dKeepWithin360(double const)
Constrains the supplied angle to be within 0 and 360 degrees.
void CalcCoastTangents(int const)
Calculates tangents to a coastline: the tangent is assumed to be the orientation of energy/sediment f...
double m_dWaveDepthRatioForWaveCalcs
Start depth for wave calculations.
Definition simulation.h:762
int nCreateCShoreInfile(int const, int const, int const, int const, int const, int const, int const, int const, int const, int const, int const, int const, int const, double const, double const, double const, double const, double const, double const, double const, double const, vector< double > const *, vector< double > const *, vector< double > const *)
void InterpolateWavePropertiesBetweenProfiles(int const, int const)
Interpolates wave properties from profiles to the coastline points between two profiles....
int m_nRunUpEquation
The run-up equation used TODO 007 Finish surge and runup stuff.
Definition simulation.h:591
double m_dBreakingWaveHeightDepthRatio
Breaking wave height-to-depth ratio.
Definition simulation.h:765
int nReadCShoreOutput(int const, string const *, int const, int const, vector< double > const *, vector< double > *)
double dGridCentroidYToExtCRSY(int const) const
Given the integer Y-axis ordinate of a cell in the raster grid CRS, returns the external CRS Y-axis o...
Definition gis_utils.cpp:74
void CalcD50AndFillWaveCalcHoles(void)
Calculates an average d50 for each polygon. Also fills in 'holes' in active zone and wave calcs i....
string m_strCMEDir
The CME folder.
vector< double > VdInterpolateCShoreProfileOutput(vector< double > const *, vector< double > const *, vector< double > const *)
Returns a linearly interpolated vector of doubles, to make CShore profile output compatible with CME....
int m_nWavePropagationModel
The wave propagation model used. Possible values are WAVE_MODEL_CSHORE and WAVE_MODEL_COVE.
Definition simulation.h:564
double m_dAllCellsDeepWaterWaveAngle
Deep water wave angle for all sea cells.
Definition simulation.h:771
void GenerateSyntheticTransects(vector< TransectWaveData > const *, vector< TransectWaveData > *)
int nInterpolateWavesToPolygonCells(vector< TransectWaveData > const *, vector< double > const *, vector< double > const *, vector< double > const *, vector< double > const *)
int nSetAllCoastpointDeepWaterWaveValues(void)
Give every coast point a value for deep water wave height and direction TODO 005 This may not be real...
double m_dTimeStep
The length of an iteration (a timestep) in hours.
Definition simulation.h:690
int nGetThisProfileElevationsForCShore(int const, CGeomProfile *, int const, vector< double > *, vector< double > *, vector< double > *)
Get profile horizontal distance and bottom elevation vectors in CShore units.
bool bIsWithinValidGrid(int const, int const) const
Checks whether the supplied point (an x-y pair, in the grid CRS) is within the raster grid,...
void ModifyBreakingWavePropertiesWithinShadowZoneToCoastline(int const, int const)
Modifies the wave breaking properties at coastline points of profiles within the shadow zone.
double m_dC_0
Deep water wave speed (m/s)
Definition simulation.h:756
unsigned long m_ulIter
The number of the current iteration (time step)
Definition simulation.h:609
double dGridCentroidXToExtCRSX(int const) const
Given the integer X-axis ordinate of a cell in the raster grid CRS, returns the external CRS X-axis o...
Definition gis_utils.cpp:65
double dGetInterpolatedValue(vector< double > const *, vector< double > const *, double, bool)
int nDoAllPropagateWaves(void)
Simulates wave propagation along all coastline-normal profiles, on all coasts.
double m_dDepthOfClosure
Depth of closure (in m) TODO 007 can be calculated using Hallermeier, R.J. (1978) or Birkemeier (1985...
Definition simulation.h:831
void InterpolateWaveHeightToCoastPoints(int const)
Linearly interpolates wave properties from profiles to the coastline cells between two profiles.
static vector< string > * VstrSplit(string const *, char const, vector< string > *)
From http://stackoverflow.com/questions/236129/split-a-string-in-c They implement (approximately) Pyt...
Definition utils.cpp:2580
static double dCalcWaveAngleToCoastNormal(double const, double const, int const)
Calculates the angle between the wave direction and a normal to the coastline tangent....
This file contains global definitions for CoastalME.
int const NO_NONZERO_THICKNESS_LAYERS
Definition cme.h:672
int const INT_NODATA
Definition cme.h:380
T tMin(T a, T b)
Definition cme.h:1175
int const WAVE_MODEL_COVE
Definition cme.h:685
double const TOLERANCE
Definition cme.h:725
int const RTN_ERR_NO_TOP_LAYER
Definition cme.h:629
string const CSHORE_DIR
Definition cme.h:802
int const RTN_ERR_CSHORE_FILE_INPUT
Definition cme.h:637
string const ERR
Definition cme.h:805
int const RUNUP_EQUATION_NIELSEN_HANSLOW
Definition cme.h:699
double const CSHORE_FRICTION_FACTOR
Definition cme.h:722
int const WAVE_MODEL_CSHORE
Definition cme.h:686
int const RUNUP_EQUATION_MASE
Definition cme.h:700
int const LOG_FILE_MIDDLE_DETAIL
Definition cme.h:393
double const PI
Definition cme.h:707
int const RTN_ERR_CSHORE_ERROR
Definition cme.h:642
bool bFPIsEqual(const T d1, const T d2, const T dEpsilon)
Definition cme.h:1213
double const WALKDEN_HALL_PARAM_2
Definition cme.h:715
T tMax(T a, T b)
Definition cme.h:1162
int const RTN_ERR_READING_CSHORE_FILE_OUTPUT
Definition cme.h:638
double const CSHORE_SURGE_LEVEL
Definition cme.h:723
string const WARN
Definition cme.h:806
int const RTN_OK
Definition cme.h:585
bool const SAVE_CSHORE_OUTPUT
Definition cme.h:363
double const DBL_NODATA
Definition cme.h:736
int const CSHOREARRAYOUTSIZE
The size of the arrays output by CShore. If this is changed, then must also set the same value on lin...
Definition cme.h:376
double const WALKDEN_HALL_PARAM_1
Definition cme.h:714
T tAbs(T a)
Definition cme.h:1187
int const RTN_ERR_CSHORE_EMPTY_PROFILE
Definition cme.h:636
int const RUNUP_EQUATION_STOCKDON
Definition cme.h:701
string const CSHORE_INFILE
Definition cme.h:803
int const LEFT_HANDED
Definition cme.h:414
char const SPACE
Definition cme.h:357
Contains CRWCoast definitions.
void CShore(int *)
void CShoreWrapper(int const *, int const *, int const *, int const *, int const *, int const *, int const *, int const *, int const *, int const *, int const *, double const *, double const *, double[], double[], double[], double[], double[], double[], int const *, double[], double[], double[], int *, int *, double[], double[], double[], double[], double[])
Contains CSimulation definitions.
bool bIsStringValidInt(string &str)
Checks to see if a string can be read as a valid integer, from https://stackoverflow....
int nRound(double const d)
Correctly rounds doubles, returns an int.