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