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