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
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); // TODO 007 What is this for?
794 // vector<double> VdStormSurge(nProfileSize, 0); // TODO 007 What is this for?
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 // TODO 007 What is this for?
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 // TODO 007 What is this for?
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 // TODO 007 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); // TODO 007 Info needed
983 // vector<double> VdStormSurgeOut(CSHOREARRAYOUTSIZE, 0); // TODO 007 Info needed
984 vector<double> VdWaveSetupRunUpOut(CSHOREARRAYOUTSIZE, 0); // TODO 007 Info needed
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 */ // TODO 007 Info needed
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 */ // TODO 007 Info needed
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]; // TODO 007 Info needed
1035 // // VdStormSurgeOut[1] = VdStormSurgeOut[0]; // TODO 007 Info needed
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 // TODO 007 What is this for?
1309 for (int nPoint = 0; nPoint < static_cast<int>(VdWaveSetupSurge.size()); nPoint++)
1310 {
1311 if (tAbs(VdWaveSetupSurge[nPoint]) < 1) // limiting the absolute value of setup + surge if cshore run fails
1312 {
1313 nValidPointsWaveSetup += 1;
1314 }
1315 else
1316 {
1317 break;
1318 }
1319 }
1320 nValidPointsWaveSetup -= 1;
1321
1322 double dWaveHeight = 0;
1323
1324 // Safety checks
1325 if ((nValidPointsWaveHeight >= 0) && (! bFPIsEqual(VdWaveHeight[nValidPointsWaveHeight], DBL_NODATA, TOLERANCE)))
1326 {
1327 dWaveHeight = VdWaveHeight[nValidPointsWaveHeight];
1328 }
1329
1330 // TODO 060 Remove these 'magic numbers'
1331 double dRunUp = 0;
1332 if (m_nRunUpEquation == 0)
1333 {
1334 // Compute the run-up using NIELSEN & HANSLOW (1991) & DHI (2004) // TODO 007
1335 dRunUp = 0.36 * pow(9.81, 0.5) * dtanBeta * pow(dWaveHeight, 0.5) * dDeepWaterWavePeriod;
1336 }
1337 else if (m_nRunUpEquation == 1)
1338 {
1339 // Compute the run-up using MASE 1989
1340 double dS0 = 2 * PI * dWaveHeight / (9.81 * dDeepWaterWavePeriod * dDeepWaterWavePeriod);
1341 dRunUp = 1.86 * dWaveHeight * pow(pow(dtanBeta / dS0, 0.5), 0.71);
1342 }
1343 else if (m_nRunUpEquation == 2)
1344 {
1345 // Compute the run-up using STOCKDON (2006)
1346 double dS0 = 2 * PI * dWaveHeight / (9.81 * dDeepWaterWavePeriod * dDeepWaterWavePeriod);
1347 // 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);
1348
1349 double dH0OverL0 = (1 / dS0) * dWaveHeight;
1350 double dTmp1 = 0.35 * dWaveHeight * pow(dH0OverL0, 0.5);
1351 double dTmp2 = pow(dH0OverL0 * ((0.563 * dWaveHeight * dWaveHeight) + 0.0004), 0.5);
1352 dRunUp = 1.1 * (dTmp1 + (dTmp2 / 2));
1353 }
1354
1355 if ((tAbs(dRunUp) < 1e-4) || (isnan(dRunUp)))
1356 {
1357 dRunUp = 0;
1358 }
1359
1360 double dWaveSetupSurge = 0; // TODO 007 Info needed
1361
1362 // Safety checks
1363 if ((nValidPointsWaveSetup >= 0) && (! bFPIsEqual(VdWaveSetupSurge[nValidPointsWaveSetup], DBL_NODATA, TOLERANCE)))
1364 {
1365 dWaveSetupSurge = VdWaveSetupSurge[nValidPointsWaveSetup];
1366 }
1367
1368 if ((tAbs(dWaveSetupSurge) < 1e-4) || (isnan(dWaveSetupSurge)))
1369 {
1370 dWaveSetupSurge = 0;
1371 }
1372
1373 // Update wave attributes along the coastline object. Wave height at the coast is always calculated (i.e. whether or not waves are breaking)
1374 // cout << "Wave Height at the coast is " << VdWaveHeight[nProfileSize - 1] << endl;
1375 m_VCoast[nCoast].SetCoastWaveHeight(nCoastPoint, dWaveHeight);
1376 m_VCoast[nCoast].SetWaveSetupSurge(nCoastPoint, dWaveSetupSurge); // TODO 007 Info needed
1377 m_VCoast[nCoast].SetRunUp(nCoastPoint, dRunUp);
1378
1379 if (nProfileBreakingDist > 0)
1380 {
1381 // This coast point is in the active zone, so set breaking wave height, breaking wave angle, and depth of breaking for the coast point
1382 m_VCoast[nCoast].SetBreakingWaveHeight(nCoastPoint, dProfileBreakingWaveHeight);
1383 m_VCoast[nCoast].SetBreakingWaveAngle(nCoastPoint, dProfileBreakingWaveAngle);
1384 m_VCoast[nCoast].SetDepthOfBreaking(nCoastPoint, dProfileBreakingDepth);
1385 m_VCoast[nCoast].SetBreakingDistance(nCoastPoint, nProfileBreakingDist);
1386
1387 // LogStream << m_ulIter << ": nProfile = " << nProfile << ", nCoastPoint = " << nCoastPoint << " in active zone, dBreakingWaveHeight = " << dBreakingWaveHeight << endl;
1388 }
1389 else
1390 {
1391 // This coast point is not in the active zone, so breaking wave height, breaking wave angle, and depth of breaking are all meaningless
1392 m_VCoast[nCoast].SetBreakingWaveHeight(nCoastPoint, DBL_NODATA);
1393 m_VCoast[nCoast].SetBreakingWaveAngle(nCoastPoint, DBL_NODATA);
1394 m_VCoast[nCoast].SetDepthOfBreaking(nCoastPoint, DBL_NODATA);
1395 m_VCoast[nCoast].SetBreakingDistance(nCoastPoint, INT_NODATA);
1396
1397 // LogStream << m_ulIter << ": nProfile = " << nProfile << ", nCoastPoint = " << nCoastPoint << " NOT in active zone" << endl;
1398 }
1399
1400 return RTN_OK;
1401}
1402
1403#if defined CSHORE_FILE_INOUT
1404//===============================================================================================================================
1406//===============================================================================================================================
1407int 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)
1408{
1409 // Create the CShore input file
1410 ofstream CShoreOutStream;
1411 CShoreOutStream.open(CSHORE_INFILE.c_str(), ios::out | ios::app);
1412 if (CShoreOutStream.fail())
1413 {
1414 // Error, cannot open file for writing
1415 LogStream << m_ulIter << ": " << ERR << "cannot write to CShore input file '" << CSHORE_INFILE << "'" << endl;
1417 }
1418
1419 // And write to the file
1420 CShoreOutStream << 3 << endl; // Number of comment lines
1421 CShoreOutStream << "------------------------------------------------------------" << endl;
1422 CShoreOutStream << "CShore input file created by CoastalME for iteration " << m_ulIter << ", coast " << nCoast << ", profile " << nProfile << endl;
1423 CShoreOutStream << "------------------------------------------------------------" << endl;
1424 CShoreOutStream << nILine << " -> ILINE" << endl;
1425 CShoreOutStream << nIProfl << " -> IPROFL" << endl;
1426 CShoreOutStream << nIPerm << " -> IPERM" << endl;
1427 CShoreOutStream << nIOver << " -> IOVER" << endl;
1428 CShoreOutStream << nIWcint << " -> IWCINT" << endl;
1429 CShoreOutStream << nIRoll << " -> IROLL" << endl;
1430 CShoreOutStream << nIWind << " -> IWIND" << endl;
1431 CShoreOutStream << nITide << " -> ITIDE" << endl;
1432 CShoreOutStream << fixed;
1433 CShoreOutStream << setw(11) << setprecision(4) << dX << " -> DX" << endl;
1434 CShoreOutStream << setw(11) << m_dBreakingWaveHeightDepthRatio << " -> GAMMA" << endl;
1435 CShoreOutStream << setw(11) << nILab << " -> ILAB" << endl;
1436 CShoreOutStream << setw(11) << nWave << " -> NWAVE" << endl;
1437 CShoreOutStream << setw(11) << nSurge << " -> NSURGE" << endl;
1438
1439 // Line 18 of infile
1440 CShoreOutStream << setw(11) << setprecision(2) << dWaveInitTime; // TWAVE(1) in CShore
1441 CShoreOutStream << setw(11) << setprecision(4) << dWavePeriod; // TPIN(1) in CShore
1442 CShoreOutStream << setw(11) << dHrms; // HRMS(1) in CShore
1443 CShoreOutStream << setw(11) << dWaveAngle << endl; // WANGIN(1) in CShore
1444
1445 // Line 19 of infile
1446 CShoreOutStream << setw(11) << setprecision(2) << dTimestep; // TWAVE(2) in CShore
1447 CShoreOutStream << setw(11) << setprecision(4) << dWavePeriod; // TPIN(2) in CShore
1448 CShoreOutStream << setw(11) << dHrms; // HRMS(2) in CShore
1449 CShoreOutStream << setw(11) << dWaveAngle << endl; // WANGIN(2) in CShore
1450
1451 // Line 20 of infile
1452 CShoreOutStream << setw(11) << setprecision(2) << dSurgeInitTime; // TSURG(1) in CShore
1453 CShoreOutStream << setw(11) << setprecision(4) << dSurgeLevel << endl; // SWLIN(1) in CShore
1454
1455 // Line 21 of infile
1456 CShoreOutStream << setw(11) << setprecision(2) << dTimestep; // TSURG(2) in CShore
1457 CShoreOutStream << setw(11) << setprecision(4) << dSurgeLevel << endl; // SWLIN(2) in CShore
1458
1459 // Line 22 of infile
1460 CShoreOutStream << setw(8) << pVdXdist->size() << " -> NBINP" << endl;
1461
1462 CShoreOutStream << fixed << setprecision(4);
1463 for (unsigned int i = 0; i < pVdXdist->size(); i++)
1464 // These are BINP(J,1), ZBINP(J,1), FBINP(J-1,1) in CShore
1465 CShoreOutStream << setw(11) << pVdXdist->at(i) << setw(11) << pVdBottomElevation->at(i) << setw(11) << pVdWaveFriction->at(i) << endl;
1466
1467 CShoreOutStream << endl;
1468
1469 // File written, so close it
1470 CShoreOutStream.close();
1471
1472 return RTN_OK;
1473}
1474#endif
1475
1476//===============================================================================================================================
1478//===============================================================================================================================
1479int CSimulation::nGetThisProfileElevationsForCShore(int const nCoast, CGeomProfile* pProfile, int const nProfSize, vector<double>* VdDistXY, vector<double>* VdVZ, vector<double>* VdFricF)
1480{
1481 bool bIsBehindIntervention = false;
1482
1483 int nX1 = 0;
1484 int nY1 = 0;
1485
1486 double dXDist;
1487 double dYDist;
1488 double dProfileDistXY = 0;
1489 double dProfileFricFact;
1490 double dPrevDist = -1;
1491
1492 for (int i = nProfSize - 1; i >= 0; i--)
1493 {
1494 int nX = pProfile->pPtiVGetCellsInProfile()->at(i).nGetX();
1495 int nY = pProfile->pPtiVGetCellsInProfile()->at(i).nGetY();
1496
1497 // Calculate the horizontal distance relative to the most seaward point
1498 if (i == nProfSize - 1)
1499 dProfileDistXY = 0;
1500 else
1501 {
1504 dProfileDistXY = dProfileDistXY + hypot(dXDist, dYDist);
1505 }
1506
1507 // 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
1508 if (bFPIsEqual(dProfileDistXY, dPrevDist, TOLERANCE))
1509 dProfileDistXY += 0.1; // TODO 084 Improve this
1510
1511 // Update the cell indexes, the initial cell is now the previous one
1512 nX1 = nX;
1513 nY1 = nY;
1514
1515 // Get the number of the highest layer with non-zero thickness
1516 int const nTopLayer = m_pRasterGrid->m_Cell[nX][nY].nGetTopNonZeroLayerAboveBasement();
1517
1518 // Safety checks
1519 if (nTopLayer == INT_NODATA)
1520 return RTN_ERR_NO_TOP_LAYER;
1521
1522 if (nTopLayer == NO_NONZERO_THICKNESS_LAYERS)
1523 // TODO 009 We are down to basement, decide what to do
1524 return RTN_OK;
1525
1526 // Get the elevation for both consolidated and unconsolidated sediment on this cell
1527 double dTopElev = m_pRasterGrid->m_Cell[nX][nY].dGetSedimentTopElev() + m_pRasterGrid->m_Cell[nX][nY].dGetInterventionHeight();
1528 double VdProfileZ = dTopElev - m_dThisIterSWL;
1529
1530 // Check that landward elevation is greater than SWL
1531 if (i == 0)
1532 {
1533 if (VdProfileZ < 0)
1534 {
1535 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
1536
1537 // Could not create the profile elevation vectors
1538 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;
1539 }
1540 else
1541 {
1542 VdVZ->push_back(VdProfileZ);
1543 }
1544 }
1545 else
1546 {
1547 VdVZ->push_back(VdProfileZ);
1548 }
1549
1550 // Now store the X-Y plane distance from the start of the profile
1551 VdDistXY->push_back(dProfileDistXY);
1552
1553 // Get the landform type at each point along the profile
1554 double dInterventionHeight = m_pRasterGrid->m_Cell[nX][nY].dGetInterventionHeight();
1555
1556 // Modify default friction factor if a structural intervention is found, otherwise use the default
1557 if (dInterventionHeight > 0 || bIsBehindIntervention)
1558 {
1559 // Use an arbitrarily high value if structure is present
1560 dProfileFricFact = 100 * CSHORE_FRICTION_FACTOR;
1561 bIsBehindIntervention = true;
1562 }
1563 else
1564 dProfileFricFact = CSHORE_FRICTION_FACTOR;
1565
1566 // Store the friction factor
1567 VdFricF->push_back(dProfileFricFact);
1568
1569 // For next time round
1570 dPrevDist = dProfileDistXY;
1571 }
1572
1573 return RTN_OK;
1574}
1575
1576#if defined CSHORE_FILE_INOUT
1577//===============================================================================================================================
1579//===============================================================================================================================
1580int CSimulation::nReadCShoreOutput(int const nProfile, string const *strCShoreFilename, int const nExpectedColumns, int const nCShorecolumn, vector<double> const* pVdProfileDistXYCME, vector<double>* pVdInterpolatedValues)
1581{
1582 // Read in the first column (contains XY distance relative to seaward limit) and CShore column from the CShore output file
1583 ifstream InStream;
1584 InStream.open(strCShoreFilename->c_str(), ios::in);
1585
1586 // Did it open OK?
1587 if (! InStream.is_open())
1588 {
1589 // Error: cannot open CShore file for input
1590 LogStream << m_ulIter << ": " << ERR << "for profile " << nProfile << ", cannot open " << *strCShoreFilename << " for input" << endl;
1591
1593 }
1594
1595 // Opened OK, so set up the vectors to hold the CShore output data
1596 vector<double> VdXYDistCShore;
1597 vector<double> VdValuesCShore;
1598
1599 // And read in the data
1600 int n = -1;
1601 int nExpectedRows = 0;
1602 string strLineIn;
1603 while (getline(InStream, strLineIn))
1604 {
1605 n++;
1606
1607 if (n == 0)
1608 {
1609 // Read in the header line
1610 vector<string> VstrItems = VstrSplit(&strLineIn, SPACE);
1611
1612 if (! bIsStringValidInt(VstrItems[1]))
1613 {
1614 string strErr = ERR + "invalid integer for number of expected rows '" + VstrItems[1] + "' in " + *strCShoreFilename + "\n";
1615 cerr << strErr;
1616 LogStream << strErr;
1617
1619 }
1620
1621 // Get the number of expected rows
1622 nExpectedRows = stoi(VstrItems[1]);
1623 }
1624 else
1625 {
1626 // Read in a data line
1627 vector<string> VstrItems = VstrSplit(&strLineIn, SPACE);
1628
1629 int nCols = static_cast<int>(VstrItems.size());
1630 if (nCols != nExpectedColumns)
1631 {
1632 // Error: did not read the expected number of CShore output columns
1633 LogStream << m_ulIter << ": " << ERR << "for profile " << nProfile << ", expected " << nExpectedColumns << " CShore output columns but read " << nCols << " columns from header section of file " << *strCShoreFilename << endl;
1634
1636 }
1637
1638 // Number of columns is OK
1639 VdXYDistCShore.push_back(strtod(VstrItems[0].c_str(), NULL));
1640 VdValuesCShore.push_back(strtod(VstrItems[nCShorecolumn - 1].c_str(), NULL));
1641 }
1642 }
1643
1644 // Check that we have read nExpectedRows from the file
1645 int nReadRows = static_cast<int>(VdXYDistCShore.size());
1646 if (nReadRows != nExpectedRows)
1647 {
1648 // Error: did not get nExpectedRows CShore output rows
1649 LogStream << m_ulIter << ": " << ERR << "for profile " << nProfile << ", expected " << nExpectedRows << " CShore output rows, but read " << nReadRows << " rows from file " << *strCShoreFilename << endl;
1650
1652 }
1653
1654 if (nReadRows < 2)
1655 {
1656 // 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
1658 LogStream << m_ulIter << ": " << WARN << "for profile " << nProfile << ", only " << nReadRows << " CShore output rows in file " << *strCShoreFilename << endl;
1659
1660 // Duplicate the data
1661 VdXYDistCShore.push_back(VdXYDistCShore[0]);
1662 VdValuesCShore.push_back(VdValuesCShore[0]);
1663
1664 // And increase the expected number of rows
1665 nReadRows++;
1666 }
1667
1668 // 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)
1669 vector<double> VdXYDistCShoreTmp(nReadRows, 0);
1670 for (int i = 0; i < nReadRows; i++)
1671 VdXYDistCShoreTmp[i] = VdXYDistCShore[nReadRows - 1] - VdXYDistCShore[i];
1672
1673 // Reverse the XY-distance and value vectors (i.e. first point is at the shoreline and must be in strictly ascending order)
1674 reverse(VdXYDistCShoreTmp.begin(), VdXYDistCShoreTmp.end());
1675
1676 // Similarly, reverse the CShore output
1677 reverse(VdValuesCShore.begin(), VdValuesCShore.end());
1678
1679 // Using a simple linear interpolation approach
1680 vector<double> VdDistXYCopy(pVdProfileDistXYCME->begin(), pVdProfileDistXYCME->end());
1681
1682 // assertVdXYDistCShoreTmp.size() == VdValuesCShore.size());
1683 *pVdInterpolatedValues = VdInterpolateCShoreProfileOutput(&VdXYDistCShoreTmp, &VdValuesCShore, &VdDistXYCopy);
1684
1685 return RTN_OK;
1686}
1687#endif
1688
1689#if defined CSHORE_ARG_INOUT || CSHORE_BOTH
1690//===============================================================================================================================
1692//===============================================================================================================================
1693void 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)
1694{
1695 // // DEBUG CODE ========================================================================================================
1696 // LogStream << m_ulIter << ": nOutSize = " << nOutSize << " nProfileSize = " << nProfileSize << " pVdProfileDistXYCME->size() = " << pVdProfileDistXYCME->size() << " pVdXYDistFromCShore->size() = " << pVdXYDistFromCShore->size() << endl;
1697 // // DEBUG CODE ========================================================================================================
1698
1699 // Sometimes the profile length returned from CShore is shorter than the CoastalME profile length
1700 bool bTooShort = false;
1701 int nTooShort = 0;
1702 if (nOutSize < nProfileSize)
1703 {
1704 bTooShort = true;
1705 nTooShort = nProfileSize - nOutSize;
1706
1707 // LogStream << m_ulIter << ": CShore PROFILE IS TOO SHORT" << endl;
1708 }
1709
1710 // // DEBUG CODE ========================================================================================================
1711 // for (int n = 0; n < static_cast<int>(pVdProfileDistXYCME->size()); n++)
1712 // LogStream << "pVdProfileDistXYCME[" << n << "] = " << pVdProfileDistXYCME->at(n) << endl;
1713 //
1714 // LogStream << endl;
1715 //
1716 // LogStream << "ORIGINAL" << endl;
1717 // for (int n = 0; n < nOutSize; n++)
1718 // 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;
1719 //
1720 // LogStream << endl;
1721 // // DEBUG CODE ========================================================================================================
1722
1723 if (bTooShort)
1724 {
1725 // Add extrapolated value(s) to the end of the valid part of each profile vector so that we have nProfileSize valid values
1726 double dLastDiff = pVdXYDistFromCShore->at(nOutSize-1) - pVdXYDistFromCShore->at(nOutSize-2);
1727 for (int n = 0; n < nTooShort; n++)
1728 pVdXYDistFromCShore->at(nOutSize + n) = pVdXYDistFromCShore->at(nOutSize-1 + n) + dLastDiff;
1729
1730 for (int n = 0; n < nTooShort; n++)
1731 pVdFreeSurfaceStdCShore->at(nOutSize + n) = pVdFreeSurfaceStdCShore->at(nOutSize-1);
1732
1733 for (int n = 0; n < nTooShort; n++)
1734 pVdWaveSetupSurgeCShore->at(nOutSize + n) = pVdWaveSetupSurgeCShore->at(nOutSize-1);
1735
1736 // TODO 007 Do same for pVdStormSurgeCShore and pVdWaveSetupRunUpCShore ?
1737
1738 for (int n = 0; n < nTooShort; n++)
1739 pVdSinWaveAngleRadiansCShore->at(nOutSize + n) = pVdSinWaveAngleRadiansCShore->at(nOutSize-1);
1740
1741 dLastDiff = pVdFractionBreakingWavesCShore->at(nOutSize-1) - pVdFractionBreakingWavesCShore->at(nOutSize-2);
1742 for (int n = 0; n < nTooShort; n++)
1743 pVdFractionBreakingWavesCShore->at(nOutSize + n) = tMin(pVdFractionBreakingWavesCShore->at(nOutSize-1 + n) + dLastDiff, 1.0);
1744
1745 // // DEBUG CODE ========================================================================================================
1746 // LogStream << "EXTENDED" << endl;
1747 // for (int n = 0; n < nProfileSize; n++)
1748 // 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;
1749 //
1750 // LogStream << endl;
1751 // // DEBUG CODE ========================================================================================================
1752 }
1753
1754 vector<double> VdXYDistCShoreTmp(nProfileSize);
1755 copy(pVdXYDistFromCShore->begin(), pVdXYDistFromCShore->begin() + nProfileSize, begin(VdXYDistCShoreTmp));
1756
1757 // 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
1758 vector<double> VdFreeSurfaceStdCShoreTmp(nProfileSize);
1759 reverse_copy(pVdFreeSurfaceStdCShore->begin(), pVdFreeSurfaceStdCShore->begin() + nProfileSize, begin(VdFreeSurfaceStdCShoreTmp));
1760
1761 vector<double> VdWaveSetupSurgeCShoreTmp(nProfileSize);
1762 reverse_copy(pVdWaveSetupSurgeCShore->begin(), pVdWaveSetupSurgeCShore->begin() + nProfileSize, begin(VdWaveSetupSurgeCShoreTmp));
1763
1764 vector<double> VdSinWaveAngleRadiansCShoreTmp(nProfileSize);
1765 reverse_copy(pVdSinWaveAngleRadiansCShore->begin(), pVdSinWaveAngleRadiansCShore->begin() + nProfileSize, begin(VdSinWaveAngleRadiansCShoreTmp));
1766
1767 vector<double> VdFractionBreakingWavesCShoreTmp(nProfileSize);
1768 reverse_copy(pVdFractionBreakingWavesCShore->begin(), pVdFractionBreakingWavesCShore->begin() + nProfileSize, begin(VdFractionBreakingWavesCShoreTmp));
1769
1770 // // DEBUG CODE ========================================================================================================
1771 // LogStream << "REVERSED" << endl;
1772 // for (int n = 0; n < nProfileSize; n++)
1773 // 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;
1774 //
1775 // LogStream << endl;
1776 // // DEBUG CODE ========================================================================================================
1777
1778 // 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
1779 *pVdFreeSurfaceStdCME = VdInterpolateCShoreProfileOutput(&VdXYDistCShoreTmp, pVdFreeSurfaceStdCShore, pVdProfileDistXYCME); // was &VdDistXYCopy);
1780 *pVdWaveSetupSurgeCME = VdInterpolateCShoreProfileOutput(&VdXYDistCShoreTmp, pVdWaveSetupSurgeCShore, pVdProfileDistXYCME);
1781 // *pVdStormSurgeCME = VdInterpolateCShoreProfileOutput(&VdXYDistCShoreTmp, pVdStormSurgeCShore, pVdProfileDistXYCME);
1782 // *pVdWaveSetupRunUpCME = VdInterpolateCShoreProfileOutput(&VdXYDistCShoreTmp, pVdWaveSetupRunUpCShore, pVdProfileDistXYCME);
1783 *pVdSinWaveAngleRadiansCME = VdInterpolateCShoreProfileOutput(&VdXYDistCShoreTmp, pVdSinWaveAngleRadiansCShore, pVdProfileDistXYCME);
1784 *pVdFractionBreakingWavesCME = VdInterpolateCShoreProfileOutput(&VdXYDistCShoreTmp, pVdFractionBreakingWavesCShore, pVdProfileDistXYCME);
1785
1786 // LogStream << "INTERPOLATED" << endl;
1787 // for (int n = 0; n < nProfileSize; n++)
1788 // 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;
1789 //
1790 // LogStream << "================================================ " << endl;
1791}
1792#endif
1793
1794//===============================================================================================================================
1796//===============================================================================================================================
1798{
1799 CGeomProfile* pProfile = m_VCoast[nCoast].pGetProfile(nProfile);
1800
1801 // Only do this for profiles without problems, including the start and end-of-coast profile
1802 if (! pProfile->bOKIncStartAndEndOfCoast())
1803 return;
1804
1805 bool bModfiedWaveHeightisBreaking = false;
1806 bool bProfileIsinShadowZone = false;
1807 int nThisCoastPoint = pProfile->nGetCoastPoint();
1808 int nProfileSize = pProfile->nGetNumCellsInProfile();
1809 int nThisBreakingDist = m_VCoast[nCoast].nGetBreakingDistance(nThisCoastPoint);
1810 double dThisBreakingWaveHeight = m_VCoast[nCoast].dGetBreakingWaveHeight(nThisCoastPoint); // This could be DBL_NODATA
1811 double dThisBreakingWaveAngle = m_VCoast[nCoast].dGetBreakingWaveAngle(nThisCoastPoint);
1812 double dThisBreakingDepth = m_VCoast[nCoast].dGetDepthOfBreaking(nThisCoastPoint);
1813
1814 // Traverse the profile landwards, checking if any profile cell is within the shadow zone
1815 for (int nProfilePoint = (nProfileSize - 1); nProfilePoint >= 0; nProfilePoint--)
1816 {
1817 int nX = pProfile->pPtiGetCellInProfile(nProfilePoint)->nGetX();
1818 int nY = pProfile->pPtiGetCellInProfile(nProfilePoint)->nGetY();
1819
1820 // If there is any cell profile within the shadow zone and waves are breaking then modify wave breaking properties otherwise continue
1821 if (m_pRasterGrid->m_Cell[nX][nY].bIsinAnyShadowZone())
1822 {
1823 bProfileIsinShadowZone = true;
1824
1825 // Check if the new wave height is breaking
1826 double dWaveHeight = m_pRasterGrid->m_Cell[nX][nY].dGetWaveHeight();
1827
1828 // 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
1829 if (dWaveHeight > (m_dDepthOfClosure * m_dBreakingWaveHeightDepthRatio) && (! bModfiedWaveHeightisBreaking) && (! bFPIsEqual(dThisBreakingWaveHeight, DBL_NODATA, TOLERANCE)))
1830 {
1831 // It is breaking
1832 bModfiedWaveHeightisBreaking = true;
1833
1834 dThisBreakingWaveHeight = m_dDepthOfClosure * m_dBreakingWaveHeightDepthRatio;
1835 dThisBreakingWaveAngle = m_pRasterGrid->m_Cell[nX][nY].dGetWaveAngle();
1836 dThisBreakingDepth = m_dDepthOfClosure;
1837 nThisBreakingDist = nProfilePoint;
1838 }
1839 }
1840 }
1841
1842 // Update breaking wave properties along coastal line object (Wave height, dir, distance). TODO 010 Update the active zone cells
1843 if (bProfileIsinShadowZone && bModfiedWaveHeightisBreaking) // Modified wave height is still breaking
1844 {
1845 // 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?
1846 if (dThisBreakingWaveHeight > dThisBreakingDepth * 0.78)
1847 {
1848 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?
1849 }
1850
1851 // assert(dThisBreakingWaveHeight >= 0);
1852 m_VCoast[nCoast].SetBreakingWaveHeight(nThisCoastPoint, dThisBreakingWaveHeight);
1853 m_VCoast[nCoast].SetBreakingWaveAngle(nThisCoastPoint, dThisBreakingWaveAngle);
1854 m_VCoast[nCoast].SetDepthOfBreaking(nThisCoastPoint, dThisBreakingDepth);
1855 m_VCoast[nCoast].SetBreakingDistance(nThisCoastPoint, nThisBreakingDist);
1856
1857 // LogStream << m_ulIter << ": nProfile = " << nProfile << ", nCoastPoint = " << nCoastPoint << " in active zone, dBreakingWaveHeight = " << dBreakingWaveHeight << endl;
1858 }
1859 else if (bProfileIsinShadowZone && (! bModfiedWaveHeightisBreaking))
1860 {
1861 // This coast point is no longer in the active zone
1862 m_VCoast[nCoast].SetBreakingWaveHeight(nThisCoastPoint, DBL_NODATA);
1863 m_VCoast[nCoast].SetBreakingWaveAngle(nThisCoastPoint, DBL_NODATA);
1864 m_VCoast[nCoast].SetDepthOfBreaking(nThisCoastPoint, DBL_NODATA);
1865 m_VCoast[nCoast].SetBreakingDistance(nThisCoastPoint, INT_NODATA);
1866
1867 // LogStream << m_ulIter << ": nProfile = " << nProfile << ", nCoastPoint = " << nCoastPoint << " NOT in active zone" << endl;
1868 }
1869
1870 return;
1871}
1872
1873//===============================================================================================================================
1875//===============================================================================================================================
1876void CSimulation::InterpolateWavePropertiesBetweenProfiles(int const nCoast, int const nCount)
1877{
1878 CGeomProfile* pProfile = m_VCoast[nCoast].pGetProfileWithDownCoastSeq(nCount);
1879
1880 // Only do this for profiles without problems, including the start-of-coast profile (but not the end-of-coast profile)
1881 // if (!pProfile->bOKIncStartOfCoast())
1882 // return;
1883
1884 int nThisCoastPoint = pProfile->nGetCoastPoint();
1885
1886 // For the breaking wave stuff, to go into the in-between coastline points
1887 int const nThisBreakingDist = m_VCoast[nCoast].nGetBreakingDistance(nThisCoastPoint);
1888 double dThisBreakingWaveHeight = m_VCoast[nCoast].dGetBreakingWaveHeight(nThisCoastPoint); // This could be DBL_NODATA
1889 double dThisBreakingWaveAngle = m_VCoast[nCoast].dGetBreakingWaveAngle(nThisCoastPoint);
1890 double dThisBreakingDepth = m_VCoast[nCoast].dGetDepthOfBreaking(nThisCoastPoint);
1891 double dThisWaveSetupSurge = m_VCoast[nCoast].dGetWaveSetupSurge(nThisCoastPoint);
1892 // double dThisStormSurge = m_VCoast[nCoast].dGetStormSurge(nThisCoastPoint);
1893 double dThisRunUp = m_VCoast[nCoast].dGetRunUp(nThisCoastPoint);
1894
1895 // 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
1896 CGeomProfile const* pTmpProfile = pProfile;
1897 CGeomProfile* pNextProfile;
1898 while (true)
1899 {
1900 pNextProfile = pTmpProfile->pGetDownCoastAdjacentProfile();
1901
1902 if (pNextProfile->bOKIncStartAndEndOfCoast())
1903 {
1904 // The next profile is OK
1905 break;
1906 }
1907
1908 // The next profile is not OK, so prepare to the one after that
1909 pTmpProfile = pNextProfile;
1910
1911 if (pTmpProfile->bEndOfCoast())
1912 {
1913 // Uh-oh, we've reached the down-coast end of the coast without finding an OK down-coast profile. So give up
1914 return;
1915 }
1916 }
1917
1918 // The next profile is OK
1919 int const nNextCoastPoint = pNextProfile->nGetCoastPoint();
1920 int const nDistBetween = nNextCoastPoint - nThisCoastPoint;
1921
1922 // Safety check
1923 if (nDistBetween <= 0)
1924 // Nothing to do
1925 return;
1926
1927 int nNextBreakingDist = m_VCoast[nCoast].nGetBreakingDistance(nNextCoastPoint);
1928 double dNextBreakingWaveHeight = m_VCoast[nCoast].dGetBreakingWaveHeight(nNextCoastPoint); // This could be DBL_NODATA
1929 double dNextBreakingWaveAngle = m_VCoast[nCoast].dGetBreakingWaveAngle(nNextCoastPoint);
1930 double dNextBreakingDepth = m_VCoast[nCoast].dGetDepthOfBreaking(nNextCoastPoint);
1931 double dNextWaveSetupSurge = m_VCoast[nCoast].dGetWaveSetupSurge(nNextCoastPoint);
1932 double dNextRunUp = m_VCoast[nCoast].dGetRunUp(nNextCoastPoint);
1933
1934 // OK, fill coast point between profiles for setupsurge and runup
1935 for (int n = nThisCoastPoint; n <= nNextCoastPoint; n++)
1936 {
1937 // Fill first wave setup and surge
1938 int nDist = n - nThisCoastPoint;
1939 double dThisWeight = (nDistBetween - nDist) / static_cast<double>(nDistBetween);
1940 double dNextWeight = 1 - dThisWeight;
1941 double dWaveSetupSurge = 0;
1942 double dRunUp = 0;
1943
1944 dWaveSetupSurge = (dThisWeight * dThisWaveSetupSurge) + (dNextWeight * dNextWaveSetupSurge);
1945 m_VCoast[nCoast].SetWaveSetupSurge(n, dWaveSetupSurge);
1946
1947 dRunUp = (dThisWeight * dThisRunUp) + (dNextWeight * dNextRunUp);
1948 m_VCoast[nCoast].SetRunUp(n, dRunUp);
1949 }
1950
1951 // int const nNextProfile = pNextProfile->nGetCoastID();
1952
1953 // If both this profile and the next profile are not in the active zone, then do no more
1954 if ((bFPIsEqual(dThisBreakingWaveHeight, DBL_NODATA, TOLERANCE)) && (bFPIsEqual(dNextBreakingWaveHeight, DBL_NODATA, TOLERANCE)))
1955 {
1956 // if (m_nLogFileDetail >= LOG_FILE_HIGH_DETAIL)
1957 // 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;
1958
1959 // Set the breaking wave height, breaking wave angle, and depth of breaking to DBL_NODATA
1960 for (int n = nThisCoastPoint; n < nNextCoastPoint; n++)
1961 {
1962 m_VCoast[nCoast].SetBreakingWaveHeight(nThisCoastPoint, DBL_NODATA);
1963 m_VCoast[nCoast].SetBreakingWaveAngle(nThisCoastPoint, DBL_NODATA);
1964 m_VCoast[nCoast].SetDepthOfBreaking(nThisCoastPoint, DBL_NODATA);
1965 m_VCoast[nCoast].SetBreakingDistance(nThisCoastPoint, DBL_NODATA);
1966 }
1967 return;
1968 }
1969
1970 // OK, at least one of the two profiles is in the active zone
1971 if (bFPIsEqual(dThisBreakingWaveHeight, DBL_NODATA, TOLERANCE))
1972 {
1973 // The next profile must be in the active zone, so use values from the next profile
1974 for (int n = nThisCoastPoint; n < nNextCoastPoint; n++)
1975 {
1976 // Set the breaking wave height, breaking wave angle, and depth of breaking for this coast point TODO 056 This assert sometimes fails: why?
1977 // assert(dNextBreakingWaveHeight >= 0);
1978 m_VCoast[nCoast].SetBreakingWaveHeight(n, dNextBreakingWaveHeight);
1979 m_VCoast[nCoast].SetBreakingWaveAngle(n, dNextBreakingWaveAngle);
1980 m_VCoast[nCoast].SetDepthOfBreaking(n, dNextBreakingDepth);
1981 m_VCoast[nCoast].SetBreakingDistance(n, nNextBreakingDist);
1982 }
1983 return;
1984 }
1985
1986 if (bFPIsEqual(dNextBreakingWaveHeight, DBL_NODATA, TOLERANCE))
1987 {
1988 // This profile must be in the active zone, so use values from this profile
1989 for (int n = nThisCoastPoint + 1; n <= nNextCoastPoint; n++)
1990 {
1991 // Set the breaking wave height, breaking wave angle, and depth of breaking for this coast point TODO 056 This assert sometimes fails: why?
1992 // assert(dThisBreakingWaveHeight >= 0);
1993 m_VCoast[nCoast].SetBreakingWaveHeight(n, dThisBreakingWaveHeight);
1994 m_VCoast[nCoast].SetBreakingWaveAngle(n, dThisBreakingWaveAngle);
1995 m_VCoast[nCoast].SetDepthOfBreaking(n, dThisBreakingDepth);
1996 m_VCoast[nCoast].SetBreakingDistance(n, nThisBreakingDist);
1997 }
1998
1999 return;
2000 }
2001
2002 // 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
2003 for (int n = nThisCoastPoint + 1; n < nNextCoastPoint; n++)
2004 {
2005 int nDist = n - nThisCoastPoint;
2006
2007 double dBreakingWaveHeight = DBL_NODATA;
2008 double dBreakingWaveAngle = DBL_NODATA;
2009 double dBreakingDepth = DBL_NODATA;
2010 double dBreakingDist = DBL_NODATA;
2011
2012 if ((dNextBreakingDepth > 0) && (dThisBreakingDepth > 0))
2013 {
2014 double
2015 dThisWeight = (nDistBetween - nDist) / static_cast<double>(nDistBetween),
2016 dNextWeight = 1 - dThisWeight;
2017
2018 dBreakingWaveHeight = (dThisWeight * dThisBreakingWaveHeight) + (dNextWeight * dNextBreakingWaveHeight),
2019 dBreakingWaveAngle = (dThisWeight * dThisBreakingWaveAngle) + (dNextWeight * dNextBreakingWaveAngle),
2020 dBreakingDepth = (dThisWeight * dThisBreakingDepth) + (dNextWeight * dNextBreakingDepth),
2021 dBreakingDist = (dThisWeight * nThisBreakingDist) + (dNextWeight * nNextBreakingDist);
2022 }
2023 else if (dNextBreakingDepth > 0)
2024 {
2025 dBreakingWaveHeight = dNextBreakingWaveHeight,
2026 dBreakingWaveAngle = dNextBreakingWaveAngle,
2027 dBreakingDepth = dNextBreakingDepth,
2028 dBreakingDist = nNextBreakingDist;
2029 }
2030 else if (dThisBreakingDepth > 0)
2031 {
2032 dBreakingWaveHeight = dThisBreakingWaveHeight,
2033 dBreakingWaveAngle = dThisBreakingWaveAngle,
2034 dBreakingDepth = dThisBreakingDepth,
2035 dBreakingDist = nThisBreakingDist;
2036 }
2037
2038 // Set the breaking wave height, breaking wave angle, and depth of breaking for this coast point TODO 056 This assert sometimes fails: why?
2039 // assert(dBreakingWaveHeight >= 0);
2040 m_VCoast[nCoast].SetBreakingWaveHeight(n, dBreakingWaveHeight);
2041 m_VCoast[nCoast].SetBreakingWaveAngle(n, dBreakingWaveAngle);
2042 m_VCoast[nCoast].SetDepthOfBreaking(n, dBreakingDepth);
2043 m_VCoast[nCoast].SetBreakingDistance(n, nRound(dBreakingDist));
2044 }
2045}
2046
2047//===============================================================================================================================
2049//===============================================================================================================================
2051{
2052 int nCoastPoints = m_VCoast[nCoast].nGetCoastlineSize();
2053
2054 // Initialize all vectors pairs (x,y) for each variable
2055 vector<int> nVCoastWaveHeightX;
2056 vector<double> dVCoastWaveHeightY;
2057
2058 // Search all coast points for non NaN values and store them into temporary variables for later interporlation
2059 for (int n = 0; n < nCoastPoints; n++)
2060 {
2061 double dCoastWaveHeight = m_VCoast[nCoast].dGetCoastWaveHeight(n);
2062
2063 if (! bFPIsEqual(dCoastWaveHeight, DBL_NODATA, TOLERANCE))
2064 {
2065 nVCoastWaveHeightX.push_back(n);
2066 dVCoastWaveHeightY.push_back(dCoastWaveHeight);
2067 }
2068 }
2069
2070 // Interpolate all coast points. Check first that x,y have more than 3 points and are both of equal size
2071 if ((nVCoastWaveHeightX.size() >= 3) && (nVCoastWaveHeightX.size() == dVCoastWaveHeightY.size()))
2072 {
2073 for (int n = 0; n < nCoastPoints; n++)
2074 {
2075 double dInterpCoastWaveHeight = dGetInterpolatedValue(&nVCoastWaveHeightX, &dVCoastWaveHeightY, n, false);
2076 m_VCoast[nCoast].SetCoastWaveHeight(n, dInterpCoastWaveHeight);
2077 }
2078 }
2079 else
2080 {
2081 for (int n = 0; n < nCoastPoints; n++)
2082 {
2083 m_VCoast[nCoast].SetCoastWaveHeight(n, 0);
2084 }
2085 }
2086}
2087
2088//===============================================================================================================================
2090//===============================================================================================================================
2092{
2093 int nCoastSize = m_VCoast[nCoast].nGetCoastlineSize();
2094
2095 for (int nCoastPoint = 0; nCoastPoint < nCoastSize; nCoastPoint++)
2096 {
2097 double dXDiff;
2098 double dYDiff;
2099
2100 if (nCoastPoint == 0)
2101 {
2102 // For the point at the start of the coastline: use the straight line from 'this' point to the next point
2103 CGeom2DPoint PtThis = *m_VCoast[nCoast].pPtGetCoastlinePointExtCRS(nCoastPoint); // In external CRS
2104 CGeom2DPoint PtAfter = *m_VCoast[nCoast].pPtGetCoastlinePointExtCRS(nCoastPoint + 1); // In external CRS
2105
2106 dXDiff = PtAfter.dGetX() - PtThis.dGetX();
2107 dYDiff = PtAfter.dGetY() - PtThis.dGetY();
2108 }
2109 else if (nCoastPoint == nCoastSize - 1)
2110 {
2111 // For the point at the end of the coastline: use the straight line from the point before to 'this' point
2112 CGeom2DPoint PtBefore = *m_VCoast[nCoast].pPtGetCoastlinePointExtCRS(nCoastPoint - 1); // In external CRS
2113 CGeom2DPoint PtThis = *m_VCoast[nCoast].pPtGetCoastlinePointExtCRS(nCoastPoint); // In external CRS
2114
2115 dXDiff = PtThis.dGetX() - PtBefore.dGetX();
2116 dYDiff = PtThis.dGetY() - PtBefore.dGetY();
2117 }
2118 else
2119 {
2120 // 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
2121 CGeom2DPoint PtBefore = *m_VCoast[nCoast].pPtGetCoastlinePointExtCRS(nCoastPoint - 1); // In external CRS
2122 CGeom2DPoint PtAfter = *m_VCoast[nCoast].pPtGetCoastlinePointExtCRS(nCoastPoint + 1); // In external CRS
2123
2124 dXDiff = PtAfter.dGetX() - PtBefore.dGetX();
2125 dYDiff = PtAfter.dGetY() - PtBefore.dGetY();
2126 }
2127
2128 // Calculate angle between line and north point, measured clockwise (the azimuth)
2129 if (bFPIsEqual(dYDiff, 0.0, TOLERANCE))
2130 {
2131 // The linking line runs either W-E or E-W
2132 if (dXDiff > 0)
2133 // It runs W to E
2134 m_VCoast[nCoast].SetFluxOrientation(nCoastPoint, 90);
2135 else
2136 // It runs E to W
2137 m_VCoast[nCoast].SetFluxOrientation(nCoastPoint, 270);
2138 }
2139 else if (bFPIsEqual(dXDiff, 0.0, TOLERANCE))
2140 {
2141 // The linking line runs N-S or S-N
2142 if (dYDiff > 0)
2143 // It runs S to N
2144 m_VCoast[nCoast].SetFluxOrientation(nCoastPoint, 0);
2145 else
2146 // It runs N to S
2147 m_VCoast[nCoast].SetFluxOrientation(nCoastPoint, 180);
2148 }
2149 else
2150 {
2151 // 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
2152 double dAzimuthAngle;
2153 if (dXDiff > 0)
2154 dAzimuthAngle = (180 / PI) * (PI * 0.5 - atan(dYDiff / dXDiff));
2155 else
2156 dAzimuthAngle = (180 / PI) * (PI * 1.5 - atan(dYDiff / dXDiff));
2157
2158 m_VCoast[nCoast].SetFluxOrientation(nCoastPoint, dAzimuthAngle);
2159 }
2160
2161 // LogStream << m_ulIter << ": nCoastPoint = " << nCoastPoint << " FluxOrientation = " << m_VCoast[nCoast].dGetFluxOrientation(nCoastPoint) << endl;
2162 }
2163}
2164
2165//===============================================================================================================================
2167//===============================================================================================================================
2169{
2170 vector<int> VnPolygonD50Count(m_nNumPolygonGlobal + 1, 0); // TODO 044
2171 vector<double> VdPolygonD50(m_nNumPolygonGlobal + 1, 0); // TODO 044
2172
2173 for (int nX = 0; nX < m_nXGridSize; nX++)
2174 {
2175 for (int nY = 0; nY < m_nYGridSize; nY++)
2176 {
2177 if (m_pRasterGrid->m_Cell[nX][nY].bIsInContiguousSea())
2178 {
2179 // This is a sea cell, first get polygon ID
2180 int nID = m_pRasterGrid->m_Cell[nX][nY].nGetPolygonID();
2181
2182 // Is it in the active zone?
2183 bool bActive = m_pRasterGrid->m_Cell[nX][nY].bIsInActiveZone();
2184
2185 if (bActive)
2186 {
2187 // 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
2188 double dTmpd50 = m_pRasterGrid->m_Cell[nX][nY].dGetUnconsD50();
2189 if (! bFPIsEqual(dTmpd50, DBL_NODATA, TOLERANCE))
2190 {
2191 // It does have unconsolidated sediment, so which polygon is this cell in?
2192 if (nID != INT_NODATA)
2193 {
2194 VnPolygonD50Count[nID]++;
2195 VdPolygonD50[nID] += dTmpd50;
2196 }
2197 }
2198 }
2199
2200 // // Now fill in wave calc holes
2201 // if (m_pRasterGrid->m_Cell[nX][nY].dGetWaveHeight() == 0)
2202 // {
2203 // if (nID == INT_NODATA)
2204 // m_pRasterGrid->m_Cell[nX][nY].SetWaveHeight(m_dAllCellsDeepWaterWaveHeight);
2205 // }
2206 //
2207 // if (m_pRasterGrid->m_Cell[nX][nY].dGetWaveAngle() == 0)
2208 // {
2209 // if (nID == INT_NODATA)
2210 // m_pRasterGrid->m_Cell[nX][nY].SetWaveAngle(m_dAllCellsDeepWaterWaveAngle);
2211 // }
2212
2213 // Next look at the cell's N-S and W-E neighbours
2214 int nXTmp;
2215 int nYTmp;
2216 int nActive = 0;
2217 int nShadow = 0;
2218 int nShadowNum = 0;
2219 int nDownDrift = 0;
2220 int nDownDriftNum = 0;
2221 int nCoast = 0;
2222 int nRead = 0;
2223 double dWaveHeight = 0;
2224 double dWaveAngle = 0;
2225
2226 // North
2227 nXTmp = nX;
2228 nYTmp = nY - 1;
2229 if (bIsWithinValidGrid(nXTmp, nYTmp))
2230 {
2231 if (m_pRasterGrid->m_Cell[nXTmp][nYTmp].bIsInContiguousSea())
2232 {
2233 nRead++;
2234 dWaveHeight += m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetWaveHeight();
2235 dWaveAngle += (m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetWaveAngle());
2236
2237 if (m_pRasterGrid->m_Cell[nXTmp][nYTmp].bIsInActiveZone())
2238 nActive++;
2239
2240 int nTmp = m_pRasterGrid->m_Cell[nXTmp][nYTmp].nGetShadowZoneNumber();
2241 if (nTmp != 0)
2242 {
2243 nShadow++;
2244 nShadowNum = nTmp;
2245 }
2246
2247 nTmp = m_pRasterGrid->m_Cell[nXTmp][nYTmp].nGetDownDriftZoneNumber();
2248 if (nTmp > 0)
2249 {
2250 nDownDrift++;
2251 nDownDriftNum = nTmp;
2252 }
2253 }
2254 else
2255 nCoast++;
2256 }
2257
2258 // East
2259 nXTmp = nX + 1;
2260 nYTmp = nY;
2261 if (bIsWithinValidGrid(nXTmp, nYTmp))
2262 {
2263 if (m_pRasterGrid->m_Cell[nXTmp][nYTmp].bIsInContiguousSea())
2264 {
2265 nRead++;
2266 dWaveHeight += m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetWaveHeight();
2267 dWaveAngle += (m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetWaveAngle());
2268
2269 if (m_pRasterGrid->m_Cell[nXTmp][nYTmp].bIsInActiveZone())
2270 nActive++;
2271
2272 int nTmp = m_pRasterGrid->m_Cell[nXTmp][nYTmp].nGetShadowZoneNumber();
2273 if (nTmp != 0)
2274 {
2275 nShadow++;
2276 nShadowNum = nTmp;
2277 }
2278
2279 nTmp = m_pRasterGrid->m_Cell[nXTmp][nYTmp].nGetDownDriftZoneNumber();
2280 if (nTmp > 0)
2281 {
2282 nDownDrift++;
2283 nDownDriftNum = nTmp;
2284 }
2285 }
2286 else
2287 nCoast++;
2288 }
2289
2290 // South
2291 nXTmp = nX;
2292 nYTmp = nY + 1;
2293 if (bIsWithinValidGrid(nXTmp, nYTmp))
2294 {
2295 if (m_pRasterGrid->m_Cell[nXTmp][nYTmp].bIsInContiguousSea())
2296 {
2297 nRead++;
2298 dWaveHeight += m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetWaveHeight();
2299 dWaveAngle += (m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetWaveAngle());
2300
2301 if (m_pRasterGrid->m_Cell[nXTmp][nYTmp].bIsInActiveZone())
2302 nActive++;
2303
2304 int nTmp = m_pRasterGrid->m_Cell[nXTmp][nYTmp].nGetShadowZoneNumber();
2305 if (nTmp != 0)
2306 {
2307 nShadow++;
2308 nShadowNum = nTmp;
2309 }
2310
2311 nTmp = m_pRasterGrid->m_Cell[nXTmp][nYTmp].nGetDownDriftZoneNumber();
2312 if (nTmp > 0)
2313 {
2314 nDownDrift++;
2315 nDownDriftNum = nTmp;
2316 }
2317 }
2318 else
2319 nCoast++;
2320 }
2321
2322 // West
2323 nXTmp = nX - 1;
2324 nYTmp = nY;
2325 if (bIsWithinValidGrid(nXTmp, nYTmp))
2326 {
2327 if (m_pRasterGrid->m_Cell[nXTmp][nYTmp].bIsInContiguousSea())
2328 {
2329 nRead++;
2330 dWaveHeight += m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetWaveHeight();
2331 dWaveAngle += (m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetWaveAngle());
2332
2333 if (m_pRasterGrid->m_Cell[nXTmp][nYTmp].bIsInActiveZone())
2334 nActive++;
2335
2336 int nTmp = m_pRasterGrid->m_Cell[nXTmp][nYTmp].nGetShadowZoneNumber();
2337 if (nTmp != 0)
2338 {
2339 nShadow++;
2340 nShadowNum = nTmp;
2341 }
2342
2343 nTmp = m_pRasterGrid->m_Cell[nXTmp][nYTmp].nGetDownDriftZoneNumber();
2344 if (nTmp > 0)
2345 {
2346 nDownDrift++;
2347 nDownDriftNum = nTmp;
2348 }
2349 }
2350 else
2351 nCoast++;
2352 }
2353
2354 if (nRead > 0)
2355 {
2356 // Calculate the average of neighbours
2357 dWaveHeight /= nRead;
2358 dWaveAngle /= nRead;
2359 dWaveAngle = dKeepWithin360(dWaveAngle);
2360
2361 // 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
2362 if (nActive == 4)
2363 {
2364 m_pRasterGrid->m_Cell[nX][nY].SetInActiveZone(true);
2365 m_pRasterGrid->m_Cell[nX][nY].SetWaveHeight(dWaveHeight);
2366 m_pRasterGrid->m_Cell[nX][nY].SetWaveAngle(dWaveAngle);
2367 }
2368
2369 // 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
2370 double dDeepWaterWaveHeight = m_pRasterGrid->m_Cell[nX][nY].dGetCellDeepWaterWaveHeight();
2371 if ((bFPIsEqual(m_pRasterGrid->m_Cell[nX][nY].dGetWaveHeight(), dDeepWaterWaveHeight, TOLERANCE)) && (! bFPIsEqual(dDeepWaterWaveHeight, dWaveHeight, TOLERANCE)))
2372 {
2373 m_pRasterGrid->m_Cell[nX][nY].SetWaveHeight(dWaveHeight);
2374 }
2375
2376 // 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
2377 double dDeepWaterWaveAngle = m_pRasterGrid->m_Cell[nX][nY].dGetCellDeepWaterWaveAngle();
2378 if ((bFPIsEqual(m_pRasterGrid->m_Cell[nX][nY].dGetWaveAngle(), dDeepWaterWaveAngle, TOLERANCE)) && (! bFPIsEqual(dDeepWaterWaveAngle, dWaveAngle, TOLERANCE)))
2379 {
2380 m_pRasterGrid->m_Cell[nX][nY].SetWaveAngle(dWaveAngle);
2381 }
2382
2383 // 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)?
2384 int nShadowZoneCode = m_pRasterGrid->m_Cell[nX][nY].nGetShadowZoneNumber();
2385 if (nShadowZoneCode <= 0)
2386 {
2387 // 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
2388 if ((nShadow == 4) || (nShadow + nDownDrift == 4) || (nShadow + nCoast == 4))
2389 {
2390 m_pRasterGrid->m_Cell[nX][nY].SetShadowZoneNumber(nShadowNum);
2391 m_pRasterGrid->m_Cell[nX][nY].SetWaveHeight(dWaveHeight);
2392 m_pRasterGrid->m_Cell[nX][nY].SetWaveAngle(dWaveAngle);
2393 }
2394 }
2395
2396 // 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
2397 int nDownDriftZoneCode = m_pRasterGrid->m_Cell[nX][nY].nGetDownDriftZoneNumber();
2398 if ((nDownDriftZoneCode == 0) && (nDownDrift == 4))
2399 {
2400 m_pRasterGrid->m_Cell[nX][nY].SetDownDriftZoneNumber(nDownDriftNum);
2401 m_pRasterGrid->m_Cell[nX][nY].SetWaveHeight(dWaveHeight);
2402 m_pRasterGrid->m_Cell[nX][nY].SetWaveAngle(dWaveAngle);
2403 }
2404 }
2405 }
2406 }
2407 }
2408
2409 // Calculate the average d50 for every polygon TODO 044
2410 for (int nCoast = 0; nCoast < static_cast<int>(m_VCoast.size()); nCoast++)
2411 {
2412 for (int nPoly = 0; nPoly < m_VCoast[nCoast].nGetNumPolygons(); nPoly++)
2413 {
2414 CGeomCoastPolygon* pPolygon = m_VCoast[nCoast].pGetPolygon(nPoly);
2415 int nID = pPolygon->nGetCoastID();
2416
2417 if (VnPolygonD50Count[nID] > 0)
2418 VdPolygonD50[nID] /= VnPolygonD50Count[nID];
2419
2420 pPolygon->SetAvgUnconsD50(VdPolygonD50[nID]);
2421 }
2422 }
2423}
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.
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:565
double dGetProfileDeepWaterWaveHeight(void) const
Returns the deep-water wave height for this profile.
Definition profile.cpp:553
int nGetCoastPoint(void) const
Returns the coast point at which the profile starts.
Definition profile.cpp:78
CGeomProfile * pGetDownCoastAdjacentProfile(void) const
Definition profile.cpp:449
CGeom2DIPoint * pPtiGetCellInProfile(int const)
Returns a single cell in the profile.
Definition profile.cpp:482
int nGetNumCellsInProfile(void) const
Returns the number of cells in the profile.
Definition profile.cpp:489
void SetCShoreProblem(bool const)
Sets a switch to indicate whether this profile has a CShore problem.
Definition profile.cpp:126
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:231
int nGetCoastID(void) const
Returns the profile's coast ID.
Definition profile.cpp:66
bool bStartOfCoast(void) const
Returns the switch to indicate whether this is a start-of-coast profile.
Definition profile.cpp:108
vector< CGeom2DIPoint > * pPtiVGetCellsInProfile(void)
Returns all cells in the profile.
Definition profile.cpp:475
bool bEndOfCoast(void) const
Returns the switch to indicate whether this is an end-of-coast profile.
Definition profile.cpp:120
double dGetProfileDeepWaterWavePeriod(void) const
Returns the deep-water wave Period for this profile.
Definition profile.cpp:577
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:530
double m_dAllCellsDeepWaterWaveHeight
Deep water wave height (m) for all sea cells.
Definition simulation.h:709
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:766
double m_dThisIterSWL
The still water level for this timestep (this includes tidal changes and any long-term SWL change)
Definition simulation.h:667
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:431
double m_dL_0
Deep water wave length (m)
Definition simulation.h:700
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:362
int m_nYGridSize
The size of the grid in the y direction.
Definition simulation.h:434
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:703
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:533
double m_dBreakingWaveHeightDepthRatio
Breaking wave height-to-depth ratio.
Definition simulation.h:706
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:506
double m_dAllCellsDeepWaterWaveAngle
Deep water wave angle for all sea cells.
Definition simulation.h:712
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:631
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:697
unsigned long m_ulIter
The number of the current iteration (time step)
Definition simulation.h:553
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:482
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:772
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:652
int const INT_NODATA
Definition cme.h:362
T tMin(T a, T b)
Definition cme.h:1136
int const WAVE_MODEL_COVE
Definition cme.h:665
double const TOLERANCE
Definition cme.h:698
int const RTN_ERR_NO_TOP_LAYER
Definition cme.h:623
string const CSHORE_DIR
Definition cme.h:772
int const RTN_ERR_CSHORE_FILE_INPUT
Definition cme.h:631
string const ERR
Definition cme.h:775
double const CSHORE_FRICTION_FACTOR
Definition cme.h:695
int const WAVE_MODEL_CSHORE
Definition cme.h:666
int const LOG_FILE_MIDDLE_DETAIL
Definition cme.h:377
double const PI
Definition cme.h:680
int const RTN_ERR_CSHORE_ERROR
Definition cme.h:636
bool bFPIsEqual(const T d1, const T d2, const T dEpsilon)
Definition cme.h:1176
double const WALKDEN_HALL_PARAM_2
Definition cme.h:688
T tMax(T a, T b)
Definition cme.h:1123
int const RTN_ERR_READING_CSHORE_FILE_OUTPUT
Definition cme.h:632
double const CSHORE_SURGE_LEVEL
Definition cme.h:696
string const WARN
Definition cme.h:776
int const RTN_OK
Definition cme.h:577
bool const SAVE_CSHORE_OUTPUT
Definition cme.h:347
double const DBL_NODATA
Definition cme.h:707
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:358
double const WALKDEN_HALL_PARAM_1
Definition cme.h:687
T tAbs(T a)
Definition cme.h:1148
int const RTN_ERR_CSHORE_EMPTY_PROFILE
Definition cme.h:630
string const CSHORE_INFILE
Definition cme.h:773
int const LEFT_HANDED
Definition cme.h:398
char const SPACE
Definition cme.h:341
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.