CoastalME (Coastal Modelling Environment)
Simulates the long-term behaviour of complex coastlines
Loading...
Searching...
No Matches
do_shore_platform_erosion.cpp
Go to the documentation of this file.
1
10
11/* ==============================================================================================================================
12 This file is part of CoastalME, the Coastal Modelling Environment.
13
14 CoastalME is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19==============================================================================================================================*/
20#include <assert.h>
21
22#include <cmath>
23
24#include <iostream>
25using std::cerr;
26using std::endl;
27using std::ios;
28
29#include <array>
30using std::array;
31
32#include <algorithm>
33using std::shuffle;
34
35#include "cme.h"
36#include "hermite_cubic.h"
37#include "simulation.h"
38#include "coast.h"
39#include "2di_point.h"
40
41//===============================================================================================================================
43//===============================================================================================================================
45{
47 LogStream << m_ulIter << ": Calculating shore platform erosion" << endl;
48
49 // // DEBUG CODE ===========================================================================================================
50 // string strOutFile = m_strOutPath + "01_polygon_shore_platform_test_";
51 // strOutFile += to_string(m_ulIter);
52 // strOutFile += ".tif";
53 //
54 // GDALDriver* pDriver = GetGDALDriverManager()->GetDriverByName("gtiff");
55 // GDALDataset* pDataSet = pDriver->Create(strOutFile.c_str(), m_nXGridSize, m_nYGridSize, 1, GDT_Float64, m_papszGDALRasterOptions);
56 // pDataSet->SetProjection(m_strGDALBasementDEMProjection.c_str());
57 // pDataSet->SetGeoTransform(m_dGeoTransform);
58 // double* pdRaster = new double[m_nXGridSize * m_nYGridSize];
59 // int n = 0;
60 // int nInPoly = 0;
61 // int nNotInPoly = 0;
62 //
63 // for (int nY = 0; nY < m_nYGridSize; nY++)
64 // {
65 // for (int nX = 0; nX < m_nXGridSize; nX++)
66 // {
67 // int nID = m_pRasterGrid->m_Cell[nX][nY].nGetPolygonID();
68 // if (nID == INT_NODATA)
69 // nNotInPoly++;
70 // else
71 // nInPoly++;
72 //
73 // pdRaster[n++] = nID;
74 // }
75 // }
76 //
77 // GDALRasterBand* pBand = pDataSet->GetRasterBand(1);
78 // pBand->SetNoDataValue(m_dMissingValue);
79 // int nRet = pBand->RasterIO(GF_Write, 0, 0, m_nXGridSize, m_nYGridSize, pdRaster, m_nXGridSize, m_nYGridSize, GDT_Float64, 0, 0, NULL);
80 // if (nRet == CE_Failure)
81 // LogStream << nRet << endl;
82 //
83 // GDALClose(pDataSet);
84 // delete[] pdRaster;
85 //
86 // LogStream << m_ulIter << " Number of cells in a polygon = " << nInPoly << endl;
87 // LogStream << m_ulIter << " Number of cells not in any polygon = " << nNotInPoly << endl;
88 // // DEBUG CODE ===========================================================================================================
89
90 // TODO 023 Only do potential erosion if cell is in a polygon
91
92 // Set direction
93 static bool bDownCoast = true;
94
95 // Do this for each coast
96 for (int nCoast = 0; nCoast < static_cast<int>(m_VCoast.size()); nCoast++)
97 {
98 int const nNumProfiles = m_VCoast[nCoast].nGetNumProfiles();
99
100 // Calculate potential platform erosion along each coastline-normal profile, do in down-coast sequence
101 for (int nn = 0; nn < nNumProfiles; nn++)
102 {
103 CGeomProfile *pProfile;
104
105 if (bDownCoast)
106 pProfile = m_VCoast[nCoast].pGetProfileWithDownCoastSeq(nn);
107 else
108 pProfile = m_VCoast[nCoast].pGetProfileWithUpCoastSeq(nn);
109
110 int const nRet = nCalcPotentialPlatformErosionOnProfile(nCoast, pProfile);
111 if (nRet != RTN_OK)
112 return nRet;
113 }
114
115 // Calculate potential platform erosion between the coastline-normal profiles. Do this in down-coast sequence
116 for (int nn = 0; nn < nNumProfiles - 1; nn++)
117 {
118 CGeomProfile *pProfile = m_VCoast[nCoast].pGetProfileWithDownCoastSeq(nn);
119
120 // Calculate potential erosion for sea cells between this profile and the next profile (or up to the edge of the grid) on these cells
122 if (nRet != RTN_OK)
123 return nRet;
124
126 if (nRet != RTN_OK)
127 return nRet;
128 }
129 }
130
131 // Swap direction for next timestep
132 bDownCoast = ! bDownCoast;
133
134 // Fills in 'holes' in the potential platform erosion i.e. orphan cells which get omitted because of rounding problems
136
137 // Do the same for beach protection
139
140 // Finally calculate actual platform erosion on all sea cells (both on profiles, and between profiles)
141 for (int nX = 0; nX < m_nXGridSize; nX++)
142 {
143 for (int nY = 0; nY < m_nYGridSize; nY++)
144 {
145 if (m_pRasterGrid->m_Cell[nX][nY].bPotentialPlatformErosion())
146 // Calculate actual (supply-limited) shore platform erosion on each cell that has potential platform erosion, also add the eroded sand/coarse sediment to that cell's polygon, ready to be redistributed within the polygon during beach erosion/deposition
148 }
149 }
150
152 {
153 LogStream << m_ulIter << ": \ttotal potential shore platform erosion (m^3) = " << m_dThisIterPotentialPlatformErosion * m_dCellArea << " (on profiles = " << m_dTotPotentialPlatformErosionOnProfiles * m_dCellArea << ", between profiles = " << m_dTotPotentialPlatformErosionBetweenProfiles * m_dCellArea << ")" << endl;
154
156 }
157
158 return RTN_OK;
159}
160
161//===============================================================================================================================
163//===============================================================================================================================
165{
166 // Only work on this profile if it is problem-free TODO 024 Or if it has just hit dry land?
167 if (! pProfile->bOKIncStartAndEndOfCoast()) // || (pProfile->nGetProblemCode() == PROFILE_DRYLAND))
168 return RTN_OK;
169
170 // Get the length of the profile (in cells) and the index of the coast point at which this profile starts
171 int const nProfSize = pProfile->nGetNumCellsInProfile();
172 int const nCoastPoint = pProfile->nGetCoastPoint();
173
174 // Get the breaking depth for this profile from the coastline point
175 double const dDepthOfBreaking = m_VCoast[nCoast].dGetDepthOfBreaking(nCoastPoint);
176
177 if (bFPIsEqual(dDepthOfBreaking, DBL_NODATA, TOLERANCE))
178 // This profile is not in the active zone, so no platform erosion here
179 return RTN_OK;
180
181 if (bFPIsEqual(dDepthOfBreaking, 0.0, TOLERANCE))
182 {
183 // Safety check, altho' this shouldn't happen
185 LogStream << m_ulIter << ": depth of breaking is zero for profile " << pProfile->nGetProfileID() << " of coast " << nCoast << endl;
186
187 return RTN_OK;
188 }
189
190 // LogStream << m_ulIter << ": ON PROFILE nProfile = " << nProfile << " dDepthOfBreaking = " << dDepthOfBreaking << endl;
191
192 // Get the height of the associated breaking wave from the coast point: this height is used in beach protection calcs
193 double const dBreakingWaveHeight = m_VCoast[nCoast].dGetBreakingWaveHeight(nCoastPoint);
194
195 // Calculate the length of the profile in external CRS units
196 int const nSegments = pProfile->nGetProfileSize() - 1;
197 double dProfileLenXY = 0;
198
199 for (int nSeg = 0; nSeg < nSegments; nSeg++)
200 {
201 // Do once for every line segment
202 double const dSegStartX = pProfile->pPtGetPointInProfile(nSeg)->dGetX();
203 double const dSegStartY = pProfile->pPtGetPointInProfile(nSeg)->dGetY();
204 double const dSegEndX = pProfile->pPtGetPointInProfile(nSeg + 1)->dGetX(); // Is OK
205 double const dSegEndY = pProfile->pPtGetPointInProfile(nSeg + 1)->dGetY();
206
207 double const dSegLen = hypot(dSegStartX - dSegEndX, dSegStartY - dSegEndY);
208 dProfileLenXY += dSegLen;
209 }
210
211 // Next calculate the average distance between profile points, again in external CRS units. Assume that the sample points are equally spaced along the profile (not quite true)
212 double const dSpacingXY = dProfileLenXY / (nProfSize - 1);
213
214 // 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). 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
215 vector<double> VdProfileZ(nProfSize, 0); // Initial (pre-erosion) elevation of both consolidated and unconsolidated sediment for cells 'under' the profile
216 vector<double> VdProfileDistXY(nProfSize, 0); // Along-profile distance measured from the coast, in external CRS units
217 vector<double> dVConsProfileZ(nProfSize, 0); // Initial (pre-erosion) elevation of consolidated sediment only for cells 'under' the profile
218 vector<double> dVConsZDiff(nProfSize, 0);
219 vector<double> dVConsSlope(nProfSize, 0);
220
221 for (int i = 0; i < nProfSize; i++)
222 {
223 int const nX = pProfile->pPtiVGetCellsInProfile()->at(i).nGetX();
224 int const nY = pProfile->pPtiVGetCellsInProfile()->at(i).nGetY();
225
226 // Get the number of the highest layer with non-zero thickness
227 int const nTopLayer = m_pRasterGrid->m_Cell[nX][nY].nGetTopNonZeroLayerAboveBasement();
228
229 // Safety check
230 if (nTopLayer == INT_NODATA)
232
233 if (nTopLayer == NO_NONZERO_THICKNESS_LAYERS)
234 // TODO 025 We are down to basement
235 return RTN_OK;
236
237 // Get the elevation for consolidated sediment only on this cell
238 dVConsProfileZ[i] = m_pRasterGrid->m_Cell[nX][nY].dGetConsSedTopElevForLayerAboveBasement(nTopLayer);
239
240 // Get the elevation for both consolidated and unconsolidated sediment on this cell (ignore any talus)
241 VdProfileZ[i] = m_pRasterGrid->m_Cell[nX][nY].dGetAllSedTopElevOmitTalus();
242
243 // And store the X-Y plane distance from the start of the profile
244 VdProfileDistXY[i] = i * dSpacingXY;
245 }
246
247 for (int i = 0; i < nProfSize - 1; i++)
248 {
249 // For the consolidated-only profile, get the Z differences (already in external CRS units)
250 dVConsZDiff[i] = dVConsProfileZ[i] - dVConsProfileZ[i + 1];
251
252 // Calculate dZ/dXY, the Z slope (i.e. rise over run) in the XY direction. Note that we use the elevation difference on the seaward side of 'this' point
253 dVConsSlope[i] = dVConsZDiff[i] / dSpacingXY;
254 }
255
256 // Sort out the final value
257 dVConsSlope[nProfSize - 1] = dVConsSlope[nProfSize - 2];
258
260 {
261 // Smooth the vector of slopes for the consolidated-only profile
262 dVConsSlope = dVSmoothProfileSlope(&dVConsSlope);
263 }
264
265 vector<double> dVProfileDepthOverDB(nProfSize, 0); // Depth over wave breaking depth at the coastline-normal sample points
266 vector<double> dVProfileErosionPotential(nProfSize, 0); // Erosion potential at the coastline-normal sample points
267
268 // Calculate the erosion potential along this profile using the shape function
269 double dTotalErosionPotential = 0;
270
271 for (int i = 0; i < nProfSize; i++)
272 {
273 // Use the actual depth of water here (i.e. the depth to the top of the unconsolidated sediment, including the thickness of consolidated sediment beneath it)
274 dVProfileDepthOverDB[i] = m_dThisIterSWL - VdProfileZ[i];
275 dVProfileDepthOverDB[i] /= dDepthOfBreaking;
276
277 // Constrain dDepthOverDB[i] to be between 0 (can get small -ve values due to rounding errors) and m_dDepthOverDBMax
278 dVProfileDepthOverDB[i] = tMax(dVProfileDepthOverDB[i], 0.0);
279 dVProfileDepthOverDB[i] = tMin(dVProfileDepthOverDB[i], m_dDepthOverDBMax);
280
281 // And then use the look-up table to find the value of erosion potential at this point on the profile
282 dVProfileErosionPotential[i] = dLookUpErosionPotential(dVProfileDepthOverDB[i]);
283
284 // If erosion potential (a -ve value) is tiny, set it to zero
285 if (dVProfileErosionPotential[i] > -SED_ELEV_TOLERANCE)
286 dVProfileErosionPotential[i] = 0;
287
288 // Keep track of the total erosion potential for this profile
289 dTotalErosionPotential += dVProfileErosionPotential[i];
290 }
291
292 // Constrain erosion potential at every point on the profile, so that the integral of erosion potential on the whole profile is unity (Walkden and Hall 2005). Note that here, erosion potential is -ve so we must constrain to -1
293 for (int i = 0; i < nProfSize; i++)
294 {
295 if (dTotalErosionPotential < 0)
296 dVProfileErosionPotential[i] /= (-dTotalErosionPotential);
297 }
298
299 vector<double> dVRecessionXY(nProfSize, 0);
300 vector<double> dVSCAPEXY(nProfSize, 0);
301
302 // Calculate recession at every point on the coastline-normal profile
303 for (int i = 0; i < nProfSize; i++)
304 {
305 // dRecession = dForce * (dBeachProtection / dR) * dErosionPotential * dSlope * dTime where:
306 // dVRecession [m] is the landward migration distance defined in the profile relative (XY) CRS
307 // dForce is given by Equation 4 in Walkden & Hall, 2005
308 // dVBeachProtection [1] is beach protection factor [1, 0] = [no protection, fully protected]. (This is calculated later, see dCalcBeachProtectionFactor())
309 // dVR [m^(9/4)s^(2/3)] is the material strength and some hydrodynamic constant
310 // dVProfileErosionPotential [?] is the erosion potential at each point along the profile
311 // dVSlope [1] is the along-profile slope
312 // m_dTimeStep * 3600 [s] is the time interval in seconds
313 //
314 // dRecession is horizontal recession (along the XY direction):
315 //
316 // dVRecessionXY[i] = (dForce * dVBeachProtection[i] * dVErosionPotentialFunc[i] * dVSlope[i] * m_dTimeStep * 3600) / dVR[i]
317 //
318 // XY recession must be -ve or zero. If it is +ve then it represents accretion not erosion, which must be described by a different set of equations. So we also need to constrain XY recession to be <= 0
319 dVRecessionXY[i] = tMin(m_VCoast[nCoast].dGetWaveEnergyAtBreaking(nCoastPoint) * dVProfileErosionPotential[i] * dVConsSlope[i] / m_dR, 0.0);
320 dVSCAPEXY[i] = VdProfileDistXY[i] - dVRecessionXY[i];
321 }
322
323 vector<double> dVChangeElevZ(nProfSize, 0);
324
325 // We have calculated the XY-plane recession at every point on the profile, so now convert this to a change in Z-plane elevation at every inundated point on the profile (not the coast point). Again we use the elevation difference on the seaward side of 'this' point
326 for (int i = 1; i < nProfSize - 1; i++)
327 {
328 // Vertical lowering dZ = dXY * tan(a), where tan(a) is the slope of the SCAPE profile in the XY direction
329 double const dSCAPEHorizDist = dVSCAPEXY[i + 1] - dVSCAPEXY[i];
330 double const dSCAPEVertDist = dVConsProfileZ[i] - dVConsProfileZ[i + 1];
331 double const dSCAPESlope = dSCAPEVertDist / dSCAPEHorizDist;
332 double dDeltaZ = dVRecessionXY[i] * dSCAPESlope;
333
334 // Safety check: if thickness model has some jumps, dVConsProfileZ might be very high, limiting dSCAPESlope to 0 because all time erode a high fix quantity
335 if (dSCAPESlope > 1)
336 dDeltaZ = 0;
337
338 int const nX = pProfile->pPtiVGetCellsInProfile()->at(i).nGetX();
339 int const nY = pProfile->pPtiVGetCellsInProfile()->at(i).nGetY();
340
341 // Store the local slope of the consolidated sediment, this is just for output display purposes
342 m_pRasterGrid->m_Cell[nX][nY].SetLocalConsSlope(dVConsSlope[i]);
343
344 // dDeltaZ is zero or -ve: if dDeltaZ is zero then do nothing, if -ve then remove some sediment from this cell
345 if (dDeltaZ < 0)
346 {
347 // If there has already been potential erosion on this cell, then it must be a shared line segment (i.e. has co-incident profiles)
348 double const dPrevPotentialErosion = -m_pRasterGrid->m_Cell[nX][nY].dGetPotentialPlatformErosion();
349
350 if (dPrevPotentialErosion < 0)
351 {
352 // Average the two values
353 // LogStream << m_ulIter << ": [" << nX << "][" << nY << "] under profile " << nProfile << " has previous potential platform erosion = " << dPrevPotentialErosion << endl;
354 dDeltaZ = ((dDeltaZ + dPrevPotentialErosion) / 2);
355 }
356
357 // Constrain the lowering so we don't get negative slopes or +ve erosion amounts (dDeltaZ must be -ve), this is implicit in SCAPE
358 dDeltaZ = tMax(dDeltaZ, -dVConsZDiff[i]);
359 dDeltaZ = tMin(dDeltaZ, 0.0);
360 dVChangeElevZ[i] = dDeltaZ;
361
362 // Set the potential (unconstrained) erosion for this cell, is a +ve value
363 m_pRasterGrid->m_Cell[nX][nY].SetPotentialPlatformErosion(-dDeltaZ);
364
365 // Update this-timestep totals
367 m_dThisIterPotentialPlatformErosion -= dDeltaZ; // Since dDeltaZ is a -ve value
368
369 // Increment the check values
372 }
373
374 // Finally, calculate the beach protection factor, this will be used in estimating actual (supply-limited) erosion
375 double const dBeachProtectionFactor = dCalcBeachProtectionFactor(nX, nY, dBreakingWaveHeight);
376 m_pRasterGrid->m_Cell[nX][nY].SetBeachProtectionFactor(dBeachProtectionFactor);
377 }
378
379 // If desired, save this coastline-normal consolidated-only profile data for checking purposes
381 {
382 int const nRet = nSaveProfile(nCoast, pProfile, nProfSize, &VdProfileDistXY, &dVConsProfileZ, &dVProfileDepthOverDB, &dVProfileErosionPotential, &dVConsSlope, &dVRecessionXY, &dVChangeElevZ, pProfile->pPtiVGetCellsInProfile(), &dVSCAPEXY);
383 if (nRet != RTN_OK)
384 return nRet;
385 }
386
387 return RTN_OK;
388}
389
390//===============================================================================================================================
392//===============================================================================================================================
393int CSimulation::nCalcPotentialPlatformErosionBetweenProfiles(int const nCoast, CGeomProfile *pProfile, int const nDirection)
394{
395 // Only work on this profile if it is problem-free
396 if (! pProfile->bOKIncStartAndEndOfCoast())
397 return RTN_OK;
398
399 int const nProfSize = pProfile->nGetNumCellsInProfile();
400 int const nCoastProfileStart = pProfile->nGetCoastPoint();
401 int const nProfileStartX = pProfile->pPtiVGetCellsInProfile()->at(0).nGetX();
402 int const nProfileStartY = pProfile->pPtiVGetCellsInProfile()->at(0).nGetY();
403 int const nCoastMax = m_VCoast[nCoast].nGetCoastlineSize();
404 int nDistFromProfile = 0;
405 int nParCoastXLast = nProfileStartX;
406 int nParCoastYLast = nProfileStartY;
407
408 // Start at the coast end of this coastline-normal profile, then move one cell forward along the coast, then construct a parallel profile from this new coastline start cell. Calculate erosion along this parallel profile in the same way as above. Move another cell forward along the coastline, do the same. Keep going until hit another profile
409 while (true)
410 {
411 // Increment the distance from the start coast-normal profile
412 nDistFromProfile++;
413
414 // Start the parallel profile nDistFromProfile cells along the coastline from the coastline-normal profile, direction depending on nDirection
415 int nThisPointOnCoast = nCoastProfileStart;
416
417 if (nDirection == DIRECTION_DOWNCOAST)
418 nThisPointOnCoast += nDistFromProfile;
419 else
420 nThisPointOnCoast -= nDistFromProfile;
421
422 // Have we reached the beginning of the coast?
423 if ((nDirection == DIRECTION_UPCOAST) && (nThisPointOnCoast < 0))
424 {
425 // LogStream << m_ulIter << ": LEAVING LOOP since hit nThisPointOnCoast = " << nThisPointOnCoast << " while doing potential platform erosion " << (nDirection == DIRECTION_DOWNCOAST ? "down" : "up") << "-coast from profile = " << nProfile << ", dist from profile = " << nDistFromProfile << endl;
426 break;
427 }
428
429 // Have we reached the end of the coast?
430 if ((nDirection == DIRECTION_DOWNCOAST) && (nThisPointOnCoast >= nCoastMax))
431 {
432 // LogStream << m_ulIter << ": LEAVING LOOP since hit nThisPointOnCoast = " << nThisPointOnCoast << " while doing potential platform erosion " << (nDirection == DIRECTION_DOWNCOAST ? "down" : "up") << "-coast from profile = " << nProfile << ", dist from profile = " << nDistFromProfile << endl;
433 break;
434 }
435
436 // LogStream << m_ulIter << ": from profile " << nProfile << ", doing potential platform erosion " << (nDirection == DIRECTION_DOWNCOAST ? "down" : "up") << "-coast, dist from profile = " << nDistFromProfile << endl;
437
438 double dDepthOfBreaking = m_VCoast[nCoast].dGetDepthOfBreaking(nThisPointOnCoast);
439
440 if (bFPIsEqual(dDepthOfBreaking, DBL_NODATA, TOLERANCE))
441 {
442 // This parallel profile is not in the active zone, so no platform erosion here. Move on to the next point along the coastline in this direction
443 // if (m_nLogFileDetail == LOG_FILE_ALL)
444 // LogStream << m_ulIter << ": not in active zone at coastline " << nCoast << " coast point " << nThisPointOnCoast << " when constructing parallel profile for potential platform erosion. Working from profile " << pProfile->nGetProfileID() << ", " << (nDirection == DIRECTION_DOWNCOAST ? "down" : "up") << "-coast, dist from profile = " << nDistFromProfile << endl;
445 continue;
446 }
447
448 // LogStream << m_ulIter << ": BETWEEN PROFILES " << (nDirection == DIRECTION_DOWNCOAST ? "down" : "up") << "-coast from profile " << nProfile << " nThisPointOnCoast = " << nThisPointOnCoast << " dDepthOfBreaking = " << dDepthOfBreaking << " nParProfSize = " << nParProfSize << endl;
449
450 // All is OK, so get the grid coordinates of this point, which is the coastline start point for the parallel profile
451 int const nParCoastX = m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(nThisPointOnCoast)->nGetX();
452 int const nParCoastY = m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(nThisPointOnCoast)->nGetY();
453
454 if ((nParCoastX == nParCoastXLast) && (nParCoastY == nParCoastYLast))
455 {
456 // Should not happen, but could do due to rounding errors
457 // if (m_nLogFileDetail >= LOG_FILE_ALL)
458 // LogStream << WARN << m_ulIter << ": rounding problem on coast " << nCoast << " profile " << pProfile->nGetProfileID() << " at [" << nParCoastX << "][" << nParCoastY << "]" << endl;
459
460 // So move on to the next point along the coastline in this direction
461 continue;
462 }
463
464 // Is this coastline start point the start point of an adjacent coastline-normal vector?
465 if (m_pRasterGrid->m_Cell[nParCoastX][nParCoastY].bIsProfile())
466 {
467 // LogStream << m_ulIter << ": coast " << nCoast << ", LEAVING LOOP since hit another profile at nThisPointOnCoast = " << nThisPointOnCoast << " while doing potential platform erosion " << (nDirection == DIRECTION_DOWNCOAST ? "down" : "up") << "-coast from profile = " << nProfile << ", dist from profile = " << nDistFromProfile << endl;
468 break;
469 }
470
471 // Get the height of the associated breaking wave from the coast point: this height is used in beach protection calcs. Note that it will be DBL_NODATA if not in active zone
472 double const dBreakingWaveHeight = m_VCoast[nCoast].dGetBreakingWaveHeight(nThisPointOnCoast);
473
474 // OK, now construct a parallel profile
475 vector<CGeom2DIPoint> PtiVGridParProfile; // Integer coords (grid CRS) of cells under the parallel profile
476 vector<CGeom2DPoint> PtVExtCRSParProfile; // coordinates (external CRS) of cells under the parallel profile
477
478 ConstructParallelProfile(nProfileStartX, nProfileStartY, nParCoastX, nParCoastY, nProfSize, pProfile->pPtiVGetCellsInProfile(), &PtiVGridParProfile, &PtVExtCRSParProfile);
479
480 int const nParProfSize = static_cast<int>(PtiVGridParProfile.size());
481
482 // We have a parallel profile which starts at the coast, but is it long enough to be useful? May have been cut short because it extended outside the grid, or we hit an adjacent profile
483 if (nParProfSize < 3)
484 {
485 // We cannot use this parallel profile, it is too short to calculate along-profile slope, so abandon it and move on to the next parallel profile in this direction
486 nParCoastXLast = nParCoastX;
487 nParCoastYLast = nParCoastY;
488 // LogStream << m_ulIter << ": parallel profile abandoned since too short, starts at [" << nParCoastX << "][" << nParCoastY << "] coastline point " << nThisPointOnCoast << ", length = " << nParProfSize << endl;
489 continue;
490 }
491
492 // This parallel profile is OK, so calculate potential erosion along it. First calculate the length of the parallel profile in external CRS units
493 double const dParProfileLenXY = dGetDistanceBetween(&PtVExtCRSParProfile[0], &PtVExtCRSParProfile[nParProfSize - 1]);
494
495 // Next calculate the distance between profile points, again in external CRS units. Assume that the sample points are equally spaced along the parallel profile (not quite true)
496 double dParSpacingXY = dParProfileLenXY / (nParProfSize - 1);
497
498 // Safety check
499 if (bFPIsEqual(dParSpacingXY, 0.0, TOLERANCE))
500 dParSpacingXY = TOLERANCE;
501
502 // LogStream << "dParSpacingXY = " << dParSpacingXY << endl;
503
504 vector<double> dVParProfileZ(nParProfSize, 0); // Initial (pre-erosion) elevation of both consolidated and unconsolidated sediment for cells 'under' the parallel profile
505 vector<double> dVParProfileDistXY(nParProfSize, 0); // Along-profile distance measured from the coast, in external CRS units
506 vector<double> dVParConsProfileZ(nParProfSize, 0); // Initial (pre-erosion) elevation of consolidated sediment only for cells 'under' the parallel profile
507 vector<double> dVParConsZDiff(nParProfSize, 0);
508 vector<double> dVParConsSlope(nParProfSize, 0);
509
510 for (int i = 0; i < nParProfSize; i++)
511 {
512 int const nXPar = PtiVGridParProfile[i].nGetX();
513 int const nYPar = PtiVGridParProfile[i].nGetY();
514
515 // Is this a sea cell?
516 if (! m_pRasterGrid->m_Cell[nXPar][nYPar].bIsInundated())
517 {
518 // It isn't so move along, nothing to do here
519 // LogStream << m_ulIter << " : [" << nXPar << "][" << nYPar << "] is not inundated" << endl;
520 continue;
521 }
522
523 // Is this cell in a polygon?
524 int const nPolyID = m_pRasterGrid->m_Cell[nXPar][nYPar].nGetPolygonID();
525
526 if (nPolyID == INT_NODATA)
527 {
528 // It isn't. This can happen at the seaward end of polygons TODO 026 Is it a problem?
529 // LogStream << m_ulIter << " : [" << nXPar << "][" << nYPar << "] = {" << dGridCentroidXToExtCRSX(nXPar) << ", " << dGridCentroidYToExtCRSY(nYPar) << "} is not in a polygon" << endl;
530 continue;
531 }
532
533 // Get the number of the highest layer with non-zero thickness
534 int const nTopLayer = m_pRasterGrid->m_Cell[nXPar][nYPar].nGetTopNonZeroLayerAboveBasement();
535
536 // Safety check
537 if (nTopLayer == INT_NODATA)
539
540 if (nTopLayer == NO_NONZERO_THICKNESS_LAYERS)
541 // TODO 025 We are down to basement
542 return RTN_OK;
543
544 // Get the elevation for consolidated sediment only on this cell
545 dVParConsProfileZ[i] = m_pRasterGrid->m_Cell[nXPar][nYPar].dGetConsSedTopElevForLayerAboveBasement(nTopLayer);
546
547 // Get the elevation for both consolidated and unconsolidated sediment on this cell (ignore any talus)
548 dVParProfileZ[i] = m_pRasterGrid->m_Cell[nXPar][nYPar].dGetAllSedTopElevOmitTalus();
549
550 // And store the X-Y plane distance from the start of the profile
551 dVParProfileDistXY[i] = i * dParSpacingXY;
552 }
553
554 for (int i = 0; i < nParProfSize - 1; i++)
555 {
556 // For the consolidated-only profile, get the Z differences (already in external CRS units)
557 dVParConsZDiff[i] = dVParConsProfileZ[i] - dVParConsProfileZ[i + 1];
558
559 // Calculate dZ/dXY, the Z slope (i.e. rise over run) in the XY direction. Note that we use the elevation difference on the seaward side of 'this' point
560 dVParConsSlope[i] = dVParConsZDiff[i] / dParSpacingXY;
561 }
562
563 // Sort out the final slope value
564 dVParConsSlope[nParProfSize - 1] = dVParConsSlope[nParProfSize - 2];
565
567 {
568 // Smooth the vector of slopes for the consolidated-only profile
569 dVParConsSlope = dVSmoothProfileSlope(&dVParConsSlope);
570 }
571
572 // Initialize the parallel profile vector with depth / m_dWaveBreakingDepth
573 vector<double> dVParProfileDepthOverDB(nParProfSize, 0); // Depth / wave breaking depth at the parallel profile sample points
574 vector<double> dVParProfileErosionPotential(nParProfSize, 0); // Erosion potential at the parallel profile sample points
575
576 // Calculate the erosion potential along this profile using the shape function which we read in earlier
577 double dTotalErosionPotential = 0;
578
579 // Safety check TODO 061 Is this safety check to depth of breaking a reasonable thing to do?
580 if (dDepthOfBreaking <= 0.0)
581 dDepthOfBreaking = 1e-10;
582
583 for (int i = 0; i < nParProfSize; i++)
584 {
585 // Use the actual depth of water here (i.e. the depth to the top of the unconsolidated sediment, including the thickness of consolidated sediment beneath it)
586 dVParProfileDepthOverDB[i] = m_dThisIterSWL - dVParProfileZ[i];
587 dVParProfileDepthOverDB[i] /= dDepthOfBreaking;
588
589 // Constrain dDepthOverDB[i] to be between 0 (can get small -ve due to rounding errors) and m_dDepthOverDBMax
590 dVParProfileDepthOverDB[i] = tMax(dVParProfileDepthOverDB[i], 0.0);
591 dVParProfileDepthOverDB[i] = tMin(dVParProfileDepthOverDB[i], m_dDepthOverDBMax);
592
593 // And then use the look-up table to find the value of erosion potential at this point on the profile
594 dVParProfileErosionPotential[i] = dLookUpErosionPotential(dVParProfileDepthOverDB[i]);
595
596 // If erosion potential (a -ve value) is tiny, set it to zero
597 if (dVParProfileErosionPotential[i] > -SED_ELEV_TOLERANCE)
598 dVParProfileErosionPotential[i] = 0;
599
600 // Keep track of the total erosion potential for this profile
601 dTotalErosionPotential += dVParProfileErosionPotential[i];
602 }
603
604 // Constrain erosion potential at every point on the profile, so that the integral of erosion potential on the whole profile is unity (Walkden and Hall 2005). Note that here, erosion potential is -ve so we must constrain to -1
605 for (int i = 0; i < nParProfSize; i++)
606 {
607 if (dTotalErosionPotential < 0)
608 dVParProfileErosionPotential[i] /= (-dTotalErosionPotential);
609 }
610
611 vector<double> dVParRecessionXY(nParProfSize, 0);
612 vector<double> dVParSCAPEXY(nParProfSize, 0);
613
614 // Calculate recession at every point on the parallel profile
615 for (int i = 0; i < nParProfSize; i++)
616 {
617 // dRecession = dForce * (dBeachProtection / dR) * dErosionPotential * dSlope * dTime
618 // where:
619 // dVRecession [m] is the landward migration distance defined in the profile relative (XY) CRS
620 // dForce is given by Equation 4 in Walkden & Hall, 2005
621 // dVBeachProtection [1] is beach protection factor [1, 0] = [no protection, fully protected] (This is calculated later, see dCalcBeachProtectionFactor())
622 // dVR [m^(9/4)s^(2/3)] is the material strength and some hydrodynamic constant
623 // dVProfileErosionPotential [?] is the erosion potential at each point along the profile
624 // dVSlope [1] is the along-profile slope
625 // m_dTimeStep * 3600 [s] is the time interval in seconds
626 //
627 // dRecession is horizontal recession (along the XY direction):
628 //
629 // dVRecessionXY[i] = (dForce * dVBeachProtection[i] * dVErosionPotentialFunc[i] * dVSlope[i] * m_dTimeStep * 3600) / dVR[i]
630 //
631 //
632 // XY recession must be -ve or zero. If it is +ve then it represents accretion not erosion, which must be described by a different set of equations. So we also need to constrain XY recession to be <= 0
633 dVParRecessionXY[i] = tMin(m_VCoast[nCoast].dGetWaveEnergyAtBreaking(nThisPointOnCoast) * dVParProfileErosionPotential[i] * dVParConsSlope[i] / m_dR, 0.0);
634 dVParSCAPEXY[i] = dVParProfileDistXY[i] - dVParRecessionXY[i];
635
636 // LogStream << m_ulIter << ": [" << nXPar << "][" << nYPar << "] = {" << dGridCentroidXToExtCRSX(nXPar) << ", " << dGridCentroidYToExtCRSY(nYPar) << "} wave energy = " << m_VCoast[nCoast].dGetWaveEnergyAtBreaking(nThisPointOnCoast) << " erosion potential = " << dVParProfileErosionPotential[i] << " slope = " << dVParProfileSlope[i] << " dVParZDiff[i] = " << dVParZDiff[i] << " nParProfSize = " << nParProfSize << endl;
637 }
638
639 vector<double> dVParDeltaZ(nParProfSize, 0);
640
641 // We have calculated the XY-plane recession at every point on the profile, so now convert this to a change in Z-plane elevation at every inundated point on the profile (not the coast point). Again we use the elevation difference on the seaward side of 'this' point
642 for (int i = 1; i < nParProfSize - 1; i++)
643 {
644 // Vertical lowering dZ = dXY * tan(a), where tan(a) is the slope of the SCAPE profile in the XY direction
645 double const dSCAPEHorizDist = dVParSCAPEXY[i + 1] - dVParSCAPEXY[i];
646
647 // Safety check
648 if (bFPIsEqual(dSCAPEHorizDist, 0.0, TOLERANCE))
649 continue;
650
651 double const dSCAPEVertDist = dVParConsProfileZ[i] - dVParConsProfileZ[i + 1];
652 double const dSCAPESlope = dSCAPEVertDist / dSCAPEHorizDist;
653 double dDeltaZ = dVParRecessionXY[i] * dSCAPESlope;
654
655 // Safety check: if thickness model has some jumps, dVConsProfileZ might be very high, limiting dSCAPESlope to 0 because all time erode a high fix quantity
656 if (dSCAPESlope > 1)
657 dDeltaZ = 0;
658
659 int const nXPar = PtiVGridParProfile[i].nGetX();
660 int const nYPar = PtiVGridParProfile[i].nGetY();
661
662 // Store the local slope of the consolidated sediment, this is just for output display purposes
663 m_pRasterGrid->m_Cell[nXPar][nYPar].SetLocalConsSlope(dVParConsSlope[i]);
664
665 // dDeltaZ is zero or -ve: if dDeltaZ is zero then do nothing, if -ve then remove some sediment from this cell
666 if (dDeltaZ < 0)
667 {
668 // Has this cell already been eroded during this timestep?
669 if (m_pRasterGrid->m_Cell[nXPar][nYPar].bPotentialPlatformErosion())
670 {
671 // It has
672 double const dPrevPotentialErosion = -m_pRasterGrid->m_Cell[nXPar][nYPar].dGetPotentialPlatformErosion();
673
674 // LogStream << m_ulIter << ": [" << nXPar << "][" << nYPar << "] parallel profile " << nDistFromProfile << " coast points " << (nDirection == DIRECTION_DOWNCOAST ? "down" : "up") << "-coast from profile " << nProfile << " has previous potential platform erosion = " << dPrevPotentialErosion << ", current potential platform erosion = " << dDeltaZ << ", max value = " << tMin(dPrevPotentialErosion, dDeltaZ) << endl;
675
676 // Use the larger of the two -ve values
677 dDeltaZ = tMin(dPrevPotentialErosion, dDeltaZ);
678
679 // Adjust this-timestep totals, since this cell has already been eroded
681 m_dThisIterPotentialPlatformErosion += dPrevPotentialErosion; // Since dPrevPotentialErosion is +ve
682 // assert(isfinite(m_dThisIterPotentialPlatformErosion));
683 // assert(m_dThisIterPotentialPlatformErosion >= 0);
684
685 // And also adjust the check values
687 m_dTotPotentialPlatformErosionBetweenProfiles += dPrevPotentialErosion; // Since -ve
688 }
689
690 // Constrain the lowering so we don't get negative slopes or +ve erosion amounts (dDeltaZ must be -ve), this is implicit in SCAPE
691 dDeltaZ = tMax(dDeltaZ, -dVParConsZDiff[i]);
692 dDeltaZ = tMin(dDeltaZ, 0.0);
693 dVParDeltaZ[i] = dDeltaZ;
694
695 // Set the potential (unconstrained) erosion for this cell, it is a +ve value
696 m_pRasterGrid->m_Cell[nXPar][nYPar].SetPotentialPlatformErosion(-dDeltaZ);
697 // LogStream << "[" << nXPar << "][" << nYPar << "] = {" << dGridCentroidXToExtCRSX(nXPar) << ", " << dGridCentroidYToExtCRSY(nYPar) << "} has potential platform erosion = " << -dDeltaZ << endl;
698
699 // Update this-timestep totals
701 m_dThisIterPotentialPlatformErosion -= dDeltaZ; // Since dDeltaZ is a -ve value
702 // assert(isfinite(m_dThisIterPotentialPlatformErosion));
703 // assert(m_dThisIterPotentialPlatformErosion >= 0);
704
705 // Increment the check values
707 m_dTotPotentialPlatformErosionBetweenProfiles -= dDeltaZ; // Since -ve
708 }
709
710 // Finally, calculate the beach protection factor, this will be used in estimating actual (supply-limited) erosion
711 double const dBeachProtectionFactor = dCalcBeachProtectionFactor(nXPar, nYPar, dBreakingWaveHeight);
712 m_pRasterGrid->m_Cell[nXPar][nYPar].SetBeachProtectionFactor(dBeachProtectionFactor);
713 }
714
715 // If desired, save this parallel coastline-normal profile for checking purposes
717 {
718 int const nRet = nSaveParProfile(nCoast, pProfile, nParProfSize, nDirection, nDistFromProfile, &dVParProfileDistXY, &dVParConsProfileZ, &dVParProfileDepthOverDB, &dVParProfileErosionPotential, &dVParConsSlope, &dVParRecessionXY, &dVParDeltaZ, pProfile->pPtiVGetCellsInProfile(), &dVParSCAPEXY);
719
720 if (nRet != RTN_OK)
721 return nRet;
722 }
723
724 // Update for next time round the loop
725 nParCoastXLast = nParCoastX;
726 nParCoastYLast = nParCoastY;
727 }
728
729 return RTN_OK;
730}
731
732//===============================================================================================================================
734//===============================================================================================================================
735void CSimulation::DoActualPlatformErosionOnCell(int const nX, int const nY)
736{
737 // LogStream << m_ulIter << ": doing platform erosion on cell [" << nX << "][" << nY << "] = {" << dGridCentroidXToExtCRSX(nX) << ", " << dGridCentroidYToExtCRSY(nY) << "}" << endl;
738
739 // Get the beach protection factor, which quantifies the extent to which unconsolidated sediment on the shore platform (beach) protects the shore platform
740 double const dBeachProtectionFactor = m_pRasterGrid->m_Cell[nX][nY].dGetBeachProtectionFactor();
741
742 if (bFPIsEqual(dBeachProtectionFactor, 0.0, TOLERANCE))
743 // The beach is sufficiently thick to prevent any platform erosion (or we are down to basement)
744 return;
745
746 // Get the potential depth of potential erosion, considering beach protection
747 double const dThisPotentialErosion = m_pRasterGrid->m_Cell[nX][nY].dGetPotentialPlatformErosion() * dBeachProtectionFactor;
748
749 // We will be eroding the topmost layer that has non-zero thickness
750 int const nThisLayer = m_pRasterGrid->m_Cell[nX][nY].nGetTopNonZeroLayerAboveBasement();
751
752 // Safety check
753 if (nThisLayer == INT_NODATA)
754 {
755 cerr << ERR << "no sediment layer in DoActualPlatformErosionOnCell()" << endl;
756 return;
757 }
758
759 if (nThisLayer == NO_NONZERO_THICKNESS_LAYERS)
760 // No layer with non-zero thickness left, we are down to basement
761 return;
762
763 // OK, we have a layer that can be eroded so find out how much consolidated sediment we have available on this cell
764 double const dExistingAvailableFine = m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetConsolidatedSediment()->dGetFineDepth();
765 double const dExistingAvailableSand = m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetConsolidatedSediment()->dGetSandDepth();
766 double const dExistingAvailableCoarse = m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetConsolidatedSediment()->dGetCoarseDepth();
767
768 // Now partition the total lowering for this cell between the three size fractions: do this by relative erodibility
769 int const nFineWeight = (dExistingAvailableFine > 0 ? 1 : 0);
770 int const nSandWeight = (dExistingAvailableSand > 0 ? 1 : 0);
771 int const nCoarseWeight = (dExistingAvailableCoarse > 0 ? 1 : 0);
772
773 double const dTotErodibility = (nFineWeight * m_dFineErodibilityNormalized) + (nSandWeight * m_dSandErodibilityNormalized) + (nCoarseWeight * m_dCoarseErodibilityNormalized);
774 double dTotActualErosion = 0;
775 double dSandEroded = 0;
776 double dCoarseEroded = 0;
777
778 if (nFineWeight)
779 {
780 // Erode some fine-sized consolidated sediment
781 double const dFineLowering = (m_dFineErodibilityNormalized * dThisPotentialErosion) / dTotErodibility;
782
783 // Make sure we don't get -ve amounts left on the cell
784 double const dFineEroded = tMin(dExistingAvailableFine, dFineLowering);
785 double const dRemaining = dExistingAvailableFine - dFineEroded;
786
787 dTotActualErosion += dFineEroded;
788
789 // Set the value for this layer
790 m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetConsolidatedSediment()->SetFineDepth(dRemaining);
791
792 // And set the changed-this-timestep switch
793 m_bConsChangedThisIter[nThisLayer] = true;
794
795 // And increment the per-timestep total, also add to the suspended sediment load
798 }
799
800 if (nSandWeight)
801 {
802 // Erode some sand-sized consolidated sediment
803 double const dSandLowering = (m_dSandErodibilityNormalized * dThisPotentialErosion) / dTotErodibility;
804
805 // Make sure we don't get -ve amounts left on the source cell
806 dSandEroded = tMin(dExistingAvailableSand, dSandLowering);
807 double const dRemaining = dExistingAvailableSand - dSandEroded;
808
809 dTotActualErosion += dSandEroded;
810
811 // Set the new value of sand consolidated sediment depth for this layer
812 m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetConsolidatedSediment()->SetSandDepth(dRemaining);
813
814 // And add this to the depth of sand unconsolidated sediment for this layer
815 m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetUnconsolidatedSediment()->AddSandDepth(dSandEroded);
816
817 // Set the changed-this-timestep switch
818 m_bConsChangedThisIter[nThisLayer] = true;
819
820 // And increment the per-timestep total
822 }
823
824 if (nCoarseWeight)
825 {
826 // Erode some coarse-sized consolidated sediment
827 double const dCoarseLowering = (m_dCoarseErodibilityNormalized * dThisPotentialErosion) / dTotErodibility;
828
829 // Make sure we don't get -ve amounts left on the source cell
830 dCoarseEroded = tMin(dExistingAvailableCoarse, dCoarseLowering);
831 double const dRemaining = dExistingAvailableCoarse - dCoarseEroded;
832
833 dTotActualErosion += dCoarseEroded;
834
835 // Set the new value of coarse consolidated sediment depth for this layer
836 m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetConsolidatedSediment()->SetCoarseDepth(dRemaining);
837
838 // And add this to the depth of coarse unconsolidated sediment for this layer
839 m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetUnconsolidatedSediment()->AddCoarseDepth(dCoarseEroded);
840
841 // Set the changed-this-timestep switch
842 m_bConsChangedThisIter[nThisLayer] = true;
843
844 // And increment the per-timestep total
846 }
847
848 // Did we erode anything?
849 if (dTotActualErosion > 0)
850 {
851 // We did, so set the actual erosion value for this cell
852 m_pRasterGrid->m_Cell[nX][nY].SetActualPlatformErosion(dTotActualErosion);
853
854 // Recalculate the elevation of every layer
855 m_pRasterGrid->m_Cell[nX][nY].CalcAllLayerElevsAndD50();
856
857 // And update the cell's sea depth
858 m_pRasterGrid->m_Cell[nX][nY].SetSeaDepth();
859
860 // Update per-timestep totals
862
863 // Add eroded sand/coarse sediment for this cell to the polygon that contains the cell, ready for redistribution during beach erosion/deposition (fine sediment has already been dealt with)
864 int nPolyID = m_pRasterGrid->m_Cell[nX][nY].nGetPolygonID();
865 int nPolyCoastID = m_pRasterGrid->m_Cell[nX][nY].nGetPolygonCoastID();
866
867 if (nPolyID == INT_NODATA)
868 {
869 // Can get occasional problems with polygon rasterization near the coastline, so also search the eight adjacent cells
870 array<int, 8> nDirection = {NORTH, NORTH_EAST, EAST, SOUTH_EAST, SOUTH, SOUTH_WEST, WEST, NORTH_WEST};
871 shuffle(nDirection.begin(), nDirection.end(), m_Rand[0]);
872
873 for (int n = 0; n < 8; n++)
874 {
875 int nXAdj;
876 int nYAdj;
877
878 if (nDirection[n] == NORTH)
879 {
880 nXAdj = nX;
881 nYAdj = nY - 1;
882
883 if (nYAdj >= 0)
884 {
885 nPolyID = m_pRasterGrid->m_Cell[nXAdj][nYAdj].nGetPolygonID();
886
887 if (nPolyID != INT_NODATA)
888 {
889 nPolyCoastID = m_pRasterGrid->m_Cell[nXAdj][nYAdj].nGetPolygonCoastID();
890 break;
891 }
892 }
893 }
894 else if (nDirection[n] == NORTH_EAST)
895 {
896 nXAdj = nX + 1;
897 nYAdj = nY - 1;
898
899 if ((nXAdj < m_nXGridSize) && (nYAdj >= 0))
900 {
901 nPolyID = m_pRasterGrid->m_Cell[nXAdj][nYAdj].nGetPolygonID();
902
903 if (nPolyID != INT_NODATA)
904 {
905 nPolyCoastID = m_pRasterGrid->m_Cell[nXAdj][nYAdj].nGetPolygonCoastID();
906 break;
907 }
908 }
909 }
910 else if (nDirection[n] == EAST)
911 {
912 nXAdj = nX + 1;
913 nYAdj = nY;
914
915 if (nXAdj < m_nXGridSize)
916 {
917 nPolyID = m_pRasterGrid->m_Cell[nXAdj][nYAdj].nGetPolygonID();
918
919 if (nPolyID != INT_NODATA)
920 {
921 nPolyCoastID = m_pRasterGrid->m_Cell[nXAdj][nYAdj].nGetPolygonCoastID();
922 break;
923 }
924 }
925 }
926 else if (nDirection[n] == SOUTH_EAST)
927 {
928 nXAdj = nX + 1;
929 nYAdj = nY + 1;
930
931 if ((nXAdj < m_nXGridSize) && (nYAdj < m_nYGridSize))
932 {
933 nPolyID = m_pRasterGrid->m_Cell[nXAdj][nYAdj].nGetPolygonID();
934
935 if (nPolyID != INT_NODATA)
936 {
937 nPolyCoastID = m_pRasterGrid->m_Cell[nXAdj][nYAdj].nGetPolygonCoastID();
938 break;
939 }
940 }
941 }
942 else if (nDirection[n] == SOUTH)
943 {
944 nXAdj = nX;
945 nYAdj = nY + 1;
946
947 if (nYAdj < m_nYGridSize)
948 {
949 nPolyID = m_pRasterGrid->m_Cell[nXAdj][nYAdj].nGetPolygonID();
950
951 if (nPolyID != INT_NODATA)
952 {
953 nPolyCoastID = m_pRasterGrid->m_Cell[nXAdj][nYAdj].nGetPolygonCoastID();
954 break;
955 }
956 }
957 }
958 else if (nDirection[n] == SOUTH_WEST)
959 {
960 nXAdj = nX - 1;
961 nYAdj = nY + 1;
962
963 if ((nXAdj >= 0) && (nXAdj < m_nXGridSize))
964 {
965 nPolyID = m_pRasterGrid->m_Cell[nXAdj][nYAdj].nGetPolygonID();
966
967 if (nPolyID != INT_NODATA)
968 {
969 nPolyCoastID = m_pRasterGrid->m_Cell[nXAdj][nYAdj].nGetPolygonCoastID();
970 break;
971 }
972 }
973 }
974 else if (nDirection[n] == WEST)
975 {
976 nXAdj = nX - 1;
977 nYAdj = nY;
978
979 if (nXAdj >= 0)
980 {
981 nPolyID = m_pRasterGrid->m_Cell[nXAdj][nYAdj].nGetPolygonID();
982
983 if (nPolyID != INT_NODATA)
984 {
985 nPolyCoastID = m_pRasterGrid->m_Cell[nXAdj][nYAdj].nGetPolygonCoastID();
986 break;
987 }
988 }
989 }
990 else if (nDirection[n] == NORTH_WEST)
991 {
992 nXAdj = nX - 1;
993 nYAdj = nY - 1;
994
995 if ((nXAdj >= 0) && (nYAdj >= 0))
996 {
997 nPolyID = m_pRasterGrid->m_Cell[nXAdj][nYAdj].nGetPolygonID();
998
999 if (nPolyID != INT_NODATA)
1000 {
1001 nPolyCoastID = m_pRasterGrid->m_Cell[nXAdj][nYAdj].nGetPolygonCoastID();
1002 break;
1003 }
1004 }
1005 }
1006 }
1007 }
1008
1009 // assert(nPolyID < m_VCoast[0].nGetNumPolygons());
1010
1011 // Safety check
1012 if (nPolyID == INT_NODATA)
1013 {
1014 // Uh-oh, we have a problem
1016 LogStream << m_ulIter << ": " << WARN << "platform erosion on cell [" << nX << "][" << nY << "] = {" << dGridCentroidXToExtCRSX(nX) << ", " << dGridCentroidYToExtCRSY(nY) << "} but this is not in a polygon" << endl;
1017
1018 // m_dDepositionSandDiff and m_dDepositionCoarseDiff are both +ve
1019 m_dDepositionSandDiff += dSandEroded;
1020 m_dDepositionCoarseDiff += dCoarseEroded;
1021
1022 return;
1023 }
1024
1025 // All OK, so add this to the polygon's total of unconsolidated sand/coarse sediment, to be deposited or moved later. These values are +ve (deposition)
1026 m_VCoast[nPolyCoastID].pGetPolygon(nPolyID)->AddPlatformErosionUnconsSand(dSandEroded);
1027 m_VCoast[nPolyCoastID].pGetPolygon(nPolyID)->AddPlatformErosionUnconsCoarse(dCoarseEroded);
1028 }
1029}
1030
1031//===============================================================================================================================
1033//===============================================================================================================================
1034bool CSimulation::bCreateErosionPotentialLookUp(vector<double> *VdDepthOverDBIn, vector<double> *VdErosionPotentialIn, vector<double> *VdErosionPotentialFirstDerivIn)
1035{
1036 // Set up a temporary vector to hold the incremental DepthOverDB values
1037 vector<double> VdDepthOverDB;
1038 double dTempDOverDB = 0;
1039
1040 while (dTempDOverDB <= 1.1) // Arbitrary max value, we will adjust this later
1041 {
1042 VdDepthOverDB.push_back(dTempDOverDB); // These are the incremental sample values of DepthOverDB
1043 dTempDOverDB += DEPTH_OVER_DB_INCREMENT;
1044
1045 m_VdErosionPotential.push_back(0); // This will hold the corresponding value of erosion potential for each sample point
1046 }
1047
1048 int const nSize = static_cast<int>(VdDepthOverDB.size());
1049 vector<double> VdDeriv(nSize, 0); // First derivative at the sample points: calculated by the spline function but not subsequently used
1050 vector<double> VdDeriv2(nSize, 0.); // Second derivative at the sample points, ditto
1051 vector<double> VdDeriv3(nSize, 0.); // Third derivative at the sample points, ditto
1052
1053 // Calculate the value of erosion potential (is a -ve value) for each of the sample values of DepthOverDB, and store it for use in the look-up function
1054 hermite_cubic_spline_value(static_cast<int>(VdDepthOverDBIn->size()), &(VdDepthOverDBIn->at(0)), &(VdErosionPotentialIn->at(0)), &(VdErosionPotentialFirstDerivIn->at(0)), nSize, &(VdDepthOverDB[0]), &(m_VdErosionPotential[0]), &(VdDeriv[0]), &(VdDeriv2[0]), &(VdDeriv3[0]));
1055
1056 // Tidy the erosion potential look-up data: cut off values (after the first) for which erosion potential is no longer -ve
1057 int nLastVal = -1;
1058
1059 for (int n = 1; n < nSize - 1; n++)
1060 {
1061 if (m_VdErosionPotential[n] > 0)
1062 {
1063 nLastVal = n;
1064 break;
1065 }
1066 }
1067
1068 if (nLastVal > 0)
1069 {
1070 // Erosion potential is no longer -ve at this value of DepthOverDB, so set the maximum value of DepthOverDB that will be used in the simulation (any DepthOverDB value greater than this produces zero erosion potential)
1071 m_dDepthOverDBMax = VdDepthOverDB[nLastVal];
1072 m_VdErosionPotential.erase(m_VdErosionPotential.begin() + nLastVal + 1, m_VdErosionPotential.end());
1073 m_VdErosionPotential.back() = 0;
1074 }
1075
1076 else
1077 // Erosion potential is unbounded, i.e. it is still -ve when we have reached the end of the look-up vector
1078 return false;
1079
1080 // All OK
1081 return true;
1082}
1083
1084//===============================================================================================================================
1086//===============================================================================================================================
1087double CSimulation::dLookUpErosionPotential(double const dDepthOverDB)
1088{
1089 // If dDepthOverDB exceeds the maximum value which we calculated earlier, erosion potential is zero
1090 if (dDepthOverDB > m_dDepthOverDBMax)
1091 return 0;
1092
1093 // OK, dDepthOverDB is less than the maximum so look up a corresponding value for erosion potential. The look-up index is dDepthOverDB divided by (the Depth Over DB increment used when creating the look-up vector). But since this look-up index may not be an integer, split the look-up index into integer and fractional parts and deal with each separately
1094 double const dErosionPotential = dGetInterpolatedValue(&m_VdDepthOverDB, &m_VdErosionPotential, dDepthOverDB, false);
1095
1096 return dErosionPotential;
1097}
1098
1099//===============================================================================================================================
1101//===============================================================================================================================
1102double CSimulation::dCalcBeachProtectionFactor(int const nX, int const nY, double const dBreakingWaveHeight)
1103{
1104 // Safety check
1105 if (bFPIsEqual(dBreakingWaveHeight, DBL_NODATA, TOLERANCE))
1106 return 0;
1107
1108 // We are considering the unconsolidated sediment (beach) of the topmost layer that has non-zero thickness
1109 int const nThisLayer = m_pRasterGrid->m_Cell[nX][nY].nGetTopNonZeroLayerAboveBasement();
1110
1111 // Safety check
1112 if (nThisLayer == INT_NODATA)
1113 {
1114 cerr << ERR << "no sediment layer in dCalcBeachProtectionFactor()" << endl;
1115 return 0;
1116 }
1117
1118 if (nThisLayer == NO_NONZERO_THICKNESS_LAYERS)
1119 // There are no layers with non-zero thickness left (i.e. we are down to basement) so no beach protection
1120 return 0;
1121
1122 // In SCAPE, 0.23 * the significant breaking wave height is assumed to be the maximum depth of beach that waves can penetrate to erode a platform. For depths less than this, the beach protective ability is assumed to vary linearly
1123 double const dBeachDepth = m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->dGetAllUnconsDepth();
1124 double const dMaxPenetrationDepth = BEACH_PROTECTION_HB_RATIO * dBreakingWaveHeight;
1125 double dFactor = 0;
1126
1127 if (dMaxPenetrationDepth > 0)
1128 dFactor = tMax(1 - (dBeachDepth / dMaxPenetrationDepth), 0.0);
1129
1130 // LogStream << m_ulIter << ": cell[" << nX << "][" << nY << "] has beach protection factor = " << dFactor << endl;
1131
1132 return dFactor;
1133}
1134
1135//===============================================================================================================================
1137//===============================================================================================================================
1139{
1140 for (int nX = 0; nX < m_nXGridSize; nX++)
1141 {
1142 for (int nY = 0; nY < m_nYGridSize; nY++)
1143 {
1144 // Find any 'legacy' ciff cells: cells with an erosional notch apex elevation which is now - due to shore platform erosion - above the top of the consolidated sediment
1145 double const dNotchApexElev = m_pRasterGrid->m_Cell[nX][nY].pGetLandform()->dGetCliffNotchApexElev();
1146 if (! bFPIsEqual(dNotchApexElev, DBL_NODATA, TOLERANCE))
1147 {
1148 // This cell has an erosional notch
1149 double const dSedTopElevNoTalus = m_pRasterGrid->m_Cell[nX][nY].dGetAllSedTopElevOmitTalus();
1150 if (dNotchApexElev >= dSedTopElevNoTalus)
1151 {
1152 // The apex elevation of the notch is above the top of the consolidated sediment, so this notch has been removed
1153 m_pRasterGrid->m_Cell[nX][nY].pGetLandform()->SetCliffNotchApexElev(DBL_NODATA);
1154 m_pRasterGrid->m_Cell[nX][nY].pGetLandform()->SetCliffNotchIncisionDepth(DBL_NODATA);
1155
1156 // Now determine the landform category
1157 int const nTopLayer = m_pRasterGrid->m_Cell[nX][nY].nGetTopNonZeroLayerAboveBasement();
1158 CRWCellLayer* pTopLayer = m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nTopLayer);
1159
1160 if (pTopLayer->bHasTalus())
1161 {
1162 // There is talus here
1163 m_pRasterGrid->m_Cell[nX][nY].pGetLandform()->SetLFCategory(LF_DRIFT_TALUS);
1164 }
1165 else if (pTopLayer->bHasUncons())
1166 {
1167 // There is some unconsolidated sediment here
1168 m_pRasterGrid->m_Cell[nX][nY].pGetLandform()->SetLFCategory(LF_DRIFT_BEACH);
1169 }
1170 else
1171 {
1172 // Set as hinterland
1173 m_pRasterGrid->m_Cell[nX][nY].pGetLandform()->SetLFCategory(LF_HINTERLAND);
1174 }
1175 }
1176 }
1177
1178 // Now look at beach protection
1179 if ((m_pRasterGrid->m_Cell[nX][nY].bIsInContiguousSea()) && (bFPIsEqual(m_pRasterGrid->m_Cell[nX][nY].dGetBeachProtectionFactor(), DBL_NODATA, TOLERANCE)))
1180 {
1181 // This is a sea cell, and it has an initialised beach protection value. So look at its N-S and W-E neighbours
1182 int nXTmp;
1183 int nYTmp;
1184 int nAdjacent = 0;
1185 double dBeachProtection = 0;
1186
1187 // North
1188 nXTmp = nX;
1189 nYTmp = nY - 1;
1190
1191 if ((bIsWithinValidGrid(nXTmp, nYTmp)) && (! bFPIsEqual(m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetBeachProtectionFactor(), DBL_NODATA, TOLERANCE)))
1192 {
1193 nAdjacent++;
1194 dBeachProtection += m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetBeachProtectionFactor();
1195 }
1196
1197 // East
1198 nXTmp = nX + 1;
1199 nYTmp = nY;
1200
1201 if ((bIsWithinValidGrid(nXTmp, nYTmp)) && (! bFPIsEqual(m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetBeachProtectionFactor(), DBL_NODATA, TOLERANCE)))
1202 {
1203 nAdjacent++;
1204 dBeachProtection += m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetBeachProtectionFactor();
1205 }
1206
1207 // South
1208 nXTmp = nX;
1209 nYTmp = nY + 1;
1210
1211 if ((bIsWithinValidGrid(nXTmp, nYTmp)) && (! bFPIsEqual(m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetBeachProtectionFactor(), DBL_NODATA, TOLERANCE)))
1212 {
1213 nAdjacent++;
1214 dBeachProtection += m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetBeachProtectionFactor();
1215 }
1216
1217 // West
1218 nXTmp = nX - 1;
1219 nYTmp = nY;
1220
1221 if ((bIsWithinValidGrid(nXTmp, nYTmp)) && (! bFPIsEqual(m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetBeachProtectionFactor(), DBL_NODATA, TOLERANCE)))
1222 {
1223 nAdjacent++;
1224 dBeachProtection += m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetBeachProtectionFactor();
1225 }
1226
1227 // If this sea cell has four neighbours with initialised beach protection values, then assume that it should not have an uninitialised beach protection value. Set it to the average of its neighbours
1228 if (nAdjacent == 4)
1229 {
1230 m_pRasterGrid->m_Cell[nX][nY].SetBeachProtectionFactor(dBeachProtection / 4);
1231 }
1232 }
1233 }
1234 }
1235}
1236
1237//===============================================================================================================================
1239//===============================================================================================================================
1241{
1242 for (int nX = 0; nX < m_nXGridSize; nX++)
1243 {
1244 for (int nY = 0; nY < m_nYGridSize; nY++)
1245 {
1246 if ((m_pRasterGrid->m_Cell[nX][nY].bIsInContiguousSea()) && (bFPIsEqual(m_pRasterGrid->m_Cell[nX][nY].dGetPotentialPlatformErosion(), 0.0, TOLERANCE)))
1247 {
1248 // This is a sea cell, it has a zero potential platform erosion value. So look at its N-S and W-E neighbours
1249 int nXTmp;
1250 int nYTmp;
1251 int nAdjacent = 0;
1252 double dPotentialPlatformErosion = 0;
1253
1254 // North
1255 nXTmp = nX;
1256 nYTmp = nY - 1;
1257
1258 if ((bIsWithinValidGrid(nXTmp, nYTmp)) && (! bFPIsEqual(m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetPotentialPlatformErosion(), 0.0, TOLERANCE)))
1259 {
1260 nAdjacent++;
1261 dPotentialPlatformErosion += m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetPotentialPlatformErosion();
1262 }
1263
1264 // East
1265 nXTmp = nX + 1;
1266 nYTmp = nY;
1267
1268 if ((bIsWithinValidGrid(nXTmp, nYTmp)) && (! bFPIsEqual(m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetPotentialPlatformErosion(), 0.0, TOLERANCE)))
1269 {
1270 nAdjacent++;
1271 dPotentialPlatformErosion += m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetPotentialPlatformErosion();
1272 }
1273
1274 // South
1275 nXTmp = nX;
1276 nYTmp = nY + 1;
1277
1278 if ((bIsWithinValidGrid(nXTmp, nYTmp)) && (! bFPIsEqual(m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetPotentialPlatformErosion(), 0.0, TOLERANCE)))
1279 {
1280 nAdjacent++;
1281 dPotentialPlatformErosion += m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetPotentialPlatformErosion();
1282 }
1283
1284 // West
1285 nXTmp = nX - 1;
1286 nYTmp = nY;
1287
1288 if ((bIsWithinValidGrid(nXTmp, nYTmp)) && (! bFPIsEqual(m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetPotentialPlatformErosion(), 0.0, TOLERANCE)))
1289 {
1290 nAdjacent++;
1291 dPotentialPlatformErosion += m_pRasterGrid->m_Cell[nXTmp][nYTmp].dGetPotentialPlatformErosion();
1292 }
1293
1294 // If this sea cell has four neighbours with non-zero potential platform erosion values, then assume that it should not have a zero potential platform erosion value. Set it to the average of its neighbours
1295 if (nAdjacent == 4)
1296 {
1297 double const dThisPotentialPlatformErosion = dPotentialPlatformErosion / 4;
1298
1299 m_pRasterGrid->m_Cell[nX][nY].SetPotentialPlatformErosion(dThisPotentialPlatformErosion);
1300
1301 // Update this-timestep totals
1303 m_dThisIterPotentialPlatformErosion += dThisPotentialPlatformErosion;
1304 // assert(isfinite(m_dThisIterPotentialPlatformErosion));
1305
1306 // Increment the check values
1308 m_dTotPotentialPlatformErosionBetweenProfiles += dThisPotentialPlatformErosion;
1309 }
1310 }
1311 }
1312 }
1313}
1314
1315//===============================================================================================================================
1317//===============================================================================================================================
1318void CSimulation::ConstructParallelProfile(int const nProfileStartX, int const nProfileStartY, int const nParCoastX, int const nParCoastY, int const nProfSize, vector<CGeom2DIPoint> *const pPtViGridProfile, vector<CGeom2DIPoint> *pPtiVGridParProfile, vector<CGeom2DPoint> *pPtVExtCRSParProfile)
1319{
1320 // OK, we have the coastline start point for the parallel profile. Now construct a temporary profile, parallel to the coastline-normal profile, starting from this point
1321 int const nXOffset = nParCoastX - nProfileStartX;
1322 int const nYOffset = nParCoastY - nProfileStartY;
1323
1324 // Append co-ord values for the temporary profile
1325 for (int nProfileStartPoint = 0; nProfileStartPoint < nProfSize; nProfileStartPoint++)
1326 {
1327 // Get the grid coordinates of the cell which is this distance seaward, from the coastline-normal profile
1328 int const nXProf = pPtViGridProfile->at(nProfileStartPoint).nGetX();
1329 int const nYProf = pPtViGridProfile->at(nProfileStartPoint).nGetY();
1330
1331 // Now calculate the grid coordinates of this cell, which is potentially in the parallel profile
1332 int const nXPar = nXProf + nXOffset;
1333 int const nYPar = nYProf + nYOffset;
1334
1335 // Is this cell within the grid? If not, cut short the profile
1336 if (! bIsWithinValidGrid(nXPar, nYPar))
1337 {
1338 // LogStream << "NOT WITHIN GRID [" << nXPar << "][" << nYPar << "]" << endl;
1339 return;
1340 }
1341
1342 // Have we hit an adjacent coastline-normal profile? If so, cut short
1343 if (m_pRasterGrid->m_Cell[nXPar][nYPar].bIsProfile())
1344 {
1345 // LogStream << "HIT PROFILE " << m_pRasterGrid->m_Cell[nXPar][nYPar].nGetProfileID() << " at [" << nXPar << "][" << nYPar << "] = {" << dGridCentroidXToExtCRSX(nXPar) << ", " << dGridCentroidYToExtCRSY(nYPar) << "}" << endl;
1346 return;
1347 }
1348
1349 // OK, append the cell details
1350 pPtiVGridParProfile->push_back(CGeom2DIPoint(nXPar, nYPar));
1351 pPtVExtCRSParProfile->push_back(CGeom2DPoint(dGridCentroidXToExtCRSX(nXPar), dGridCentroidYToExtCRSY(nYPar)));
1352 }
1353}
Contains CGeom2DIPoint definitions.
Geometry class used to represent 2D point objects with integer coordinates.
Definition 2di_point.h:25
Geometry class used to represent 2D point objects with floating-point coordinates.
Definition 2d_point.h:25
double dGetY(void) const
Returns the CGeom2DPoint object's double Y coordinate.
Definition 2d_point.cpp:51
double dGetX(void) const
Returns the CGeom2DPoint object's double X coordinate.
Definition 2d_point.cpp:45
Geometry class used to represent coast profile objects.
Definition profile.h:33
int nGetProfileID(void) const
Returns the profile's this-coast ID.
Definition profile.cpp:74
int nGetCoastPoint(void) const
Returns the coast point at which the profile starts.
Definition profile.cpp:80
int nGetNumCellsInProfile(void) const
Returns the number of cells in the profile.
Definition profile.cpp:539
CGeom2DPoint * pPtGetPointInProfile(int const)
Returns a single point (external CRS) from the profile.
Definition profile.cpp:364
bool bOKIncStartAndEndOfCoast(void) const
Returns true if this is a problem-free profile (however it could be a start-of-coast or an end-of-coa...
Definition profile.cpp:262
int nGetProfileSize(void) const
Returns the number of external CRS points in the profile (only two, initally; and always just two for...
Definition profile.cpp:358
vector< CGeom2DIPoint > * pPtiVGetCellsInProfile(void)
Returns all cells (grid CRS) in the profile.
Definition profile.cpp:512
Real-world class used to represent the sediment layers associated with a cell object.
Definition cell_layer.h:28
bool bHasTalus(void)
Returns true if the layer has talus, false otherwise.
bool bHasUncons(void)
Return true if the layer has unconsolidated sediment, false otherwise.
int m_nLogFileDetail
The level of detail in the log file output. Can be LOG_FILE_LOW_DETAIL, LOG_FILE_MIDDLE_DETAIL,...
Definition simulation.h:588
double m_dThisIterSWL
The still water level for this timestep (this includes tidal changes and any long-term SWL change)
Definition simulation.h:726
CGeomRasterGrid * m_pRasterGrid
Pointer to the raster grid object.
int m_nXGridSize
The size of the grid in the x direction.
Definition simulation.h:477
ofstream LogStream
vector< CRWCoast > m_VCoast
The coastline objects.
double m_dFineErodibilityNormalized
Relative erodibility of fine unconsolidated beach sediment, normalized.
Definition simulation.h:810
double m_dThisIterActualPlatformErosionCoarseCons
Total actual platform erosion (coarse consolidated sediment) for this iteration (depth in m)
Definition simulation.h:858
int nDoAllShorePlatFormErosion(void)
Does platform erosion on all coastlines by first calculating platform erosion on coastline-normal pro...
int m_nYGridSize
The size of the grid in the y direction.
Definition simulation.h:480
vector< double > m_VdErosionPotential
For erosion potential lookup.
void ConstructParallelProfile(int const, int const, int const, int const, int const, vector< CGeom2DIPoint > *const, vector< CGeom2DIPoint > *, vector< CGeom2DPoint > *)
Constructs a parallel coastline-normal profile.
int nSaveParProfile(int const, CGeomProfile const *, int const, int const, int const, vector< double > const *, vector< double > const *, vector< double > const *, vector< double > const *, vector< double > const *, vector< double > const *, vector< double > const *, vector< CGeom2DIPoint > *const, vector< double > const *) const
Save a coastline-normal parallel profile.
static double dGetDistanceBetween(CGeom2DPoint const *, CGeom2DPoint const *)
Returns the distance (in external CRS) between two points.
double m_dCoarseErodibilityNormalized
Relative erodibility of coarse unconsolidated beach sediment, normalized.
Definition simulation.h:816
vector< double > m_VdDepthOverDB
For erosion potential lookup.
double m_dTotPotentialPlatformErosionBetweenProfiles
Total potential platform erosion between profiles.
Definition simulation.h:915
double m_dDepositionCoarseDiff
Error term: if we are unable to deposit enough unconslidated coarse on polygon(s),...
Definition simulation.h:906
unsigned long m_ulThisIterNumActualPlatformErosionCells
The number of grid cells on which actual platform erosion occurs, for this iteration.
Definition simulation.h:630
int nCalcPotentialPlatformErosionBetweenProfiles(int const, CGeomProfile *, int const)
Calculates potential platform erosion on cells to one side of a given coastline-normal profile,...
double m_dDepositionSandDiff
Error term: if we are unable to deposit enough unconslidated sand on polygon(s), this is held over to...
Definition simulation.h:903
int nSaveProfile(int const, CGeomProfile const *, int const, vector< double > const *, vector< double > const *, vector< double > const *, vector< double > const *, vector< double > const *, vector< double > const *, vector< double > const *, vector< CGeom2DIPoint > *const, vector< double > const *) const
Save a coastline-normal profile.
double m_dThisIterPotentialPlatformErosion
Total potential platform erosion (all size classes of consolidated sediment) for this iteration (dept...
Definition simulation.h:849
vector< double > dVSmoothProfileSlope(vector< double > *) const
Does running-mean smoothing of the slope of a coastline-normal profile.
double m_dDepthOverDBMax
Maximum value of deoth over DB, is used in erosion potential look-up function.
Definition simulation.h:909
double m_dSandErodibilityNormalized
Relative erodibility of sand unconsolidated beach sediment, normalized.
Definition simulation.h:813
double m_dR
Coast platform resistance to erosion R, see Walkden & Hall, 2011.
Definition simulation.h:783
double m_dThisIterActualPlatformErosionSandCons
Total actual platform erosion (sand consolidated sediment) for this iteration (depth in m)
Definition simulation.h:855
double dGridCentroidYToExtCRSY(int const) const
Given the integer Y-axis ordinate of a cell in the raster grid CRS, returns the external CRS Y-axis o...
Definition gis_utils.cpp:74
void FillInBeachProtectionHolesAndRemoveLegacyCliffs(void)
Fills in 'holes' in the beach protection i.e. orphan cells which get omitted because of rounding prob...
double m_dTotPotentialPlatformErosionOnProfiles
Total potential platform erosion on profiles.
Definition simulation.h:912
int nCalcPotentialPlatformErosionOnProfile(int const, CGeomProfile *)
Calculates potential (i.e. unconstrained by available sediment) erosional lowering of the shore platf...
void DoActualPlatformErosionOnCell(int const, int const)
Calculates actual (constrained by available sediment) erosion of the consolidated shore platform on a...
double m_dThisIterFineSedimentToSuspension
Total fine unconsolidated sediment in suspension for this iteration (depth in m)
Definition simulation.h:879
void FillPotentialPlatformErosionHoles(void)
Fills in 'holes' in the potential platform erosion i.e. orphan cells which get omitted because of rou...
double dLookUpErosionPotential(double const)
The erosion potential lookup: it returns a value for erosion potential given a value of Depth Over DB...
unsigned long m_ulThisIterNumPotentialPlatformErosionCells
The number of grid cells on which potential platform erosion occurs, for this iteration.
Definition simulation.h:627
default_random_engine m_Rand[NUMBER_OF_RNGS]
The c++11 random number generators.
unsigned long m_ulTotPotentialPlatformErosionOnProfiles
The number of cells on which on-profile average potential shore platform erosion occurs.
Definition simulation.h:642
double m_dCellArea
Area of a cell (in external CRS units)
Definition simulation.h:675
unsigned long m_ulTotPotentialPlatformErosionBetweenProfiles
The number of cells on which between-profile average potential shore platform erosion occurs.
Definition simulation.h:645
bool m_bOutputConsolidatedProfileData
Output profile data?
Definition simulation.h:336
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,...
unsigned long m_ulIter
The number of the current iteration (time step)
Definition simulation.h:609
double dGridCentroidXToExtCRSX(int const) const
Given the integer X-axis ordinate of a cell in the raster grid CRS, returns the external CRS X-axis o...
Definition gis_utils.cpp:65
double dGetInterpolatedValue(vector< double > const *, vector< double > const *, double, bool)
double dCalcBeachProtectionFactor(int const, int const, double const)
Calculates the (inverse) beach protection factor as in SCAPE: 0 is fully protected,...
bool bCreateErosionPotentialLookUp(vector< double > *, vector< double > *, vector< double > *)
Creates a look-up table for erosion potential, given depth over DB.
double m_dThisIterActualPlatformErosionFineCons
Total actual platform erosion (fine consolidated sediment) for this iteration (depth in m)
Definition simulation.h:852
int m_nProfileSmoothWindow
The size of the window used for running-mean coast-normal profile smoothing (must be odd)
Definition simulation.h:504
vector< bool > m_bConsChangedThisIter
One element per layer: has the consolidated sediment of this layer been changed during this iteration...
bool m_bOutputParallelProfileData
Output parallel profile data?
Definition simulation.h:339
This file contains global definitions for CoastalME.
int const NO_NONZERO_THICKNESS_LAYERS
Definition cme.h:672
int const INT_NODATA
Definition cme.h:380
T tMin(T a, T b)
Definition cme.h:1175
double const TOLERANCE
Definition cme.h:725
int const RTN_ERR_NO_TOP_LAYER
Definition cme.h:629
int const LF_DRIFT_TALUS
Definition cme.h:439
string const ERR
Definition cme.h:805
int const DIRECTION_DOWNCOAST
Definition cme.h:408
int const SOUTH_EAST
Definition cme.h:402
double const DEPTH_OVER_DB_INCREMENT
Definition cme.h:717
int const LOG_FILE_MIDDLE_DETAIL
Definition cme.h:393
bool bFPIsEqual(const T d1, const T d2, const T dEpsilon)
Definition cme.h:1213
int const SOUTH_WEST
Definition cme.h:404
T tMax(T a, T b)
Definition cme.h:1162
int const NORTH_WEST
Definition cme.h:406
int const LOG_FILE_HIGH_DETAIL
Definition cme.h:394
int const LF_HINTERLAND
Definition cme.h:435
string const WARN
Definition cme.h:806
int const SOUTH
Definition cme.h:403
int const LOG_FILE_ALL
Definition cme.h:395
int const EAST
Definition cme.h:401
int const RTN_OK
Definition cme.h:585
int const NORTH_EAST
Definition cme.h:400
int const DIRECTION_UPCOAST
Definition cme.h:409
double const DBL_NODATA
Definition cme.h:736
int const LF_DRIFT_BEACH
Definition cme.h:440
double const BEACH_PROTECTION_HB_RATIO
Definition cme.h:713
double const SED_ELEV_TOLERANCE
Definition cme.h:726
int const NORTH
Definition cme.h:399
int const WEST
Definition cme.h:405
Contains CRWCoast definitions.
void hermite_cubic_spline_value(int const nn, double *const xn, double *const fn, double *const dn, int const n, double *const x, double *f, double *d, double *s, double *t)
This is part of a C++ library from http://people.sc.fsu.edu/~jburkardt/cpp_src/hermite_cubic/hermite_...
Definitions of some routines from the hermite_cubic library.
Contains CSimulation definitions.