CoastalME (Coastal Modelling Environment)
Simulates the long-term behaviour of complex coastlines
Loading...
Searching...
No Matches
do_beach_within_polygon.cpp
Go to the documentation of this file.
1
12
13/* ==============================================================================================================================
14
15 This file is part of CoastalME, the Coastal Modelling Environment.
16
17 CoastalME is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
23==============================================================================================================================*/
24#include <assert.h>
25
26#include <cmath>
27#include <cfloat>
28
29#include <iostream>
30// using std::cout;
31using std::endl;
32
33#include <algorithm>
34using std::shuffle;
35
36#include "cme.h"
37#include "simulation.h"
38#include "coast.h"
39#include "2d_point.h"
40#include "2di_point.h"
41
42//===============================================================================================================================
44//===============================================================================================================================
45int CSimulation::nDoUnconsErosionOnPolygon(int const nCoast, CGeomCoastPolygon* pPolygon, int const nTexture, double const dErosionTargetOnPolygon, double& dEroded)
46{
47 string strTexture;
48
49 if (nTexture == TEXTURE_FINE)
50 strTexture = "fine";
51
52 else if (nTexture == TEXTURE_SAND)
53 strTexture = "sand";
54
55 else if (nTexture == TEXTURE_COARSE)
56 strTexture = "coarse";
57
58 // Intialise
59 double dStillToErodeOnPolygon = dErosionTargetOnPolygon;
60 dEroded = 0;
61
62 // Get the up-coast and down-coast boundary details
63 int const nUpCoastProfile = pPolygon->nGetUpCoastProfile();
64 CGeomProfile* pUpCoastProfile = m_VCoast[nCoast].pGetProfile(nUpCoastProfile);
65
66 int const nDownCoastProfile = pPolygon->nGetDownCoastProfile();
67 CGeomProfile const* pDownCoastProfile = m_VCoast[nCoast].pGetProfile(nDownCoastProfile);
68
69 // We will use only part of the up-coast boundary profile, seaward as far as the depth of closure. First find the seaward end point of this up-coast part-profile. Note that this does not change as the landwards offset changes
70 int const nIndex = pUpCoastProfile->nGetCellGivenDepth(m_pRasterGrid, m_dDepthOfClosure);
71
72 if (nIndex == INT_NODATA)
73 {
75 LogStream << m_ulIter << ": " << ERR << "while eroding unconsolidated " + strTexture + " sediment on polygon " << pPolygon->nGetCoastID() << ", could not find the seaward end point of the up-coast profile (" << nUpCoastProfile << ") for depth of closure = " << m_dDepthOfClosure << endl;
76
78 }
79
80 // The part-profile length is one greater than nIndex, since pPtiGetCellGivenDepth() returns the index of the cell at the depth of closure
81 int const nUpCoastPartProfileLen = nIndex + 1;
82
83 // assert(bIsWithinValidGrid(&PtiUpCoastPartProfileSeawardEnd));
84
85 // Store the cell coordinates of the boundary part-profile in reverse (sea to coast) order so we can append to the coastward end as we move inland (i.e. as nInlandOffset increases)
86 vector<CGeom2DIPoint> PtiVUpCoastPartProfileCell;
87
88 // for (int n = 0; n < nUpCoastPartProfileLen; n++)
89 // PtiVUpCoastPartProfileCell.push_back(*pUpCoastProfile->pPtiGetCellInProfile(nUpCoastPartProfileLen - n - 1));
90 for (int n = nUpCoastPartProfileLen - 1; n >= 0; n--)
91 {
92 CGeom2DIPoint const Pti = *pUpCoastProfile->pPtiGetCellInProfile(n);
93 PtiVUpCoastPartProfileCell.push_back(Pti);
94 }
95
96 int const nUpCoastProfileCoastPoint = pUpCoastProfile->nGetCoastPoint();
97 int const nDownCoastProfileCoastPoint = pDownCoastProfile->nGetCoastPoint();
98 int const nXUpCoastProfileExistingCoastPoint = m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(nUpCoastProfileCoastPoint)->nGetX();
99 int const nYUpCoastProfileExistingCoastPoint = m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(nUpCoastProfileCoastPoint)->nGetY();
100 int nCoastSegLen;
101
102 // Store the coast point numbers for this polygon so that we can shuffle them
103 vector<int> nVCoastPoint;
104
105 if (nDownCoastProfileCoastPoint == m_VCoast[nCoast].nGetCoastlineSize() - 1)
106 {
107 // This is the final down-coast polygon, so also include the down-coast polygon boundary
108 nCoastSegLen = nDownCoastProfileCoastPoint - nUpCoastProfileCoastPoint + 1;
109
110 for (int nCoastPoint = nUpCoastProfileCoastPoint; nCoastPoint <= nDownCoastProfileCoastPoint; nCoastPoint++)
111 nVCoastPoint.push_back(nCoastPoint);
112 }
113
114 else
115 {
116 // This is not the final down-coast polygon, so do not include the polygon's down-coast boundary
117 nCoastSegLen = nDownCoastProfileCoastPoint - nUpCoastProfileCoastPoint;
118
119 for (int nCoastPoint = nUpCoastProfileCoastPoint; nCoastPoint < nDownCoastProfileCoastPoint; nCoastPoint++)
120 nVCoastPoint.push_back(nCoastPoint);
121 }
122
123 // Estimate the volume of sediment which is to be eroded from each parallel profile
124 double const dAllTargetPerProfile = dErosionTargetOnPolygon / nCoastSegLen;
125
126 // Shuffle the coast points, this is necessary so that leaving the loop does not create sequence-related artefacts
127 shuffle(nVCoastPoint.begin(), nVCoastPoint.begin() + nCoastSegLen, m_Rand[1]);
128
129 // Traverse the polygon's existing coastline in a DOWN-COAST (i.e. increasing coastpoint indices) sequence, at each coast point fitting a Dean profile which is parallel to the up-coast polygon boundary
130 for (int n = 0; n < nCoastSegLen; n++)
131 {
132 // Get the coast point
133 int const nCoastPoint = nVCoastPoint[n];
134
135 CGeom2DIPoint const PtiCoastPoint = *m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(nCoastPoint);
136 int const nCoastX = PtiCoastPoint.nGetX();
137 int const nCoastY = PtiCoastPoint.nGetY();
138
139 // LogStream << m_ulIter << ": nCoastX = " << nCoastX << ", nCoastY = " << nCoastY << ", this is {" << dGridCentroidXToExtCRSX(nCoastX) << ", " << dGridCentroidYToExtCRSY(nCoastY) << "}" << endl;
140
141 // Is the coast cell an intervention structure?
142 if (bIsInterventionCell(nCoastX, nCoastY))
143 {
144 // No erosion possible on this parallel profile, so move on
145 // LogStream << m_ulIter << ": intervention structure at coast point [" << nCoastX << "][" << nCoastY << "] = {" << dGridCentroidXToExtCRSX(nCoastX) << ", " << dGridCentroidYToExtCRSY(nCoastY) << "}, cannot erode this parallel profile" << endl;
146
147 continue;
148 }
149
150 // LogStream << m_ulIter << ": PtiVUpCoastPartProfileCell.back().nGetX() = " << PtiVUpCoastPartProfileCell.back().nGetX() << ", PtiVUpCoastPartProfileCell.back().nGetY() = " << PtiVUpCoastPartProfileCell.back().nGetY() << ", this is {" << dGridCentroidXToExtCRSX(PtiVUpCoastPartProfileCell.back().nGetX()) << ", " << dGridCentroidYToExtCRSY(PtiVUpCoastPartProfileCell.back().nGetY()) << "}" << endl;
151
152 // Not an intervention structure, so calculate the x-y offset between this coast point, and the coast point of the up-coast normal
153 int const nXOffset = nCoastX - PtiVUpCoastPartProfileCell.back().nGetX();
154 int const nYOffset = nCoastY - PtiVUpCoastPartProfileCell.back().nGetY();
155
156 // Get the x-y coords of a profile starting from this coast point and parallel to the up-coast polygon boundary profile (these are in reverse sequence, like the boundary part-profile)
157 vector<CGeom2DIPoint> VPtiParProfile;
158
159 for (int m = 0; m < nUpCoastPartProfileLen; m++)
160 {
161 // TODO 017 Check that each point is within valid grid, do same for other similar places in rest of model
162 CGeom2DIPoint const PtiTmp(PtiVUpCoastPartProfileCell[m].nGetX() + nXOffset, PtiVUpCoastPartProfileCell[m].nGetY() + nYOffset);
163 VPtiParProfile.push_back(PtiTmp);
164 }
165
166 // Get the elevations of the start and end points of the parallel profiles (as we extend the profile inland, the elevation of the new coast point of the Dean profile is set to the elevation of the original coast point)
167 int nParProfEndX = VPtiParProfile[0].nGetX();
168 int nParProfEndY = VPtiParProfile[0].nGetY();
169
170 // Safety check
171 if (!bIsWithinValidGrid(nParProfEndX, nParProfEndY))
172 {
173 // if (m_nLogFileDetail >= LOG_FILE_ALL)
174 // LogStream << WARN << "while eroding unconsolidated " + strTexture + " sediment for coast " << nCoast << " polygon " << pPolygon->nGetCoastID() << ", hit edge of grid at [" << nParProfEndX << "][" << nParProfEndY << "] for parallel profile from coast point " << nCoastPoint << " at [" << nCoastX << "][" << nCoastY << "]. Constraining this parallel profile at its seaward end" << endl;
175
176 KeepWithinValidGrid(nCoastX, nCoastY, nParProfEndX, nParProfEndY);
177 VPtiParProfile[0].SetX(nParProfEndX);
178 VPtiParProfile[0].SetY(nParProfEndY);
179 }
180
181 bool bHitEdge = false;
182 bool bEndProfile = false;
183 bool bZeroGradient = false;
184 bool bEnoughEroded = false;
185
186 int nParProfLen;
187 int nInlandOffset = -1;
188
189 double const dParProfCoastElev = m_pRasterGrid->m_Cell[nCoastX][nCoastY].dGetSedimentTopElev();
190 double const dParProfEndElev = m_pRasterGrid->m_Cell[nParProfEndX][nParProfEndY].dGetSedimentTopElev();
191
192 vector<double> VdParProfileDeanElev;
193
194 // These are for saving values for each offset
195 vector<int> VnParProfLenEachOffset;
196 vector<double> VdAmountEachOffset;
197 vector<vector<CGeom2DIPoint>> VVPtiParProfileEachOffset;
198 vector<vector<double>> VVdParProfileDeanElevEachOffset;
199
200 // OK, loop either until we can erode sufficient unconsolidated sediment, or until the landwards-moving parallel profile hits the grid edge
201 while (true)
202 {
203 // Move inland by one cell
204 nInlandOffset++;
205
206 if (nInlandOffset > 0)
207 {
208 if (nInlandOffset > (pUpCoastProfile->nGetNumCellsInProfile() - 1))
209 {
211 LogStream << m_ulIter << ": reached end of up-coast profile " << nUpCoastProfile << " during down-coast erosion of unconsolidated " + strTexture + " sediment for coast " << nCoast << " polygon " << pPolygon->nGetCoastID() << " (nCoastPoint = " << nCoastPoint << " nInlandOffset = " << nInlandOffset << ")" << endl;
212
213 bEndProfile = true;
214 break;
215 }
216
217 // Extend the parallel profile by one cell in the coastward direction. First get the coords of the cell that is nInlandOffset cells seaward from the existing up-coast part-profile start point
218 CGeom2DIPoint const PtiUpCoastTmp = *pUpCoastProfile->pPtiGetCellInProfile(nInlandOffset);
219
220 // Then get the offset between this PtiUpCoastTmp cell and the existing up-coast part-profile start point, and use the reverse of this offset to get the coordinates of the cell that extends the existing up-coast part-profile landwards
221 int const nXUpCoastStartOffset = PtiUpCoastTmp.nGetX() - nXUpCoastProfileExistingCoastPoint;
222 int const nYUpCoastStartOffset = PtiUpCoastTmp.nGetY() - nYUpCoastProfileExistingCoastPoint;
223 int const nXUpCoastThisStart = nCoastX - nXUpCoastStartOffset;
224 int const nYUpCoastThisStart = nCoastY - nYUpCoastStartOffset;
225
226 // Is the new landwards point within the raster grid?
227 if (!bIsWithinValidGrid(nXUpCoastThisStart, nYUpCoastThisStart))
228 {
229 // It isn't
230 // LogStream << WARN << "reached edge of grid at [" << nXUpCoastThisStart << "][" << nYUpCoastThisStart << "] = {" << dGridCentroidXToExtCRSX(nXUpCoastThisStart) << ", " << dGridCentroidYToExtCRSY(nYUpCoastThisStart) << "} during DOWN-COAST beach erosion for coast " << nCoast << " polygon " << nPoly << ", nCoastPoint = " << nCoastPoint << ", this is [" << nCoastX << "][" << nCoastY << "] = {" << dGridCentroidXToExtCRSX(nCoastX) << ", " << dGridCentroidYToExtCRSY(nCoastY) << "}, nInlandOffset = " << nInlandOffset << ")" << endl << endl;
231
232 // TODO 018 Need to improve this: at present we just abandon erosion on this coast point and move to another coast point
233 bHitEdge = true;
234 break;
235 }
236
237 // CGeom2DIPoint PtiThisUpCoastStart(nXUpCoastThisStart, nYUpCoastThisStart);
238
239 // Calculate the coordinates of a possible new landwards cell for the parallel profile
240 int
241 nXParNew = nXUpCoastThisStart + nXOffset,
242 nYParNew = nYUpCoastThisStart + nYOffset;
243
244 // Safety check
245 if (!bIsWithinValidGrid(nXParNew, nYParNew))
246 {
247 // LogStream << WARN << "while eroding beach on coast " << nCoast << " polygon " << nPoly << " (nInlandOffset = " << nInlandOffset << "), outside valid grid at [" << nXParNew << "][" << nYParNew << "] for parallel profile from coast point " << nCoastPoint << " at [" << nCoastX << "][" << nCoastY << "]. Constraining this parallel profile at its landward end, is now [";
248
249 KeepWithinValidGrid(nCoastX, nCoastY, nXParNew, nYParNew);
250
251 // LogStream << "[" << nXParNew << "][" << nYParNew << "] = {" << dGridCentroidXToExtCRSX(nXParNew) << ", " << dGridCentroidYToExtCRSY(nYParNew) << "}" << endl;
252
253 // Is this cell already in the parallel profile?
254 if ((VPtiParProfile.back().nGetX() != nXParNew) || (VPtiParProfile.back().nGetY() != nYParNew))
255 {
256 // It isn't, so append it to the parallel profile
257 CGeom2DIPoint const PtiTmp(nXParNew, nYParNew);
258 VPtiParProfile.push_back(PtiTmp);
259 }
260 }
261
262 else
263 {
264 // No problem, so just append this to the parallel profile
265 CGeom2DIPoint const PtiTmp(nXParNew, nYParNew);
266 VPtiParProfile.push_back(PtiTmp);
267 }
268 }
269
270 nParProfLen = static_cast<int>(VPtiParProfile.size());
271
272 if (nParProfLen < MIN_PARALLEL_PROFILE_SIZE)
273 {
274 // Can't have a meaningful parallel profile with very few points
275 // LogStream << m_ulIter << ": only " << nParProfLen << " points in parallel profile, min is " << MIN_PARALLEL_PROFILE_SIZE << ", abandoning" << endl;
276
277 continue;
278 }
279
280 // for (int m = 0; m < static_cast<int>(VPtiParProfile.size()); m++)
281 // LogStream << "[" << VPtiParProfile[m].nGetX() << "][" << VPtiParProfile[m].nGetY() << "] ";
282 // LogStream << endl;
283
284 // Get the distance between the start and end of the parallel profile, in external CRS units. Note that the parallel profile coordinates are in reverse sequence
285 CGeom2DPoint const PtStart = PtGridCentroidToExt(&VPtiParProfile.back());
286 CGeom2DPoint const PtEnd = PtGridCentroidToExt(&VPtiParProfile[0]);
287
288 // Calculate the length of the parallel profile
289 double dParProfileLen = dGetDistanceBetween(&PtStart, &PtEnd);
290
291 // Calculate the elevation difference between the start and end of the parallel profile
292 double const dElevDiff = dParProfCoastElev - dParProfEndElev;
293
294 if (bFPIsEqual(dElevDiff, 0.0, TOLERANCE))
295 {
296 // Can't have a meaningful Dean profile with a near-zero elevation difference
297 // TODO 019 Need to improve this: at present we just abandon erosion on this coast point and move to another coast point
298 // LogStream << m_ulIter << ": zero gradient on parallel profile, abandoning" << endl;
299
300 bZeroGradient = true;
301 break;
302 }
303
304 // Safety check
305 if (dParProfileLen <= 0)
306 dParProfileLen = 1;
307
308 // Solve for dA so that the existing elevations at the end of the parallel profile, and at the end of a Dean equilibrium profile on that part-normal, are the same
309 double const dParProfA = dElevDiff / pow(dParProfileLen, DEAN_POWER);
310 VdParProfileDeanElev.resize(nParProfLen, 0);
311 double const dInc = dParProfileLen / (nParProfLen - 1);
312
313 // For the parallel profile, calculate the Dean equilibrium profile of the unconsolidated sediment h(y) = A * y^(2/3) where h(y) is the distance below the highest point in the profile at a distance y from the landward start of the profile
314 CalcDeanProfile(&VdParProfileDeanElev, dInc, dParProfCoastElev, dParProfA, false, 0, 0);
315
316 vector<double> dVParProfileNow(nParProfLen, 0);
317 vector<bool> bVProfileValid(nParProfLen, true);
318
319 for (int m = 0; m < nParProfLen; m++)
320 {
321 int const nX = VPtiParProfile[nParProfLen - m - 1].nGetX();
322 int const nY = VPtiParProfile[nParProfLen - m - 1].nGetY();
323
324 // Safety check
325 if (!bIsWithinValidGrid(nX, nY))
326 {
327 // if (m_nLogFileDetail >= LOG_FILE_ALL)
328 // LogStream << WARN << "while constructing parallel profile for erosion of unconsolidated " + strTexture + " sediment on coast " << nCoast << " polygon " << nPoly << ", hit edge of grid at [" << nX << "][" << nY << "] for parallel profile from coast point " << nCoastPoint << " at [" << nCoastX << "][" << nCoastY << "]. Constraining this parallel profile at its seaward end" << endl;
329
330 bVProfileValid[m] = false;
331 continue;
332 }
333
334 // Don't erode intervention cells
335 if (bIsInterventionCell(nX, nY))
336 bVProfileValid[m] = false;
337
338 dVParProfileNow[m] = m_pRasterGrid->m_Cell[nX][nY].dGetSedimentTopElev();
339 }
340
341 // Get the total difference in elevation (present profile - Dean profile)
342 double const dParProfTotDiff = dSubtractProfiles(&dVParProfileNow, &VdParProfileDeanElev, &bVProfileValid);
343
344 // // DEBUG CODE -----------------------------------------------------
345 // LogStream << m_ulIter<< ": eroding polygon " << nPoly << " at coast point " << nCoastPoint << ", parallel profile with nInlandOffset = " << nInlandOffset << ", from [" << VPtiParProfile.back().nGetX() << "][" << VPtiParProfile.back().nGetY() << "] = {" << dGridCentroidXToExtCRSX(VPtiParProfile.back().nGetX()) << ", " << dGridCentroidYToExtCRSY(VPtiParProfile.back().nGetY()) << "} to [" << VPtiParProfile[0].nGetX() << "][" << VPtiParProfile[0].nGetY() << "] = {" << dGridCentroidXToExtCRSX(VPtiParProfile[0].nGetX()) << ", " << dGridCentroidYToExtCRSY(VPtiParProfile[0].nGetY()) << "}, nParProfLen = " << nParProfLen << " dParProfileLen = " << dParProfileLen << " dParProfCoastElev = " << dParProfCoastElev << " dParProfEndElev = " << dParProfEndElev << " dParProfA = " << dParProfA << endl;
346
347 // LogStream << "Profile now:" << endl;
348 // for (int n = 0; n < nParProfLen; n++)
349 // {
350 // if (bVProfileValid[n])
351 // LogStream << dVParProfileNow[n] << " ";
352 // else
353 // LogStream << "XXX ";
354 // }
355 // LogStream << endl << endl;;
356 //
357 // LogStream << "Parallel Dean profile for erosion:" << endl;
358 // for (int n = 0; n < nParProfLen; n++)
359 // {
360 // if (bVProfileValid[n])
361 // LogStream << VdParProfileDeanElev[n] << " ";
362 // else
363 // LogStream << "XXX ";
364 // }
365 // LogStream << endl << endl;
366 //
367 // LogStream << "Difference (present profile minus Dean profile):" << endl;
368 // for (int n = 0; n < nParProfLen; n++)
369 // {
370 // if (bVProfileValid[n])
371 // LogStream << dVParProfileNow[n] - VdParProfileDeanElev[n] << " ";
372 // else
373 // LogStream << "XXX ";
374 // }
375 // LogStream << endl << endl;
376 //
377 // LogStream << "dParProfTotDiff = " << dParProfTotDiff << " dAllTargetPerProfile = " << dAllTargetPerProfile << endl;
378 // // DEBUG CODE -----------------------------------------------------
379
380 // So will we be able to erode as much as is needed?
381 if (dParProfTotDiff > dAllTargetPerProfile)
382 {
383 // LogStream << m_ulIter << ": eroding polygon " << nPoly << " at coast point " << nCoastPoint << ", on parallel profile with nInlandOffset = " << nInlandOffset << ", can meet erosion target: dParProfTotDiff = " << dParProfTotDiff << " dAllTargetPerProfile = " << dAllTargetPerProfile << endl;
384
385 bEnoughEroded = true;
386 break;
387 }
388
389 // We have not been able to reach the erosion target for this parallel profile. Now, if we have moved at least MIN_INLAND_OFFSET_UNCONS_EROSION cells inland, and dParProfTotDiff is zero, break out of the loop
390 if ((nInlandOffset >= MIN_INLAND_OFFSET_UNCONS_EROSION) && (bFPIsEqual(dParProfTotDiff, 0.0, TOLERANCE)))
391 {
393 LogStream << m_ulIter << ": leaving loop because nInlandOffset (" << nInlandOffset << ") >= MIN_INLAND_OFFSET_UNCONS_EROSION) and dParProfTotDiff = " << dParProfTotDiff << endl;
394
395 break;
396 }
397
398 // Save the amount which can be eroded for this offset
399 VdAmountEachOffset.push_back(dParProfTotDiff);
400 VnParProfLenEachOffset.push_back(nParProfLen);
401 VVPtiParProfileEachOffset.push_back(VPtiParProfile);
402 VVdParProfileDeanElevEachOffset.push_back(VdParProfileDeanElev);
403 }
404
405 // If we hit the edge of the grid, or have a zero gradient on the profile, or this is an end profile, then abandon this profile and do the next parallel profile
406 // TODO 019 TODO 018 Improve this, see above
407 if (bHitEdge || bEndProfile || bZeroGradient)
408 continue;
409
410 // OK we will do some erosion on this parallel profile, set the target for this profile to be the full target amount
411 double dStillToErodeOnProfile = dAllTargetPerProfile;
412
413 if (!bEnoughEroded)
414 {
415 // We have not been able to reach the target for erosion on this parallel profile. So find the offset that gives us the largest erosion amount
416 int nOffsetForLargestPossible = -1;
417 double dLargestPossibleErosion = 0;
418
419 for (unsigned int nn = 0; nn < VdAmountEachOffset.size(); nn++)
420 {
421 if (VdAmountEachOffset[nn] > dLargestPossibleErosion)
422 {
423 dLargestPossibleErosion = VdAmountEachOffset[nn];
424 nOffsetForLargestPossible = nn;
425 }
426 }
427
428 // If every offset gave zero erosion then abandon this profile and do the next parallel profile
429 if (nOffsetForLargestPossible < 0)
430 continue;
431
432 // OK, we have an offset which gives us the largest possible erosion (but less than the full target amount), continue with this
433 nInlandOffset = nOffsetForLargestPossible;
434 dStillToErodeOnProfile = dLargestPossibleErosion;
435 nParProfLen = VnParProfLenEachOffset[nInlandOffset];
436 VPtiParProfile = VVPtiParProfileEachOffset[nInlandOffset];
437 VdParProfileDeanElev = VVdParProfileDeanElevEachOffset[nInlandOffset];
438
439 // LogStream << m_ulIter << ": eroding polygon " << nPoly << " at coast point " << nCoastPoint << ", for parallel profile with nInlandOffset = " << nInlandOffset << ", could not meet erosion target dAllTargetPerProfile = " << dAllTargetPerProfile << ", instead using best possible: nInlandOffset = " << nInlandOffset << " which gives dStillToErodeOnProfile = " << dStillToErodeOnProfile << endl;
440 }
441
442 // This value of nInlandOffset gives us some (tho' maybe not enough) erosion. So do the erosion of this sediment size class, by working along the parallel profile from the landward end (which is inland from the existing coast, if nInlandOffset > 0). Note that dStillToErodeOnProfile and dStillToErodeOnPolygon are changed within nDoParallelProfileUnconsErosion()
443 int const nRet = nDoParallelProfileUnconsErosion(pPolygon, nCoastPoint, nCoastX, nCoastY, nTexture, nInlandOffset, nParProfLen, &VPtiParProfile, &VdParProfileDeanElev, dStillToErodeOnProfile, dStillToErodeOnPolygon, dEroded);
444
445 if (nRet != RTN_OK)
446 return nRet;
447
448 // LogStream << m_ulIter << ": eroding polygon " << nPoly << ": finished at coast point " << nCoastPoint << " dStillToErodeOnProfile = " << dStillToErodeOnProfile << " dStillToErodeOnPolygon = " << dStillToErodeOnPolygon << " dAllTargetPerProfile = " << dAllTargetPerProfile << endl;
449
450 // if (dStillToErodeOnProfile > 0)
451 // {
452 // // LogStream << " X Still to erode on profile = " << dStillToErodeOnProfile << " dStillToErodeOnPolygon WAS = " << dStillToErodeOnPolygon;
453 // dStillToErodeOnPolygon += dStillToErodeOnProfile;
454 // dAllTargetPerProfile += (dStillToErodeOnProfile / (nCoastSegLen - n));
455 // // LogStream << " dStillToErodeOnPolygon NOW = " << dStillToErodeOnPolygon << endl;
456 // }
457
458 if (dStillToErodeOnPolygon <= 0)
459 {
460 // LogStream << m_ulIter << ": YYYYYYYYYYYYYYY in polygon " << nPoly << ", leaving loop because dStillToErodeOnPolygon = " << dStillToErodeOnPolygon << endl;
461 break;
462 }
463 }
464
465 // How much have we been able to erode?
466 // LogStream << m_ulIter << ": nPoly = " << nPoly << " dEroded = " << dEroded << endl;
467
468 // // Is the depth eroded within TOLERANCE of the target depth-equivalent?
469 // if (bFPIsEqual(dEroded, dErosionTargetOnPolygon, TOLERANCE))
470 // {
471 // if (m_nLogFileDetail >= LOG_FILE_MIDDLE_DETAIL)
472 // LogStream << m_ulIter << ": polygon " << nPoly << " actual erosion of " + strTexture + " sediment is approximately equal to estimate, actual = " << dEroded * m_dCellArea << " estimate = " << dErosionTargetOnPolygon * m_dCellArea << endl;
473 // }
474 // else
475 // {
476 // if (dEroded < dErosionTargetOnPolygon)
477 // {
478 // if (m_nLogFileDetail >= LOG_FILE_MIDDLE_DETAIL)
479 // LogStream << m_ulIter << ": polygon " << nPoly << " actual erosion of " + strTexture + " sediment is less than estimate, actual = " << dEroded * m_dCellArea << " estimate = " << dErosionTargetOnPolygon * m_dCellArea << " dStillToErodeOnPolygon = " << dStillToErodeOnPolygon * m_dCellArea << ". This reduces the volume of " + strTexture + " sediment exported from this polygon to " << (dErosionTargetOnPolygon - dStillToErodeOnPolygon) * m_dCellArea << endl;
480 // }
481 // else
482 // {
483 // if (m_nLogFileDetail >= LOG_FILE_MIDDLE_DETAIL)
484 // LogStream << ERR << "polygon " << nPoly << " actual erosion of " + strTexture + " sediment is greater than estimate, actual = " << dEroded * m_dCellArea << " estimate = " << dErosionTargetOnPolygon * m_dCellArea << " dStillToErodeOnPolygon = " << dStillToErodeOnPolygon * m_dCellArea << endl;
485 // }
486 // }
487
488 return RTN_OK;
489}
490
491//===============================================================================================================================
493//===============================================================================================================================
494int CSimulation::nDoParallelProfileUnconsErosion(CGeomCoastPolygon* pPolygon, int const nCoastPoint, int const nCoastX, int const nCoastY, int const nTexture, int const nInlandOffset, int const nParProfLen, vector<CGeom2DIPoint> const* pVPtiParProfile, vector<double> const* pVdParProfileDeanElev, double& dStillToErodeOnProfile, double& dStillToErodeOnPolygon, double& dTotEroded)
495{
496 for (int nDistSeawardFromNewCoast = 0; nDistSeawardFromNewCoast < nParProfLen; nDistSeawardFromNewCoast++)
497 {
498 // Leave the loop if we have eroded enough for this polygon
499 if (dStillToErodeOnPolygon <= 0)
500 {
502 LogStream << m_ulIter << ": AAA in polygon " << pPolygon->nGetCoastID() << " at coast point " << nCoastPoint << " nInlandOffset = " << nInlandOffset << ", leaving loop because enough erosion for polygon, dStillToErodeOnPolygon = " << dStillToErodeOnPolygon << " dStillToErodeOnProfile = " << dStillToErodeOnProfile << endl;
503
504 break;
505 }
506
507 // Leave the loop if we have eroded enough for this parallel profile
508 if (dStillToErodeOnProfile <= 0)
509 {
511 LogStream << m_ulIter << ": BBB in polygon " << pPolygon->nGetCoastID() << " at coast point " << nCoastPoint << " nInlandOffset = " << nInlandOffset << ", leaving loop because enough erosion for profile, dStillToErodeOnPolygon = " << dStillToErodeOnPolygon << " dStillToErodeOnProfile = " << dStillToErodeOnProfile << endl;
512
513 break;
514 }
515
516 CGeom2DIPoint PtiTmp = pVPtiParProfile->at(nParProfLen - nDistSeawardFromNewCoast - 1);
517 int
518 nX = PtiTmp.nGetX(),
519 nY = PtiTmp.nGetY();
520
521 // Safety check
522 if (!bIsWithinValidGrid(nX, nY))
523 {
524 // LogStream << WARN << "04 @@@@ while eroding polygon " << nPoly << ", hit edge of grid at [" << nX << "][" << nY << "] for parallel profile from coast point " << nCoastPoint << ". Constraining this parallel profile at its seaward end" << endl;
525
526 KeepWithinValidGrid(nCoastX, nCoastY, nX, nY);
527 PtiTmp.SetX(nX);
528 PtiTmp.SetY(nY);
529 }
530
531 // Don't do anything to intervention cells
532 if (bIsInterventionCell(nX, nY))
533 continue;
534
535 // Don't do cells twice
536 if (!m_pRasterGrid->m_Cell[nX][nY].bBeachErosionOrDepositionThisIter())
537 {
538 // Get this cell's current elevation
539 double const dThisElevNow = m_pRasterGrid->m_Cell[nX][nY].dGetSedimentTopElev();
540
541 // LogStream << "\tnPoly = " << nPoly << ", [" << nX << "][" << nY << "] = {" << dGridCentroidXToExtCRSX(nX) << ", " << dGridCentroidYToExtCRSY(nY) << "} nCoastPoint = " << nCoastPoint << " nDistSeawardFromNewCoast = " << nDistSeawardFromNewCoast << " dThisElevNow = " << dThisElevNow << " Dean Elev = " << VdParProfileDeanElev[nDistSeawardFromNewCoast] << endl;
542
543 // Subtract the two elevations
544 double const dElevDiff = dThisElevNow - pVdParProfileDeanElev->at(nDistSeawardFromNewCoast);
545
546 if ((dElevDiff > 0) && (m_pRasterGrid->m_Cell[nX][nY].bIsInContiguousSea()))
547 {
548 // The current elevation is higher than the Dean elevation, so we have possible beach erosion (i.e. if not constrained by availability of unconsolidated sediment) here
549 // LogStream << "\tnPoly = " << nPoly << " doing DOWN-COAST, possible beach erosion = " << dElevDiff << " at [" << nX << "][" << nY << "] = {" << dGridCentroidXToExtCRSX(nX) << ", " << dGridCentroidYToExtCRSY(nY) << "} nCoastPoint = " << nCoastPoint << " nDistSeawardFromNewCoast = " << nDistSeawardFromNewCoast << " dThisElevNow = " << dThisElevNow << " Dean Elev = " << pVdParProfileDeanElev->at(nDistSeawardFromNewCoast) << endl;
550
551 // Now get the number of the highest layer with non-zero thickness
552 int const nThisLayer = m_pRasterGrid->m_Cell[nX][nY].nGetTopNonZeroLayerAboveBasement();
553
554 // Safety check
555 if (nThisLayer == INT_NODATA)
557
558 if (nThisLayer != NO_NONZERO_THICKNESS_LAYERS)
559 {
560 // We still have at least one layer left with non-zero thickness (i.e. we are not down to basement), and the cell's current elevation is higher than the Dean equilibrium profile elevation. So do some beach erosion
561 double const dToErode = tMin(dElevDiff, dStillToErodeOnProfile, dStillToErodeOnPolygon);
562 double dRemoved = 0;
563
564 // assert(dToErode > 0);
565
566 // Erode this sediment size class
567 ErodeCellBeachSedimentSupplyLimited(nX, nY, nThisLayer, nTexture, dToErode, dRemoved);
568
569 if (dRemoved > 0)
570 {
571 // Update totals for the polygon and the profile
572 dTotEroded += dRemoved;
573 dStillToErodeOnProfile -= dRemoved;
574 dStillToErodeOnPolygon -= dRemoved;
575
576 // Update this-timestep totals
578
579 // LogStream << m_ulIter << ": in polygon " << nPoly << ", actual beach erosion = " << dTmpTot << " at [" << nX << "][" << nY << "] = {" << dGridCentroidXToExtCRSX(nX) << ", " << dGridCentroidYToExtCRSY(nY) << "} nCoastPoint = " << nCoastPoint << " nDistSeawardFromNewCoast = " << nDistSeawardFromNewCoast << endl;
580
581 // // DEBUG CODE ==================================================================================================
582 // if (nTexture == TEXTURE_SAND)
583 // {
584 // LogStream << m_ulIter << ": $$$$$$$$$ BEACH 2 Dean profile lower than existing profile, SAND depth eroded on [" << nX << "][" << nY << "] in Poly " << nPoly << " is " << dRemoved * m_dCellArea << endl;
585 // }
586 // else
587 // {
588 // LogStream << m_ulIter << ": $$$$$$$$$ BEACH 2 Dean profile lower than existing profile, COARSE depth eroded on [" << nX << "][" << nY << "] in Poly " << nPoly << " is " << dRemoved * m_dCellArea << endl;
589 // }
590 // // DEBUG CODE ==================================================================================================
591
592 // Store the this-polygon depth of sediment eroded during Dean profile deposition of beach unconsolidated sediment
593 if (nTexture == TEXTURE_SAND)
594 pPolygon->AddBeachSandErodedDeanProfile(dRemoved);
595
596 else
597 pPolygon->AddBeachCoarseErodedDeanProfile(dRemoved);
598 }
599 }
600 }
601
602 else if ((dElevDiff < 0) && (m_pRasterGrid->m_Cell[nX][nY].bIsInContiguousSea()))
603 {
604 if ((nTexture == TEXTURE_SAND) || (nTexture == TEXTURE_COARSE))
605 {
606 // The current elevation is below the Dean elevation, so we have can have unconsolidated sediment deposition here provided that we have some previously-eroded unconsolidated sediment (sand and coarse only) to deposit
607 if (dTotEroded > 0)
608 {
609 double dTotToDeposit = tMin(-dElevDiff, dTotEroded);
610
611 int const nTopLayer = m_pRasterGrid->m_Cell[nX][nY].nGetTopLayerAboveBasement();
612
613 // Safety check
614 if (nTopLayer == INT_NODATA)
616
617 if (dTotToDeposit > 0)
618 {
619 dTotToDeposit = tMin(dTotToDeposit, dTotEroded);
620
621 if (nTexture == TEXTURE_SAND)
622 {
623 double const dSandNow = m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nTopLayer)->pGetUnconsolidatedSediment()->dGetSandDepth();
624 m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nTopLayer)->pGetUnconsolidatedSediment()->SetSandDepth(dSandNow + dTotToDeposit);
625
626 // Set the changed-this-timestep switch
627 m_bUnconsChangedThisIter[nTopLayer] = true;
628
629 dTotEroded -= dTotToDeposit;
630
631 dStillToErodeOnProfile += dTotToDeposit;
632 dStillToErodeOnPolygon += dTotToDeposit;
633
634 // Update per-timestep totals
636 // m_dThisIterBeachDepositionSand += dTotToDeposit;
637 }
638
639 if (nTexture == TEXTURE_COARSE)
640 {
641 double const dCoarseNow = m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nTopLayer)->pGetUnconsolidatedSediment()->dGetCoarseDepth();
642 m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nTopLayer)->pGetUnconsolidatedSediment()->SetCoarseDepth(dCoarseNow + dTotToDeposit);
643
644 // Set the changed-this-timestep switch
645 m_bUnconsChangedThisIter[nTopLayer] = true;
646
647 dTotEroded -= dTotToDeposit;
648
649 dStillToErodeOnProfile += dTotToDeposit;
650 dStillToErodeOnPolygon += dTotToDeposit;
651
652 // Update per-timestep totals
654 m_dThisIterBeachDepositionCoarse += dTotToDeposit;
655 }
656 }
657
658 // Now update the cell's layer elevations
659 m_pRasterGrid->m_Cell[nX][nY].CalcAllLayerElevsAndD50();
660
661 // Update the cell's sea depth
662 m_pRasterGrid->m_Cell[nX][nY].SetSeaDepth();
663
664 // Update the cell's beach deposition, and total beach deposition, values
665 m_pRasterGrid->m_Cell[nX][nY].IncrBeachDeposition(dTotToDeposit);
666
667 // And set the landform category
668 CRWCellLandform* pLandform = m_pRasterGrid->m_Cell[nX][nY].pGetLandform();
669 int const nCat = pLandform->nGetLFCategory();
670
673
674 // LogStream << m_ulIter << ": nPoly = " << nPoly << ", beach deposition = " << dTotToDeposit << " at [" << nX << "][" << nY << "] = {" << dGridCentroidXToExtCRSX(nX) << ", " << dGridCentroidYToExtCRSY(nY) << "} nCoastPoint = " << nCoastPoint << " nDistSeawardFromNewCoast = " << nDistSeawardFromNewCoast << endl;
675 }
676 }
677 }
678 }
679 }
680
681 return RTN_OK;
682}
683
684//===============================================================================================================================
686//===============================================================================================================================
687void CSimulation::ErodeCellBeachSedimentSupplyLimited(int const nX, int const nY, int const nThisLayer, int const nTexture, double const dMaxToErode, double& dRemoved)
688{
689 // Find out how much unconsolidated sediment of this size class we have available on this cell
690 double dExistingAvailable = 0;
691 double dErodibility = 0;
692
693 if (nTexture == TEXTURE_FINE)
694 {
695 dExistingAvailable = m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetUnconsolidatedSediment()->dGetFineDepth();
696 dErodibility = m_dFineErodibilityNormalized;
697 }
698
699 else if (nTexture == TEXTURE_SAND)
700 {
701 dExistingAvailable = m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetUnconsolidatedSediment()->dGetSandDepth();
702 dErodibility = m_dSandErodibilityNormalized;
703 }
704
705 else if (nTexture == TEXTURE_COARSE)
706 {
707 dExistingAvailable = m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetUnconsolidatedSediment()->dGetCoarseDepth();
708 dErodibility = m_dCoarseErodibilityNormalized;
709 }
710
711 // Is there any unconsolidated sediment on this cell?
712 if (dExistingAvailable <= 0)
713 {
714 return;
715 }
716
717 // Erode some unconsolidated sediment
718 double const dLowering = dErodibility * dMaxToErode;
719
720 // Make sure we don't get -ve amounts left on the cell
721 dRemoved = tMin(dExistingAvailable, dLowering);
722 double const dRemaining = dExistingAvailable - dRemoved;
723
724 if (nTexture == TEXTURE_FINE)
725 {
726 // Set the value for this layer
727 m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetUnconsolidatedSediment()->SetFineDepth(dRemaining);
728 }
729
730 else if (nTexture == TEXTURE_SAND)
731 {
732 // Set the value for this layer
733 m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetUnconsolidatedSediment()->SetSandDepth(dRemaining);
734 }
735
736 else if (nTexture == TEXTURE_COARSE)
737 {
738 // Set the value for this layer
739 m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nThisLayer)->pGetUnconsolidatedSediment()->SetCoarseDepth(dRemaining);
740 }
741
742 // And set the changed-this-timestep switch
743 m_bUnconsChangedThisIter[nThisLayer] = true;
744
745 // Set the actual erosion value for this cell
746 m_pRasterGrid->m_Cell[nX][nY].SetActualBeachErosion(dRemoved);
747
748 if (dRemoved > 0)
749 {
750 // Recalculate the elevation of every layer
751 m_pRasterGrid->m_Cell[nX][nY].CalcAllLayerElevsAndD50();
752
753 // And update the cell's sea depth
754 m_pRasterGrid->m_Cell[nX][nY].SetSeaDepth();
755 }
756}
757
758//===============================================================================================================================
760//===============================================================================================================================
761int CSimulation::nDoUnconsDepositionOnPolygon(int const nCoast, CGeomCoastPolygon* pPolygon, int const nTexture, double dTargetToDepositOnPoly, double& dDepositedOnPoly)
762{
763 // // DEBUG CODE #####################
764 // if (m_ulIter == 1)
765 // {
766 // int nPoly = pPolygon->nGetCoastID();
767 // LogStream << m_ulIter << ": entered nDoUnconsDepositionOnPolygon() nCoast = " << nCoast << " nPoly = " << nPoly << " dTargetToDepositOnPoly = " << dTargetToDepositOnPoly * m_dCellArea << " dDepositedOnPoly = " << dDepositedOnPoly * m_dCellArea << endl;
768 // }
769 // // DEBUG CODE #####################
770
771 string strTexture;
772
773 if (nTexture == TEXTURE_SAND)
774 strTexture = "sand";
775
776 else if (nTexture == TEXTURE_COARSE)
777 strTexture = "coarse";
778
779 // Don't bother with tiny amounts of deposition
780 if (dTargetToDepositOnPoly < SEDIMENT_ELEV_TOLERANCE)
781 return RTN_OK;
782
783 // Get the grid cell coordinates of this polygon's up-coast and down-coast profiles
784 int const nUpCoastProfile = pPolygon->nGetUpCoastProfile();
785 int const nDownCoastProfile = pPolygon->nGetDownCoastProfile();
786
787 CGeomProfile* pUpCoastProfile = m_VCoast[nCoast].pGetProfile(nUpCoastProfile);
788 CGeomProfile* pDownCoastProfile = m_VCoast[nCoast].pGetProfile(nDownCoastProfile);
789
790 // We are using only part of each profile, seaward as far as the depth of closure. First find the seaward end point of the up-coast part-profile
791 // CGeom2DIPoint PtiUpCoastPartProfileSeawardEnd;
792 // int nIndex = pUpCoastProfile->nGetCellGivenDepth(m_pRasterGrid, m_dDepthOfClosure, &PtiUpCoastPartProfileSeawardEnd);
793 int const nIndex = pUpCoastProfile->nGetCellGivenDepth(m_pRasterGrid, m_dDepthOfClosure);
794
795 if (nIndex == INT_NODATA)
796 {
797 LogStream << m_ulIter << ": " << ERR << "while depositing " + strTexture + " unconsolidated sediment for coast " << nCoast << " polygon " << pPolygon->nGetCoastID() << ", could not find the seaward end point of the up-coast profile (" << nUpCoastProfile << ") for depth of closure = " << m_dDepthOfClosure << endl;
798
800 }
801
802 // The part-profile length is one greater than nIndex, since pPtiGetCellGivenDepth() returns the index of the cell at depth of closure. This will be the number of cells in the Dean profile portion of every parallel profile
803 int const nUpCoastDeanLen = nIndex + 1;
804
805 // assert(bIsWithinValidGrid(&PtiUpCoastPartProfileSeawardEnd));
806
807 // Get the distance between the start and end of the part-profile (the Dean length), in external CRS units
808 // CGeom2DPoint
809 // PtUpCoastProfileStart = *pUpCoastProfile->pPtGetPointInProfile(0),
810 // PtUpCoastProfileEnd = PtGridCentroidToExt(&PtiUpCoastPartProfileSeawardEnd);
811
812 // double dUpCoastDeanLen = dGetDistanceBetween(&PtUpCoastProfileStart, &PtUpCoastProfileEnd);
813
814 int const nUpCoastProfileCoastPoint = pUpCoastProfile->nGetCoastPoint();
815 int const nDownCoastProfileCoastPoint = pDownCoastProfile->nGetCoastPoint();
816 int const nXUpCoastProfileExistingCoastPoint = m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(nUpCoastProfileCoastPoint)->nGetX();
817 int const nYUpCoastProfileExistingCoastPoint = m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(nUpCoastProfileCoastPoint)->nGetY();
818 int nCoastSegLen;
819
820 // Store the coast point numbers for this polygon so that we can shuffle them
821 vector<int> nVCoastPoint;
822
823 if (nDownCoastProfileCoastPoint == m_VCoast[nCoast].nGetCoastlineSize() - 1)
824 {
825 // This is the final down-coast polygon, so also include the down-coast polygon boundary
826 nCoastSegLen = nDownCoastProfileCoastPoint - nUpCoastProfileCoastPoint + 1;
827
828 for (int nCoastPoint = nUpCoastProfileCoastPoint; nCoastPoint <= nDownCoastProfileCoastPoint; nCoastPoint++)
829 nVCoastPoint.push_back(nCoastPoint);
830 }
831
832 else
833 {
834 // This is not the final down-coast polygon, so do not include the polygon's down-coast boundary
835 nCoastSegLen = nDownCoastProfileCoastPoint - nUpCoastProfileCoastPoint;
836
837 for (int nCoastPoint = nUpCoastProfileCoastPoint; nCoastPoint < nDownCoastProfileCoastPoint; nCoastPoint++)
838 nVCoastPoint.push_back(nCoastPoint);
839 }
840
841 double dStillToDepositOnPoly = dTargetToDepositOnPoly;
842 double dTargetToDepositOnProfile = dTargetToDepositOnPoly / nCoastSegLen;
843 double dStillToDepositOnProfile; // = dTargetToDepositOnProfile;
844
845 // Shuffle the coast points, this is necessary so that leaving the loop does not create sequence-related artefacts
846 shuffle(nVCoastPoint.begin(), nVCoastPoint.begin() + nCoastSegLen, m_Rand[1]);
847
848 // // Get the volume of sediment which is to be deposited on the polygon and on each parallel profile. Note that if dSandToMoveOnPoly is -ve, then don't do any sand deposition. Similarly if dCoarseToMoveOnPoly is -ve then don't do any coarse deposition
849 // double
850 // dSandToMoveOnPoly = pPolygon->dGetToDoBeachDepositionUnconsSand(), // +ve is deposition, -ve is erosion
851 // dCoarseToMoveOnPoly = pPolygon->dGetToDoBeachDepositionUnconsCoarse(); // +ve is deposition, -ve is erosion
852 //
853 // double
854 // dTmpLower = 0,
855 // dSandRatio = 0,
856 // dCoarseRatio = 0,
857 // dSandTargetToDepositOnPoly = 0,
858 // dCoarseTargetToDepositOnPoly = 0;
859 // if (dSandToMoveOnPoly > 0)
860 // dTmpLower += dSandToMoveOnPoly;
861 // if (dCoarseToMoveOnPoly > 0)
862 // dTmpLower += dCoarseToMoveOnPoly;
863 //
864 // if ((dSandToMoveOnPoly > 0) && (dTmpLower > 0))
865 // dSandRatio = dSandToMoveOnPoly / dTmpLower;
866 // if (dCoarseToMoveOnPoly > 0)
867 // dCoarseRatio = 1 - dSandRatio;
868 //
869 // // LogStream << "####### nPoly = " << nPoly << " dSandRatio = " << dSandRatio << " dCoarseRatio = " << dCoarseRatio << endl;
870 //
871 // dSandTargetToDepositOnPoly = dAllTargetToDepositOnPoly * dSandRatio,
872 // dCoarseTargetToDepositOnPoly = dAllTargetToDepositOnPoly * dCoarseRatio;
873 //
874 // double
875 // dAllTargetPerProfile = dTargetToDepositOnPoly / nCoastSegLen,
876 // dTargetStillToDepositOnProfile = dTargetToDepositOnPoly / nCoastSegLen,
877 // dSandDepositedOnPoly = 0, // Grand total for the whole polygon
878 // dCoarseDepositedOnPoly = 0; // Grand total for the whole polygon
879 //
880 // // LogStream << "####### nPoly = " << nPoly << " dSandToMoveOnPoly = " << dSandToMoveOnPoly << " dCoarseToMoveOnPoly = " << dCoarseToMoveOnPoly << endl;
881 //
882 // // LogStream << "####### nPoly = " << nPoly << " dSandTargetToDepositOnPoly = " << dSandTargetToDepositOnPoly << " dCoarseTargetToDepositOnPoly = " << dCoarseTargetToDepositOnPoly << " dAllTargetToDepositOnPoly = " << dAllTargetToDepositOnPoly << endl;
883
884 // Now traverse the polygon's existing coastline in a random (but broadly DOWN-COAST i.e. increasing coast point indices) sequence, fitting a Dean profile at each coast point
885 // DOWN-COAST (increasing coastpoint indices) ================================================================================
886 // LogStream << "####### DOWN-COAST nPoly = " << nPoly << " nCoastSegLen = " << nCoastSegLen << endl;
887 for (int n = 0; n < nCoastSegLen; n++)
888 {
889 // Pick a random coast point
890 int const nCoastPoint = nVCoastPoint[n];
891 CGeom2DIPoint const PtiCoastPoint = *m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(nCoastPoint);
892 int const nCoastX = PtiCoastPoint.nGetX();
893 int const nCoastY = PtiCoastPoint.nGetY();
894
895 // Calculate the x-y offset between this coast point, and the coast point of the up-coast normal
896 int const nXOffset = nCoastX - nXUpCoastProfileExistingCoastPoint;
897 int const nYOffset = nCoastY - nYUpCoastProfileExistingCoastPoint;
898 int nSeawardOffset = -1;
899 // nParProfLen;
900 vector<CGeom2DIPoint> PtiVParProfile;
901 vector<double> VdParProfileDeanElev;
902
903 // OK, loop until we can deposit sufficient unconsolidated sediment on the parallel profile starting at this coast point
904 while (true)
905 {
906 // Move seaward by one cell
907 nSeawardOffset++;
908
909 // And lengthen the parallel profile
910 int nParProfLen = nUpCoastDeanLen + nSeawardOffset;
911
912 if (nParProfLen > (pUpCoastProfile->nGetNumCellsInProfile()))
913 {
914 // We've reached the seaward end of the up-coast profile, need to quit
915 // if (m_nLogFileDetail >= LOG_FILE_MIDDLE_DETAIL)
916 // LogStream << m_ulIter << ": " << WARN << "reached seaward end of up-coast profile during DOWN-COAST deposition of unconsolidated sediment for coast " << nCoast << " polygon " << pPolygon->nGetCoastID() << " (nCoastPoint = " << nCoastPoint << " nSeawardOffset = " << nSeawardOffset << ")" << endl;
917
918 break;
919 }
920
921 // Get the x-y coords of a profile starting from this coast point and parallel to the up-coast polygon boundary profile (these are in natural sequence, like the boundary part-profile)
922 PtiVParProfile.resize(0);
923
924 for (int m = 0; m < nParProfLen; m++)
925 {
926 CGeom2DIPoint const PtiProf = *pUpCoastProfile->pPtiGetCellInProfile(m);
927 CGeom2DIPoint const PtiTmp(PtiProf.nGetX() + nXOffset, PtiProf.nGetY() + nYOffset);
928 PtiVParProfile.push_back(PtiTmp);
929 }
930
931 // Get the existing elevation of the seaward end of the parallel profile
932 int nSeaEndX = PtiVParProfile.back().nGetX();
933 int nSeaEndY = PtiVParProfile.back().nGetY();
934
935 // Safety check
936 if (!bIsWithinValidGrid(nSeaEndX, nSeaEndY))
937 {
938 // if (m_nLogFileDetail >= LOG_FILE_MIDDLE_DETAIL)
939 // LogStream << WARN << "09 @@@@ while doing DOWN-COAST deposition on polygon " << nPoly << ", hit edge of grid at [" << nSeaEndX << "][" << nSeaEndY << "] for parallel profile from coast point " << nCoastPoint << " at [" << nCoastX << "][" << nCoastY << "]. Constraining this parallel profile at its seaward end" << endl;
940
941 KeepWithinValidGrid(nCoastX, nCoastY, nSeaEndX, nSeaEndY);
942 PtiVParProfile.back().SetX(nSeaEndX);
943 PtiVParProfile.back().SetY(nSeaEndY);
944 }
945
946 double const dParProfEndElev = m_pRasterGrid->m_Cell[nSeaEndX][nSeaEndY].dGetSedimentTopElev();
947
948 // Set the start elevation for the Dean profile just a bit above mean SWL for this timestep (i.e. so that it is a Bruun profile)
949 double const dParProfStartElev = m_dThisIterMeanSWL + m_dDeanProfileStartAboveSWL;
950
951 // Calculate the total length of the parallel profile, including any seaward offset
952 double const dParProfLen = dGetDistanceBetween(&PtiVParProfile.front(), &PtiVParProfile.back());
953
954 // Now calculate the length of the Dean profile-only part i.e. without any seaward offset. The approach used here is approximate but probably OK
955 double dParProfDeanLen = dParProfLen - (nSeawardOffset * m_dCellSide);
956
957 // Safety check
958 if (dParProfDeanLen <= 0)
959 dParProfDeanLen = 1;
960
961 // Solve for dA so that the existing elevations at the end of the parallel profile, and at the end of a Dean equilibrium profile on that part-normal, are the same
962 double const dParProfA = (dParProfStartElev - dParProfEndElev) / pow(dParProfDeanLen, DEAN_POWER);
963
964 nParProfLen = static_cast<int>(PtiVParProfile.size());
965 VdParProfileDeanElev.resize(nParProfLen, 0);
966
967 // for (int m = 0; m < static_cast<int>(PtiVParProfile.size()); m++)
968 // LogStream << "[" << PtiVParProfile[m].nGetX() << "][" << PtiVParProfile[m].nGetY() << "] ";
969 // LogStream << endl;
970
971 double const dInc = dParProfDeanLen / (nParProfLen - nSeawardOffset - 2);
972
973 // The elevation of the coast point in the Dean profile is the same as the elevation of the current coast point TODO 020 Is this correct? Should it be dParProfStartElev?
974 double const dCoastElev = m_pRasterGrid->m_Cell[nCoastX][nCoastY].dGetSedimentTopElev();
975
976 // For this depositing parallel profile, calculate the Dean equilibrium profile of the unconsolidated sediment h(y) = A * y^(2/3) where h(y) is the distance below the highest point in the profile at a distance y from the landward start of the profile
977 CalcDeanProfile(&VdParProfileDeanElev, dInc, dParProfStartElev, dParProfA, true, nSeawardOffset, dCoastElev);
978
979 double dParProfTotDiff = 0;
980
981 for (int m = 0; m < nParProfLen; m++)
982 {
983 CGeom2DIPoint PtiTmp = PtiVParProfile[m];
984 int nX = PtiTmp.nGetX();
985 int nY = PtiTmp.nGetY();
986
987 // Safety check
988 if (!bIsWithinValidGrid(nX, nY))
989 {
990 // LogStream << WARN << "10 @@@@ while doing DOWN-COAST deposition on polygon " << nPoly << ", hit edge of grid at [" << nX << "][" << nY << "] for parallel profile from coast point " << nCoastPoint << " at [" << nCoastX << "][" << nCoastY << "]. Constraining this parallel profile at its seaward end" << endl;
991
992 KeepWithinValidGrid(nCoastX, nCoastY, nX, nY);
993 PtiTmp.SetX(nX);
994 PtiTmp.SetY(nY);
995 }
996
997 // Don't do anything to intervention cells
998 if (bIsInterventionCell(nX, nY))
999 continue;
1000
1001 // Don't do cells twice
1002 if (!m_pRasterGrid->m_Cell[nX][nY].bBeachErosionOrDepositionThisIter())
1003 {
1004 double const dTmpElev = m_pRasterGrid->m_Cell[nX][nY].dGetSedimentTopElev();
1005 double const dDiff = VdParProfileDeanElev[m] - dTmpElev;
1006
1007 dParProfTotDiff += dDiff;
1008 }
1009 }
1010
1011 // // DEBUG CODE -----------------------------------------------------
1012 // LogStream << endl << "\tFor polygon " << nPoly << " doing DOWN-COAST deposition, nSeawardOffset = " << nSeawardOffset << ", parallel profile from [" << PtiVParProfile[0].nGetX() << "][" << PtiVParProfile[0].nGetY() << "] to [" << PtiVParProfile.back().nGetX() << "][" << PtiVParProfile.back().nGetY() << "], nUpCoastDeanLen = " << nUpCoastDeanLen << " dUpCoastDeanLen = " << dUpCoastDeanLen << " nParProfLen = " << nParProfLen << " dParProfDeanLen = " << dParProfDeanLen << " dInc = " << dInc << " dParProfStartElev = " << dParProfStartElev << " dParProfEndElev = " << dParProfEndElev << " dParProfA = " << dParProfA << endl;
1013 //
1014 // LogStream << "\tExisting profile for deposition = ";
1015 // for (int n = 0; n < nParProfLen; n++)
1016 // {
1017 // CGeom2DIPoint PtiTmp = PtiVParProfile[n];
1018 // int
1019 // nX = PtiTmp.nGetX(),
1020 // nY = PtiTmp.nGetY();
1021 //
1022 // // Safety check
1023 // if (! bIsWithinValidGrid(nX, nY))
1024 // KeepWithinValidGrid(nX, nY);
1025 //
1026 // LogStream << m_pRasterGrid->m_Cell[nX][nY].dGetSedimentTopElev() << " ";
1027 // }
1028 // LogStream << endl;
1029 // LogStream << "\tParallel Dean equilibrium profile for deposition = ";
1030 // for (int n = 0; n < nParProfLen; n++)
1031 // {
1032 // LogStream << VdParProfileDeanElev[n] << " ";
1033 // }
1034 // LogStream << endl;
1035 //
1036 // LogStream << "\tnCoastPoint = " << nCoastPoint << " nSeawardOffset = " << nSeawardOffset << " difference = ";
1037 // for (int n = 0; n < nParProfLen; n++)
1038 // {
1039 // CGeom2DIPoint PtiTmp = PtiVParProfile[n];
1040 // int
1041 // nX = PtiTmp.nGetX(),
1042 // nY = PtiTmp.nGetY();
1043 //
1044 // // Safety check
1045 // if (! bIsWithinValidGrid(nX, nY))
1046 // KeepWithinValidGrid(nX, nY);
1047 //
1048 // double
1049 // dTmpElev = m_pRasterGrid->m_Cell[nX][nY].dGetSedimentTopElev(),
1050 // dDiff = VdParProfileDeanElev[n] - dTmpElev;
1051 //
1052 // LogStream << dDiff << " ";
1053 // }
1054 // LogStream << endl;
1055 // // END DEBUG CODE -----------------------------------------------------
1056
1057 // So will we be able to deposit as much as is needed?
1058 if (dParProfTotDiff >= dTargetToDepositOnProfile)
1059 {
1060 // LogStream << " DOWN-COAST nPoly = " << pPolygon->nGetCoastID() << " nCoastPoint = " << nCoastPoint << " nSeawardOffset = " << nSeawardOffset << " dParProfTotDiff = " << dParProfTotDiff << " dTargetToDepositOnProfile = " << dTargetToDepositOnProfile << " WILL BE ABLE TO DEPOSIT ENOUGH" << endl;
1061
1062 break;
1063 }
1064 }
1065
1066 // assert(dParProfTotDiff > 0);
1067
1068 // OK, this value of nSeawardOffset gives us enough deposition. So start depositing on the parallel profile from the coastward end
1069 double dDepositedOnProfile = 0; // Total for this parallel profile
1070
1071 // LogStream << " DOWN-COAST nPoly = " << nPoly << " nCoastPoint = " << nCoastPoint << " doing deposition on parallel profile, dSandTargetStillToDepositOnProfile = " << dSandTargetStillToDepositOnProfile << " dCoarseTargetToDepositOnProfile = " << dCoarseTargetToDepositOnProfile << endl;
1072
1073 dStillToDepositOnProfile = dTargetToDepositOnProfile;
1074
1075 for (unsigned int nSeawardFromCoast = 0; nSeawardFromCoast < PtiVParProfile.size(); nSeawardFromCoast++)
1076 {
1077 // Move along this parallel profile starting from the coast. Leave the loop if we have deposited enough on this polygon
1078 if (dStillToDepositOnPoly < SEDIMENT_ELEV_TOLERANCE)
1079 {
1080 // LogStream << m_ulIter << ": nPoly = " << nPoly << " texture = " << strTexture << " DOWN-COAST nCoastPoint = " << nCoastPoint << " nSeawardOffset = " << nSeawardOffset << " leaving loop because enough deposited on polygon, dTargetToDepositOnPoly = " << dTargetToDepositOnPoly << " dDepositedOnPoly = " << dDepositedOnPoly << endl;
1081
1082 break;
1083 }
1084
1085 // Leave the loop if we have deposited enough on this parallel profile
1086 if (dStillToDepositOnProfile < SEDIMENT_ELEV_TOLERANCE)
1087 {
1088 // LogStream << m_ulIter << ": nPoly = " << nPoly << " texture = " << strTexture << " DOWN-COAST nCoastPoint = " << nCoastPoint << " nSeawardOffset = " << nSeawardOffset << " leaving loop because enough deposited on parallel profile, dTargetStillToDepositOnProfile = " << dTargetStillToDepositOnProfile << " dDepositedOnProfile = " << dDepositedOnProfile << endl;
1089
1090 break;
1091 }
1092
1093 // assert(nSeawardFromCoast < PtiVParProfile.size());
1094 CGeom2DIPoint PtiTmp = PtiVParProfile[nSeawardFromCoast];
1095 int nX = PtiTmp.nGetX();
1096 int nY = PtiTmp.nGetY();
1097
1098 // Safety check
1099 if (!bIsWithinValidGrid(nX, nY))
1100 {
1101 // LogStream << WARN << "11 @@@@ while doing DOWN-COAST deposition on polygon " << nPoly << ", hit edge of grid at [" << nX << "][" << nY << "] for parallel profile from coast point " << nCoastPoint << " at [" << nCoastX << "][" << nCoastY << "]. Constraining this parallel profile at its seaward end" << endl;
1102
1103 KeepWithinValidGrid(nCoastX, nCoastY, nX, nY);
1104 PtiTmp.SetX(nX);
1105 PtiTmp.SetY(nY);
1106 }
1107
1108 // Don't do anything to intervention cells
1109 if (bIsInterventionCell(nX, nY))
1110 continue;
1111
1112 // Don't do cells twice
1113 if (!m_pRasterGrid->m_Cell[nX][nY].bBeachErosionOrDepositionThisIter())
1114 {
1115 // Get this cell's current elevation
1116 double const dThisElevNow = m_pRasterGrid->m_Cell[nX][nY].dGetSedimentTopElev();
1117
1118 // LogStream << "\tnPoly = " << nPoly << ", [" << nX << "][" << nY << "] nCoastPoint = " << nCoastPoint << " nSeawardFromCoast = " << nSeawardFromCoast << " dThisElevNow = " << dThisElevNow << " Dean Elev = " << VdParProfileDeanElev[nSeawardFromCoast] << endl;
1119
1120 // Subtract the two elevations
1121 double const dElevDiff = VdParProfileDeanElev[nSeawardFromCoast] - dThisElevNow;
1122 CRWCellLandform* pLandform = m_pRasterGrid->m_Cell[nX][nY].pGetLandform();
1123
1124 if (dElevDiff > SEDIMENT_ELEV_TOLERANCE)
1125 {
1126 bool bDeposited = false;
1127 double dToDepositHere = 0;
1128
1129 // The current elevation is below the Dean elevation, so we have can have beach deposition here
1130 if (dStillToDepositOnProfile > SEDIMENT_ELEV_TOLERANCE)
1131 {
1132 dToDepositHere = tMin(dElevDiff, dStillToDepositOnProfile, dStillToDepositOnPoly);
1133
1134 // LogStream << " DOWN-COAST nPoly = " << nPoly << " nCoastPoint = " << nCoastPoint << " texture = " << strTexture << " dToDepositHere = " << dToDepositHere << endl;
1135
1136 int const nTopLayer = m_pRasterGrid->m_Cell[nX][nY].nGetTopLayerAboveBasement();
1137
1138 // Safety check
1139 if (nTopLayer == INT_NODATA)
1140 return RTN_ERR_NO_TOP_LAYER;
1141
1142 if (dToDepositHere > SEDIMENT_ELEV_TOLERANCE)
1143 {
1144 bDeposited = true;
1145
1146 if (nTexture == TEXTURE_SAND)
1147 {
1148 double const dSandNow = m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nTopLayer)->pGetUnconsolidatedSediment()->dGetSandDepth();
1149
1150 m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nTopLayer)->pGetUnconsolidatedSediment()->SetSandDepth(dSandNow + dToDepositHere);
1151
1152 // Set the changed-this-timestep switch
1153 m_bUnconsChangedThisIter[nTopLayer] = true;
1154
1155 dDepositedOnProfile += dToDepositHere;
1156 dDepositedOnPoly += dToDepositHere;
1157
1158 // LogStream << "XXXXXXX texture = " << strTexture << " dDepositedOnProfile = " << dDepositedOnProfile << " dDepositedOnPoly = " << dDepositedOnPoly << endl;
1159
1160 // Update the cell's beach deposition, and total beach deposition, values
1161 m_pRasterGrid->m_Cell[nX][nY].IncrBeachDeposition(dToDepositHere);
1162
1163 dStillToDepositOnPoly -= dToDepositHere;
1164 dStillToDepositOnProfile -= dToDepositHere;
1165
1166 // if (dDepositedOnPoly > dTargetToDepositOnPoly)
1167 // {
1168 // // LogStream << "££££££ 1 nPoly = " << nPoly << " nCoastPoint = " << nCoastPoint << " dDepositedOnProfile = " << dDepositedOnProfile << " dDepositedOnPoly = " << dDepositedOnPoly << " dTargetToDepositOnPoly = " << dTargetToDepositOnPoly << endl;
1169 // }
1170
1171 // LogStream << m_ulIter << ": nPoly = " << nPoly << " texture = " << strTexture << " dToDepositHere = " << dToDepositHere << " at [" << nX << "][" << nY << "] = {" << dGridCentroidXToExtCRSX(nX) << ", " << dGridCentroidYToExtCRSY(nY) << "} nCoastPoint = " << nCoastPoint << " nSeawardFromCoast = " << nSeawardFromCoast << endl;
1172 }
1173
1174 else if (nTexture == TEXTURE_COARSE)
1175 {
1176 double const dCoarseNow = m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nTopLayer)->pGetUnconsolidatedSediment()->dGetCoarseDepth();
1177
1178 m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nTopLayer)->pGetUnconsolidatedSediment()->SetCoarseDepth(dCoarseNow + dToDepositHere);
1179
1180 // Set the changed-this-timestep switch
1181 m_bUnconsChangedThisIter[nTopLayer] = true;
1182
1183 // if (dDepositedOnPoly > dTargetToDepositOnPoly)
1184 // {
1185 // // LogStream << "££££££ 2 nPoly = " << nPoly << " dDepositedOnPoly = " << dDepositedOnPoly << " dTargetToDepositOnPoly = " << dTargetToDepositOnPoly << endl;
1186 // }
1187
1188 dDepositedOnProfile += dToDepositHere;
1189 dDepositedOnPoly += dToDepositHere;
1190
1191 // LogStream << "XXXXXXX texture = " << strTexture << " dDepositedOnProfile = " << dDepositedOnProfile << " dDepositedOnPoly = " << dDepositedOnPoly << endl;
1192
1193 // Update the cell's beach deposition, and total beach deposition, values
1194 m_pRasterGrid->m_Cell[nX][nY].IncrBeachDeposition(dToDepositHere);
1195
1196 dStillToDepositOnPoly -= dToDepositHere;
1197 dStillToDepositOnProfile -= dToDepositHere;
1198
1199 // LogStream << m_ulIter << ": nPoly = " << nPoly << " texture = " << strTexture << " dToDepositHere = " << dToDepositHere << " at [" << nX << "][" << nY << "] nCoastPoint = " << nCoastPoint << " nSeawardFromCoast = " << nSeawardFromCoast << endl;
1200 }
1201 }
1202 }
1203
1204 // if (dDepositedOnPoly > dTargetToDepositOnPoly)
1205 // {
1206 // // LogStream << "££££££ 3 nPoly = " << nPoly << " texture = " << strTexture << " dDepositedOnPoly = " << dDepositedOnPoly << " dTargetToDepositOnPoly = " << dTargetToDepositOnPoly << endl;
1207 // }
1208
1209 if (bDeposited)
1210 {
1211 // Update the cell's layer elevations
1212 m_pRasterGrid->m_Cell[nX][nY].CalcAllLayerElevsAndD50();
1213
1214 // Update the cell's sea depth
1215 m_pRasterGrid->m_Cell[nX][nY].SetSeaDepth();
1216
1217 // And set the landform category
1218 int const nCat = pLandform->nGetLFCategory();
1219
1222
1223 // Update this-timestep totals
1225
1226 if (nTexture == TEXTURE_SAND)
1227 m_dThisIterBeachDepositionSand += dToDepositHere;
1228
1229 else if (nTexture == TEXTURE_COARSE)
1230 m_dThisIterBeachDepositionCoarse += dToDepositHere;
1231 }
1232 }
1233
1234 else if (bElevAboveDeanElev(nX, nY, dElevDiff, pLandform))
1235 {
1236 // The current elevation is higher than the Dean elevation, so we have potential beach erosion (i.e. not constrained by availability of unconsolidated sediment) here
1238
1239 m_pRasterGrid->m_Cell[nX][nY].SetPotentialBeachErosion(-dElevDiff);
1240
1241 // LogStream << m_ulIter << ": nPoly = " << nPoly << " texture = " << strTexture << " going DOWN-COAST, potential beach erosion = " << -dElevDiff << " at [" << nX << "][" << nY << "] nCoastPoint = " << nCoastPoint << " nSeawardFromCoast = " << nSeawardFromCoast << " dThisElevNow = " << dThisElevNow << " Dean Elev = " << VdParProfileDeanElev[nSeawardFromCoast] << endl;
1242
1243 // Now get the number of the highest layer with non-zero thickness
1244 int const nThisLayer = m_pRasterGrid->m_Cell[nX][nY].nGetTopNonZeroLayerAboveBasement();
1245
1246 // Safety check
1247 if (nThisLayer == INT_NODATA)
1248 return RTN_ERR_NO_TOP_LAYER;
1249
1250 if (nThisLayer != NO_NONZERO_THICKNESS_LAYERS)
1251 {
1252 // We still have at least one layer left with non-zero thickness (i.e. we are not down to basement), and the cell's current elevation is higher than the Dean equilibrium profile elevation. So do some beach erosion on this cell (Note: we are in nDoUnconsDepositionOnPolygon() still)
1253 if (nTexture == TEXTURE_SAND)
1254 {
1255 double dSandRemoved = 0;
1256 ErodeCellBeachSedimentSupplyLimited(nX, nY, nThisLayer, TEXTURE_SAND, -dElevDiff, dSandRemoved);
1257
1258 // Update totals for this parallel profile
1259 dDepositedOnProfile -= dSandRemoved;
1260 dStillToDepositOnProfile += dSandRemoved;
1261
1262 // Update totals for the polygon (note that these may become slightly -ve if erosion occurs early during this routine, but this is not a problem since the values will eventually become +ve again
1263 dDepositedOnPoly -= dSandRemoved;
1264 dStillToDepositOnPoly += dSandRemoved;
1265
1266 // if (dDepositedOnPoly < 0)
1267 // LogStream << m_ulIter << ": BBB LESS THAN ZERO dDepositedOnPoly = " << dDepositedOnPoly << endl;
1268
1269 // Update this-timestep totals
1271
1272 // // DEBUG CODE ==================================================================================================
1273 // LogStream << m_ulIter << ": $$$$$$$$$ BEACH 1 Dean profile lower than existing profile, SAND depth eroded on [" << nX << "][" << nY << "] in Poly " << nPoly << " is " << dSandRemoved * m_dCellArea << endl;
1274 // // DEBUG CODE ==================================================================================================
1275
1276 // Store the this-polygon depth of sand sediment eroded during Dean profile deposition of beach unconsolidated sediment
1277 pPolygon->AddBeachSandErodedDeanProfile(dSandRemoved);
1278 }
1279
1280 else if (nTexture == TEXTURE_COARSE)
1281 {
1282 double dCoarseRemoved = 0;
1283 ErodeCellBeachSedimentSupplyLimited(nX, nY, nThisLayer, TEXTURE_COARSE, -dElevDiff, dCoarseRemoved);
1284
1285 // Update totals for this parallel profile
1286 dDepositedOnProfile -= dCoarseRemoved;
1287 dStillToDepositOnProfile += dCoarseRemoved;
1288
1289 // Update totals for the polygon (note that these may become slightly -ve if erosion occurs early during this routine, but this is not a problem since the values will eventually become +ve again
1290 dDepositedOnPoly -= dCoarseRemoved;
1291 dStillToDepositOnPoly += dCoarseRemoved;
1292
1293 // Update this-timestep totals
1295
1296 // // DEBUG CODE ==================================================================================================
1297 // LogStream << m_ulIter << ": $$$$$$$$$ BEACH 1 Dean profile lower than existing profile, COARSE depth eroded on [" << nX << "][" << nY << "] in Poly " << nPoly << " is " << dCoarseRemoved * m_dCellArea << endl;
1298 // // DEBUG CODE ==================================================================================================
1299
1300 // Store the this-polygon depth of coarse sediment eroded during Dean profile deposition of beach unconsolidated sediment
1301 pPolygon->AddBeachCoarseErodedDeanProfile(dCoarseRemoved);
1302 }
1303 }
1304
1305 // if (dDepositedOnPoly > dTargetToDepositOnPoly)
1306 // {
1307 // LogStream << "££££££ 4 nPoly = " << nPoly << " texture = " << strTexture << " dDepositedOnPoly = " << dDepositedOnPoly << " dTargetToDepositOnPoly = " << dTargetToDepositOnPoly << endl;
1308 // }
1309
1310 // LogStream << m_ulIter << ": in polygon " << nPoly << " have net deposition for " << strTexture << ", actual beach erosion = " << dSand + dCoarse << " at [" << nX << "][" << nY << "]" << endl;
1311 }
1312 }
1313 }
1314
1315 // LogStream << m_ulIter << ": nPoly = " << nPoly << " texture = " << strTexture << " nCoastPoint = " << nCoastPoint << " nSeawardOffset = " << nSeawardOffset << " dTargetStillToDepositOnProfile = " << dTargetStillToDepositOnProfile << endl;
1316 }
1317
1318 // Have we deposited enough?
1319 if (dTargetToDepositOnPoly > 0)
1320 {
1321 // LogStream << "##### texture = " << strTexture << " dDepositedOnPoly = " << dDepositedOnPoly << " dTargetToDepositOnPoly = " << dTargetToDepositOnPoly << " Not enough deposited, so now going UP-COAST" << endl;
1322 // No, so do the same in an UP-COAST (i.e. decreasing coastpoint indices) direction
1323 // UP-COAST (decreasing coastpoint indices) ==================================================================================
1324
1325 // Start by finding the seaward end point of the down-coast part-profile, as before we are using only part of each profile, seaward as far as the depth of closure
1326 // CGeom2DIPoint PtiDownCoastPartProfileSeawardEnd;
1327 // int nIndex1 = pDownCoastProfile->nGetCellGivenDepth(m_pRasterGrid, m_dDepthOfClosure, &PtiDownCoastPartProfileSeawardEnd);
1328 int const nIndex1 = pDownCoastProfile->nGetCellGivenDepth(m_pRasterGrid, m_dDepthOfClosure);
1329
1330 if (nIndex1 == INT_NODATA)
1331 {
1332 LogStream << m_ulIter << ": " << ERR << "while depositing beach for coast " << nCoast << " polygon " << pPolygon->nGetCoastID() << ", could not find the seaward end point of the down-coast profile (" << nUpCoastProfile << ") for depth of closure = " << m_dDepthOfClosure << endl;
1333
1335 }
1336
1337 // The part-profile length is one greater than nIndex1, since pPtiGetCellGivenDepth() returns the index of the cell at depth of closure. This will be the number of cells in the Dean profile portion of every parallel profile
1338 int const nDownCoastDeanLen = nIndex1 + 1;
1339
1340 // assert(bIsWithinValidGrid(&PtiDownCoastPartProfileSeawardEnd));
1341
1342 // Get the distance between the start and end of the part-profile (the Dean length), in external CRS units
1343 // CGeom2DPoint
1344 // PtDownCoastProfileStart = *pDownCoastProfile->pPtGetPointInProfile(0),
1345 // PtDownCoastProfileEnd = PtGridCentroidToExt(&PtiDownCoastPartProfileSeawardEnd);
1346
1347 // double dDownCoastDeanLen = dGetDistanceBetween(&PtDownCoastProfileStart, &PtDownCoastProfileEnd);
1348
1349 int const nXDownCoastProfileExistingCoastPoint = m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(nDownCoastProfileCoastPoint)->nGetX();
1350 int const nYDownCoastProfileExistingCoastPoint = m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(nDownCoastProfileCoastPoint)->nGetY();
1351
1352 // int nCoastSegLen;
1353
1354 // Store the coast point numbers for this polygon so that we can shuffle them
1355 nVCoastPoint.resize(0);
1356
1357 if (nUpCoastProfileCoastPoint == 0)
1358 {
1359 // This is the final up-coast polygon, so also include the up-coast polygon boundary
1360 nCoastSegLen = nDownCoastProfileCoastPoint - nUpCoastProfileCoastPoint + 1;
1361
1362 for (int nCoastPoint = nUpCoastProfileCoastPoint; nCoastPoint <= nDownCoastProfileCoastPoint; nCoastPoint++)
1363 nVCoastPoint.push_back(nCoastPoint);
1364 }
1365
1366 else
1367 {
1368 // This is not the final down-coast polygon, so do not include the polygon's down-coast boundary
1369 nCoastSegLen = nDownCoastProfileCoastPoint - nUpCoastProfileCoastPoint;
1370
1371 for (int nCoastPoint = nUpCoastProfileCoastPoint; nCoastPoint < nDownCoastProfileCoastPoint; nCoastPoint++)
1372 nVCoastPoint.push_back(nCoastPoint);
1373 }
1374
1375 // Shuffle the coast points, this is necessary so that leaving the loop does not create sequence-related artefacts
1376 shuffle(nVCoastPoint.begin(), nVCoastPoint.begin() + nCoastSegLen, m_Rand[1]);
1377
1378 // Recalc the targets for deposition per profile
1379 dTargetToDepositOnProfile = dStillToDepositOnPoly / nCoastSegLen;
1380
1381 // Set a switch
1382 bool bEnoughDepositedOnPolygon = false;
1383
1384 // Now traverse the polygon's existing coastline in a random (but broadly UP-COAST, i.e. decreasing coastpoint indices) sequence, fitting a Dean profile at each coast point
1385 for (int n = 0; n < nCoastSegLen; n++)
1386 {
1387 // Check the switch
1388 if (bEnoughDepositedOnPolygon)
1389 break;
1390
1391 // Pick a random coast point
1392 int const nCoastPoint = nVCoastPoint[n];
1393 CGeom2DIPoint const PtiCoastPoint = *m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(nCoastPoint);
1394 int const nCoastX = PtiCoastPoint.nGetX();
1395 int const nCoastY = PtiCoastPoint.nGetY();
1396
1397 // Calculate the x-y offset between this coast point, and the coast point of the down-coast normal
1398 int const nXOffset = nCoastX - nXDownCoastProfileExistingCoastPoint;
1399 int const nYOffset = nCoastY - nYDownCoastProfileExistingCoastPoint;
1400 int nSeawardOffset = -1;
1401 // nParProfLen;
1402 vector<CGeom2DIPoint> PtiVParProfile;
1403 vector<double> VdParProfileDeanElev;
1404
1405 // OK, loop until we can deposit sufficient unconsolidated sediment
1406 while (true)
1407 {
1408 // Move seaward by one cell
1409 nSeawardOffset++;
1410
1411 // And lengthen the parallel profile
1412 int nParProfLen = nDownCoastDeanLen + nSeawardOffset;
1413
1414 if (nParProfLen > (pDownCoastProfile->nGetNumCellsInProfile()))
1415 {
1416 // We've reached the seaward end of the down-coast profile, need to quit
1417 // if (m_nLogFileDetail >= LOG_FILE_MIDDLE_DETAIL)
1418 // LogStream << m_ulIter << ": " << WARN << "reached seaward end of down-coast profile during UP-COAST deposition of unconsolidated sediment for coast " << nCoast << " polygon " << nPoly << " (nCoastPoint = " << nCoastPoint << " nSeawardOffset = " << nSeawardOffset << ")" << endl;
1419
1420 break;
1421 }
1422
1423 // Get the x-y coords of a profile starting from this coast point and parallel to the down-coast polygon boundary profile (these are in natural sequence, like the boundary part-profile)
1424 PtiVParProfile.resize(0);
1425
1426 for (int m = 0; m < nParProfLen; m++)
1427 {
1428 CGeom2DIPoint const PtiProf = *pDownCoastProfile->pPtiGetCellInProfile(m);
1429 CGeom2DIPoint const PtiTmp(PtiProf.nGetX() + nXOffset, PtiProf.nGetY() + nYOffset);
1430 PtiVParProfile.push_back(PtiTmp);
1431 }
1432
1433 // Get the existing elevation of the seaward end of the parallel profile
1434 int nSeaEndX = PtiVParProfile.back().nGetX();
1435 int nSeaEndY = PtiVParProfile.back().nGetY();
1436
1437 // Safety check
1438 if (!bIsWithinValidGrid(nSeaEndX, nSeaEndY))
1439 {
1440 // LogStream << WARN << "12 @@@@ while doing UP-COAST deposition on polygon " << nPoly << ", hit edge of grid at [" << nSeaEndX << "][" << nSeaEndY << "] for parallel profile from coast point " << nCoastPoint << " at [" << nCoastX << "][" << nCoastY << "]. Constraining this parallel profile at its seaward end" << endl;
1441
1442 KeepWithinValidGrid(nCoastX, nCoastY, nSeaEndX, nSeaEndY);
1443 PtiVParProfile.back().SetX(nSeaEndX);
1444 PtiVParProfile.back().SetY(nSeaEndY);
1445 }
1446
1447 double const dParProfEndElev = m_pRasterGrid->m_Cell[nSeaEndX][nSeaEndY].dGetSedimentTopElev();
1448
1449 // Set the start elevation for the Dean profile just a bit above mean SWL for this timestep (i.e. so that it is a Bruun profile)
1450 double const dParProfStartElev = m_dThisIterMeanSWL + m_dDeanProfileStartAboveSWL;
1451
1452 // Calculate the total length of the parallel profile, including any seaward offset
1453 double const dParProfLen = dGetDistanceBetween(&PtiVParProfile.front(), &PtiVParProfile.back());
1454
1455 // Now calculate the length of the Dean profile-only part i.e. without any seaward offset. The approach used here is approximate but probably OK
1456 double dParProfDeanLen = dParProfLen - (nSeawardOffset * m_dCellSide);
1457
1458 // Safety check
1459 if (dParProfDeanLen <= 0)
1460 dParProfDeanLen = 1;
1461
1462 // Solve for dA so that the existing elevations at the end of the parallel profile, and at the end of a Dean equilibrium profile on that part-normal, are the same
1463 double const dParProfA = (dParProfStartElev - dParProfEndElev) / pow(dParProfDeanLen, DEAN_POWER);
1464
1465 nParProfLen = static_cast<int>(PtiVParProfile.size());
1466 VdParProfileDeanElev.resize(nParProfLen, 0);
1467
1468 double const dInc = dParProfDeanLen / (nParProfLen - nSeawardOffset - 2);
1469
1470 // The elevation of the coast point in the Dean profile is the same as the elevation of the current coast point TODO 020 Is this correct? Should it be dParProfStartElev?
1471 double const dCoastElev = m_pRasterGrid->m_Cell[nCoastX][nCoastY].dGetSedimentTopElev();
1472
1473 // For this depositing parallel profile, calculate the Dean equilibrium profile of the unconsolidated sediment h(y) = A * y^(2/3) where h(y) is the distance below the highest point in the profile at a distance y from the landward start of the profile
1474 CalcDeanProfile(&VdParProfileDeanElev, dInc, dParProfStartElev, dParProfA, true, nSeawardOffset, dCoastElev);
1475
1476 double dParProfTotDiff = 0;
1477
1478 for (int m = 0; m < nParProfLen; m++)
1479 {
1480 CGeom2DIPoint PtiTmp = PtiVParProfile[m];
1481 int nX = PtiTmp.nGetX();
1482 int nY = PtiTmp.nGetY();
1483
1484 // Safety check
1485 if (!bIsWithinValidGrid(nX, nY))
1486 {
1487 // LogStream << WARN << "13 @@@@ while constructing parallel profile for UP-COAST deposition on polygon " << nPoly << ", hit edge of grid at [" << nX << "][" << nY << "] for parallel profile from coast point " << nCoastPoint << " at [" << nCoastX << "][" << nCoastY << "]. Constraining this parallel profile at its seaward end" << endl;
1488
1489 KeepWithinValidGrid(nCoastX, nCoastY, nX, nY);
1490 PtiTmp.SetX(nX);
1491 PtiTmp.SetY(nY);
1492 }
1493
1494 // Don't do anything to intervention cells
1495 if (bIsInterventionCell(nX, nY))
1496 continue;
1497
1498 // Don't do cells twice
1499 if (!m_pRasterGrid->m_Cell[nX][nY].bBeachErosionOrDepositionThisIter())
1500 {
1501 double const dTmpElev = m_pRasterGrid->m_Cell[nX][nY].dGetSedimentTopElev();
1502 double const dDiff = VdParProfileDeanElev[m] - dTmpElev;
1503
1504 dParProfTotDiff += dDiff;
1505 }
1506 }
1507
1508 // // DEBUG CODE -----------------------------------------------------
1509 // LogStream << endl << "\tFor polygon " << nPoly << " doing UP-COAST deposition, nSeawardOffset = " << nSeawardOffset << ", parallel profile from [" << PtiVParProfile[0].nGetX() << "][" << PtiVParProfile[0].nGetY() << "] to [" << PtiVParProfile.back().nGetX() << "][" << PtiVParProfile.back().nGetY() << "], nDownCoastDeanLen = " << nDownCoastDeanLen << " dDownCoastDeanLen = " << dDownCoastDeanLen << " nParProfLen = " << nParProfLen << " dParProfDeanLen = " << dParProfDeanLen << " dInc = " << dInc << " dParProfStartElev = " << dParProfStartElev << " dParProfEndElev = " << dParProfEndElev << " dParProfA = " << dParProfA << endl;
1510 //
1511 // LogStream << "\tExisting profile for deposition = ";
1512 // for (int n = 0; n < nParProfLen; n++)
1513 // {
1514 // CGeom2DIPoint PtiTmp = PtiVParProfile[n];
1515 // int
1516 // nX = PtiTmp.nGetX(),
1517 // nY = PtiTmp.nGetY();
1518 //
1519 // // Safety check
1520 // if (! bIsWithinValidGrid(nX, nY))
1521 // KeepWithinValidGrid(nX, nY);
1522 //
1523 // LogStream << m_pRasterGrid->m_Cell[nX][nY].dGetSedimentTopElev() << " ";
1524 // }
1525 // LogStream << endl;
1526 // LogStream << "\tParallel Dean equilibrium profile for deposition = ";
1527 // for (int n = 0; n < nParProfLen; n++)
1528 // {
1529 // LogStream << VdParProfileDeanElev[n] << " ";
1530 // }
1531 // LogStream << endl;
1532 //
1533 // LogStream << "\tnCoastPoint = " << nCoastPoint << " nSeawardOffset = " << nSeawardOffset << " difference = ";
1534 // for (int n = 0; n < nParProfLen; n++)
1535 // {
1536 // CGeom2DIPoint PtiTmp = PtiVParProfile[n];
1537 // int
1538 // nX = PtiTmp.nGetX(),
1539 // nY = PtiTmp.nGetY();
1540 //
1541 // // Safety check
1542 // if (! bIsWithinValidGrid(nX, nY))
1543 // KeepWithinValidGrid(nX, nY);
1544 //
1545 // double
1546 // dTmpElev = m_pRasterGrid->m_Cell[nX][nY].dGetSedimentTopElev(),
1547 // dDiff = VdParProfileDeanElev[n] - dTmpElev;
1548 //
1549 // LogStream << dDiff << " ";
1550 // }
1551 // LogStream << endl;
1552 // // END DEBUG CODE -----------------------------------------------------
1553
1554 // So will we be able to deposit as much as is needed?
1555 if (dParProfTotDiff >= dTargetToDepositOnProfile)
1556 {
1557 // LogStream << " UP-COAST nCoastPoint = " << nCoastPoint << " nSeawardOffset = " << nSeawardOffset << " dParProfTotDiff = " << dParProfTotDiff << " dTargetToDepositOnProfile = " << dTargetToDepositOnProfile << " WILL BE ABLE TO DEPOSIT ENOUGH" << endl;
1558
1559 break;
1560 }
1561 }
1562
1563 // assert(dParProfTotDiff > 0);
1564
1565 // OK, this value of nSeawardOffset gives us enough deposition. So start depositing on the parallel profile from the coastward end
1566 double dDepositedOnProfile = 0; // Total for this parallel profile
1567
1568 dStillToDepositOnProfile = dTargetToDepositOnProfile;
1569
1570 for (unsigned int nSeawardFromCoast = 0; nSeawardFromCoast < PtiVParProfile.size(); nSeawardFromCoast++)
1571 {
1572 // Move along this parallel profile starting from the coast. Leave the loop if we have deposited enough on this polygon
1573 if (dStillToDepositOnPoly < SEDIMENT_ELEV_TOLERANCE)
1574 {
1575 // LogStream << m_ulIter << ": nPoly = " << nPoly << " texture = " << strTexture << " UP-COAST nCoastPoint = " << nCoastPoint << " nSeawardOffset = " << nSeawardOffset << " leaving loop because enough deposited on polygon, dTargetToDepositOnPoly = " << dTargetToDepositOnPoly << " dDepositedOnPoly = " << dDepositedOnPoly << endl;
1576
1577 bEnoughDepositedOnPolygon = true;
1578
1579 break;
1580 }
1581
1582 // Leave the loop if we have deposited enough on this parallel profile
1583 if (dStillToDepositOnProfile < SEDIMENT_ELEV_TOLERANCE)
1584 {
1585 // LogStream << m_ulIter << ": nPoly = " << nPoly << " texture = " << strTexture << " UP-COAST nCoastPoint = " << nCoastPoint << " nSeawardOffset = " << nSeawardOffset << " leaving loop because enough deposited on parallel profile, dTargetStillToDepositOnProfile = " << dTargetStillToDepositOnProfile << " dDepositedOnProfile = " << dDepositedOnProfile << endl;
1586
1587 break;
1588 }
1589
1590 // assert(nSeawardFromCoast < PtiVParProfile.size());
1591 CGeom2DIPoint PtiTmp = PtiVParProfile[nSeawardFromCoast];
1592 int nX = PtiTmp.nGetX();
1593 int nY = PtiTmp.nGetY();
1594
1595 // Safety check
1596 if (!bIsWithinValidGrid(nX, nY))
1597 {
1598 // LogStream << WARN << "14 @@@@ while constructing parallel profile for UP-COAST deposition on polygon " << nPoly << ", hit edge of grid at [" << nX << "][" << nY << "] for parallel profile from coast point " << nCoastPoint << " at [" << nCoastX << "][" << nCoastY << "]. Constraining this parallel profile at its seaward end" << endl;
1599
1600 KeepWithinValidGrid(nCoastX, nCoastY, nX, nY);
1601 PtiTmp.SetX(nX);
1602 PtiTmp.SetY(nY);
1603 }
1604
1605 // Don't do anything to intervention cells
1606 if (bIsInterventionCell(nX, nY))
1607 continue;
1608
1609 // Don't do cells twice
1610 if (!m_pRasterGrid->m_Cell[nX][nY].bBeachErosionOrDepositionThisIter())
1611 {
1612 // Get this cell's current elevation
1613 double const dThisElevNow = m_pRasterGrid->m_Cell[nX][nY].dGetSedimentTopElev();
1614
1615 // LogStream << "\tnPoly = " << nPoly << " going UP-COAST, [" << nX << "][" << nY << "] nCoastPoint = " << nCoastPoint << " nSeawardFromCoast = " << nSeawardFromCoast << " dThisElevNow = " << dThisElevNow << " Dean Elev = " << VdParProfileDeanElev[nSeawardFromCoast] << endl;
1616
1617 // Subtract the two elevations
1618 double const dElevDiff = VdParProfileDeanElev[nSeawardFromCoast] - dThisElevNow;
1619 CRWCellLandform* pLandform = m_pRasterGrid->m_Cell[nX][nY].pGetLandform();
1620
1621 if (dElevDiff > SEDIMENT_ELEV_TOLERANCE)
1622 {
1623 bool bDeposited = false;
1624 double dToDepositHere = 0;
1625
1626 // The current elevation is below the Dean elevation, so we have can have beach deposition here
1627 if (dStillToDepositOnProfile > SEDIMENT_ELEV_TOLERANCE)
1628 {
1629 dToDepositHere = tMin(dElevDiff, dStillToDepositOnProfile, dStillToDepositOnPoly);
1630
1631 // LogStream << " UP-COAST nPoly = " << nPoly << " nCoastPoint = " << nCoastPoint << " texture = " << strTexture << " dToDepositHere = " << dToDepositHere << endl;
1632
1633 int const nTopLayer = m_pRasterGrid->m_Cell[nX][nY].nGetTopLayerAboveBasement();
1634
1635 // Safety check
1636 if (nTopLayer == INT_NODATA)
1637 return RTN_ERR_NO_TOP_LAYER;
1638
1639 if (dToDepositHere > SEDIMENT_ELEV_TOLERANCE)
1640 {
1641 bDeposited = true;
1642
1643 if (nTexture == TEXTURE_SAND)
1644 {
1645 double const dSandNow = m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nTopLayer)->pGetUnconsolidatedSediment()->dGetSandDepth();
1646
1647 m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nTopLayer)->pGetUnconsolidatedSediment()->SetSandDepth(dSandNow + dToDepositHere);
1648
1649 // Set the changed-this-timestep switch
1650 m_bUnconsChangedThisIter[nTopLayer] = true;
1651
1652 dDepositedOnProfile += dToDepositHere;
1653 dDepositedOnPoly += dToDepositHere;
1654
1655 // LogStream << "XXXXXXX texture = " << strTexture << " dDepositedOnProfile = " << dDepositedOnProfile << " dDepositedOnPoly = " << dDepositedOnPoly << endl;
1656
1657 // Update the cell's beach deposition, and total beach deposition, values
1658 m_pRasterGrid->m_Cell[nX][nY].IncrBeachDeposition(dToDepositHere);
1659
1660 dStillToDepositOnPoly -= dToDepositHere;
1661 dStillToDepositOnProfile -= dToDepositHere;
1662
1663 // if (dDepositedOnPoly > dTargetToDepositOnPoly)
1664 // {
1665 // // LogStream << "££££££ 5 nPoly = " << nPoly << " nCoastPoint = " << nCoastPoint << " dDepositedOnProfile = " << dDepositedOnProfile << " dDepositedOnPoly = " << dDepositedOnPoly << " dTargetToDepositOnPoly = " << dTargetToDepositOnPoly << endl;
1666 // }
1667
1668 // LogStream << m_ulIter << ": nPoly = " << nPoly << " texture = " << strTexture << " dToDepositHere = " << dToDepositHere << " at [" << nX << "][" << nY << "] = {" << dGridCentroidXToExtCRSX(nX) << ", " << dGridCentroidYToExtCRSY(nY) << "} nCoastPoint = " << nCoastPoint << " nSeawardFromCoast = " << nSeawardFromCoast << endl;
1669 }
1670
1671 else if (nTexture == TEXTURE_COARSE)
1672 {
1673 double const dCoarseNow = m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nTopLayer)->pGetUnconsolidatedSediment()->dGetCoarseDepth();
1674
1675 m_pRasterGrid->m_Cell[nX][nY].pGetLayerAboveBasement(nTopLayer)->pGetUnconsolidatedSediment()->SetCoarseDepth(dCoarseNow + dToDepositHere);
1676
1677 // Set the changed-this-timestep switch
1678 m_bUnconsChangedThisIter[nTopLayer] = true;
1679
1680 if (dDepositedOnPoly > dTargetToDepositOnPoly)
1681 {
1682 // LogStream << "££££££ 6 nPoly = " << nPoly << " dDepositedOnPoly = " << dDepositedOnPoly << " dTargetToDepositOnPoly = " << dTargetToDepositOnPoly << endl;
1683 }
1684
1685 dDepositedOnProfile += dToDepositHere;
1686 dDepositedOnPoly += dToDepositHere;
1687
1688 // LogStream << "XXXXXXX texture = " << strTexture << " dDepositedOnProfile = " << dDepositedOnProfile << " dDepositedOnPoly = " << dDepositedOnPoly << endl;
1689
1690 // Update the cell's beach deposition, and total beach deposition, values
1691 m_pRasterGrid->m_Cell[nX][nY].IncrBeachDeposition(dToDepositHere);
1692
1693 dStillToDepositOnPoly -= dToDepositHere;
1694 dStillToDepositOnProfile -= dToDepositHere;
1695
1696 // LogStream << m_ulIter << ": nPoly = " << nPoly << " texture = " << strTexture << " dToDepositHere = " << dToDepositHere << " at [" << nX << "][" << nY << "] nCoastPoint = " << nCoastPoint << " nSeawardFromCoast = " << nSeawardFromCoast << endl;
1697 }
1698 }
1699 }
1700
1701 if (bDeposited)
1702 {
1703 // Now update the cell's layer elevations
1704 m_pRasterGrid->m_Cell[nX][nY].CalcAllLayerElevsAndD50();
1705
1706 // Update the cell's sea depth
1707 m_pRasterGrid->m_Cell[nX][nY].SetSeaDepth();
1708
1709 int const nCat = pLandform->nGetLFCategory();
1710
1713
1714 // Update this-timestep totals
1716
1717 if (nTexture == TEXTURE_SAND)
1718 m_dThisIterBeachDepositionSand += dToDepositHere;
1719
1720 else if (nTexture == TEXTURE_COARSE)
1721 m_dThisIterBeachDepositionCoarse += dToDepositHere;
1722 }
1723 }
1724
1725 else if (bElevAboveDeanElev(nX, nY, dElevDiff, pLandform))
1726 {
1727 // The current elevation is higher than the Dean elevation, so we could have beach erosion here
1729
1730 m_pRasterGrid->m_Cell[nX][nY].SetPotentialBeachErosion(-dElevDiff);
1731
1732 // LogStream << m_ulIter << ": nPoly = " << nPoly << " texture = " << strTexture << " going UP-COAST, potential beach erosion = " << -dElevDiff << " at [" << nX << "][" << nY << "] nCoastPoint = " << nCoastPoint << " nSeawardFromCoast = " << nSeawardFromCoast << " dThisElevNow = " << dThisElevNow << " Dean Elev = " << VdParProfileDeanElev[nSeawardFromCoast] << endl;
1733
1734 // Now get the number of the highest layer with non-zero thickness
1735 int const nThisLayer = m_pRasterGrid->m_Cell[nX][nY].nGetTopNonZeroLayerAboveBasement();
1736
1737 // Safety check
1738 if (nThisLayer == INT_NODATA)
1739 return RTN_ERR_NO_TOP_LAYER;
1740
1741 if (nThisLayer != NO_NONZERO_THICKNESS_LAYERS)
1742 {
1743 // We still have at least one layer left with non-zero thickness (i.e. we are not down to basement), and the cell's current elevation is higher than the Dean equilibrium profile elevation. So do some beach erosion on this cell (Note: we are in nDoUnconsDepositionOnPolygon() still)
1744 if (nTexture == TEXTURE_SAND)
1745 {
1746 double dSandRemoved = 0;
1747 ErodeCellBeachSedimentSupplyLimited(nX, nY, nThisLayer, TEXTURE_SAND, -dElevDiff, dSandRemoved);
1748
1749 // Update total for this parallel profile
1750 dDepositedOnProfile -= dSandRemoved;
1751 dStillToDepositOnProfile += dSandRemoved;
1752
1753 // Update totals for the polygon (note that these may become slightly -ve if erosion occurs early during this routine, but this is not a problem since the values will eventually become +ve again
1754 dDepositedOnPoly -= dSandRemoved;
1755 dStillToDepositOnPoly += dSandRemoved;
1756
1757 // if (dDepositedOnPoly < 0)
1758 // LogStream << m_ulIter << ": AAA LESS THAN ZERO dDepositedOnPoly = " << dDepositedOnPoly << endl;
1759
1760 // Update this-timestep totals
1762
1763 // // DEBUG CODE ==============================================================================================
1764 // LogStream << m_ulIter << ": $$$$$$$$$ BEACH 3 Dean profile lower than existing profile, SAND depth eroded on [" << nX << "][" << nY << "] in Poly " << nPoly << " is " << dSandRemoved * m_dCellArea << endl;
1765 // // DEBUG CODE ==============================================================================================
1766
1767 // Store the this-polygon depth of sand sediment eroded during Dean profile deposition of beach unconsolidated sediment
1768 pPolygon->AddBeachSandErodedDeanProfile(dSandRemoved);
1769 }
1770
1771 else if (nTexture == TEXTURE_COARSE)
1772 {
1773 double dCoarseRemoved = 0;
1774 ErodeCellBeachSedimentSupplyLimited(nX, nY, nThisLayer, TEXTURE_COARSE, -dElevDiff, dCoarseRemoved);
1775
1776 // Update total for this parallel profile
1777 dDepositedOnProfile -= dCoarseRemoved;
1778 dStillToDepositOnProfile += dCoarseRemoved;
1779
1780 // Update totals for the polygon (note that these may become slightly -ve if erosion occurs early during this routine, but this is not a problem since the values will eventually become +ve again
1781 dDepositedOnPoly -= dCoarseRemoved;
1782 dStillToDepositOnPoly += dCoarseRemoved;
1783
1784 // Update this-timestep totals
1786
1787 // // DEBUG CODE ==============================================================================================
1788 // LogStream << m_ulIter << ": $$$$$$$$$ BEACH 3 Dean profile lower than existing profile, COARSE depth eroded on [" << nX << "][" << nY << "] in Poly " << nPoly << " is " << dCoarseRemoved * m_dCellArea << endl;
1789 // // DEBUG CODE ==============================================================================================
1790
1791 // Store the this-polygon depth of coarse sediment eroded during Dean profile deposition of beach unconsolidated sediment
1792 pPolygon->AddBeachCoarseErodedDeanProfile(dCoarseRemoved);
1793 }
1794 }
1795
1796 // if (dDepositedOnPoly > dTargetToDepositOnPoly)
1797 // {
1798 // // LogStream << "££££££ 4 nPoly = " << nPoly << " texture = " << strTexture << " dDepositedOnPoly = " << dDepositedOnPoly << " dTargetToDepositOnPoly = " << dTargetToDepositOnPoly << endl;
1799 // }
1800
1801 // LogStream << m_ulIter << ": in polygon " << nPoly << " have net deposition for " << strTexture << ", actual beach erosion = " << dSand + dCoarse << " at [" << nX << "][" << nY << "]" << endl;
1802 }
1803 }
1804 }
1805 }
1806 }
1807
1808 // Store amounts deposited on this polygon
1809 if (nTexture == TEXTURE_SAND)
1810 {
1811 pPolygon->SetBeachDepositionUnconsSand(dDepositedOnPoly);
1812
1813 // Check mass balance for sand deposited
1815 if (!bFPIsEqual(pPolygon->dGetToDoBeachDepositionUnconsSand(), dDepositedOnPoly, MASS_BALANCE_TOLERANCE))
1816 LogStream << m_ulIter << ": polygon " << pPolygon->nGetCoastID() << " NOT equal SAND dGetToDoBeachDepositionUnconsSand() = " << pPolygon->dGetToDoBeachDepositionUnconsSand() << " dDepositedOnPoly = " << dDepositedOnPoly << endl;
1817
1819 }
1820
1821 else if (nTexture == TEXTURE_COARSE)
1822 {
1823 pPolygon->SetBeachDepositionUnconsCoarse(dDepositedOnPoly);
1824
1825 // Check mass balance for coarse deposited
1827 if (!bFPIsEqual(pPolygon->dGetToDoBeachDepositionUnconsCoarse(), dDepositedOnPoly, MASS_BALANCE_TOLERANCE))
1828 LogStream << m_ulIter << ": polygon " << pPolygon->nGetCoastID() << " NOT equal COARSE dGetToDoBeachDepositionUnconsCoarse() = " << pPolygon->dGetToDoBeachDepositionUnconsCoarse() << " dDepositedOnPoly = " << dDepositedOnPoly << endl;
1829
1831 }
1832
1833 // // DEBUG CODE #####################
1834 // if (m_ulIter == 5)
1835 // {
1836 // LogStream << m_ulIter << ": leaving nDoUnconsDepositionOnPolygon() nCoast = " << nCoast << " nPoly = " << nPoly << " strTexture = " << strTexture << " dTargetToDepositOnPoly = " << dTargetToDepositOnPoly * m_dCellArea << " dDepositedOnPoly = " << dDepositedOnPoly * m_dCellArea << endl;
1837 //
1838 // double dTmpSandUncons = 0;
1839 // for (int nX1 = 0; nX1 < m_nXGridSize; nX1++)
1840 // {
1841 // for (int nY1 = 0; nY1 < m_nYGridSize; nY1++)
1842 // {
1843 // dTmpSandUncons += m_pRasterGrid->m_Cell[nX1][nY1].dGetTotUnconsSand();
1844 // }
1845 // }
1846 //
1847 // LogStream << m_ulIter << ": leaving nDoUnconsDepositionOnPolygon() for nPoly = " << nPoly << " TOTAL UNCONSOLIDATED SAND ON ALL CELLS = " << dTmpSandUncons * m_dCellArea << endl;
1848 // }
1849 // // DEBUG CODE #####################
1850
1851 return RTN_OK;
1852}
1853
1854//===============================================================================================================================
1856//===============================================================================================================================
1857bool CSimulation::bElevAboveDeanElev(int const nX, int const nY, double const dElevDiff, CRWCellLandform const* pLandform)
1858{
1859 // TODO 075 What if it is bedrock that sticks above Dean profile?
1860 if (dElevDiff <= 0)
1861 {
1862 if (m_pRasterGrid->m_Cell[nX][nY].bIsInContiguousSea())
1863 return true;
1864
1865 int const nCat = pLandform->nGetLFCategory();
1866
1867 if (nCat == LF_CAT_DRIFT)
1868 return true;
1869
1871 return true;
1872 }
1873
1874 return false;
1875}
Contains CGeom2DPoint definitions.
Contains CGeom2DIPoint definitions.
Geometry class used to represent 2D point objects with integer coordinates.
Definition 2di_point.h:29
void SetY(int const)
The integer parameter sets a value for the CGeom2DIPoint object's Y coordinate.
Definition 2di_point.cpp:79
int nGetY(void) const
Returns the CGeom2DIPoint object's integer Y coordinate.
Definition 2di_point.cpp:55
void SetX(int const)
The integer parameter sets a value for the CGeom2DIPoint object's X coordinate.
Definition 2di_point.cpp:73
int nGetX(void) const
Returns the CGeom2DIPoint object's integer X coordinate.
Definition 2di_point.cpp:49
Geometry class used to represent 2D point objects with floating-point coordinates.
Definition 2d_point.h:27
Geometry class used for coast polygon objects.
void AddBeachCoarseErodedDeanProfile(double const)
Adds a depth (in m) of coarse sediment eroded during beach Dean profile deposition.
void SetBeachDepositionUnconsCoarse(double const)
Sets the depth of coarse-sized unconsolidated sediment deposited on this polygon during this timestep...
void AddBeachSandErodedDeanProfile(double const)
Adds a depth (in m) of sand sediment eroded during beach Dean profile deposition.
void SetZeroToDoDepositionUnconsSand(void)
Re-initializes this timestep's still-to-do deposition of unconsolidated sand sediment (from beach red...
void SetBeachDepositionUnconsSand(double const)
Sets the depth of sand-sized unconsolidated sediment deposited on this polygon during this timestep (...
void SetZeroToDoDepositionUnconsCoarse(void)
Re-initializes this timestep's still-to-do deposition of unconsolidated coarse sediment (from beach r...
int nGetUpCoastProfile(void) const
Return the number of the up-coast profile.
double dGetToDoBeachDepositionUnconsSand(void) const
Returns this timestep's still-to-do deposition of sand-sized unconsolidated sediment (from beach redi...
int nGetDownCoastProfile(void) const
Return the number of the down-coast profile.
int nGetCoastID(void) const
Get the coast ID, this is the same as the down-coast sequence of polygons.
double dGetToDoBeachDepositionUnconsCoarse(void) const
Returns this timestep's still-to-do deposition of coarse unconsolidated sediment (from beach redistri...
Geometry class used to represent coast profile objects.
Definition profile.h:37
int nGetCellGivenDepth(CGeomRasterGrid const *, double const)
Returns the index of the cell on this profile which has a sea depth which is just less than a given d...
Definition profile.cpp:552
int nGetCoastPoint(void) const
Returns the coast point at which the profile starts.
Definition profile.cpp:87
CGeom2DIPoint * pPtiGetCellInProfile(int const)
Returns a single cell in the profile.
Definition profile.cpp:511
int nGetNumCellsInProfile(void) const
Returns the number of cells in the profile.
Definition profile.cpp:525
Real-world class used to represent the landform of a cell.
int nGetLFCategory(void) const
Get the landform category.
void SetLFSubCategory(int const)
Set the both the landform sub-category, and the landform category.
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:574
CGeomRasterGrid * m_pRasterGrid
Pointer to the raster grid object.
ofstream LogStream
vector< CRWCoast > m_VCoast
The coastline objects.
double m_dFineErodibilityNormalized
Relative erodibility of fine unconsolidated beach sediment, normalized.
Definition simulation.h:796
void ErodeCellBeachSedimentSupplyLimited(int const, int const, int const, int const, double const, double &)
Erodes the unconsolidated beach sediment on a single cell, for a single size class,...
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:802
void KeepWithinValidGrid(int &, int &) const
static double dSubtractProfiles(vector< double > const *, vector< double > const *, vector< bool > const *)
Calculate the total elevation difference between every point in two elevation profiles (first profile...
Definition utils.cpp:2597
unsigned long m_ulThisIterNumBeachDepositionCells
The number of grid cells on which beach (unconsolidated sediment) deposition occurs,...
Definition simulation.h:628
double m_dDeanProfileStartAboveSWL
Berm height i.e. height above SWL of start of depositional Dean profile.
Definition simulation.h:961
int nDoUnconsDepositionOnPolygon(int const, CGeomCoastPolygon *, int const, double, double &)
Deposits unconsolidated beach sediment (sand or coarse) on the cells within a polygon....
double m_dSandErodibilityNormalized
Relative erodibility of sand unconsolidated beach sediment, normalized.
Definition simulation.h:799
double m_dThisIterBeachDepositionCoarse
Total beach deposition (coarse unconsolidated sediment) for this iteration (depth in m)
Definition simulation.h:865
bool bElevAboveDeanElev(int const, int const, double const, CRWCellLandform const *)
Return true if the given elevation is higher than the Dean elevation (and other conditions are met),...
unsigned long m_ulThisIterNumActualBeachErosionCells
The number of grid cells on which actual beach (unconsolidated sediment) erosion occurs,...
Definition simulation.h:625
vector< bool > m_bUnconsChangedThisIter
One element per layer: has the consolidated sediment of this layer been changed during this iteration...
default_random_engine m_Rand[NUMBER_OF_RNGS]
The c++11 random number generators.
int nDoUnconsErosionOnPolygon(int const, CGeomCoastPolygon *, int const, double const, double &)
Erodes unconsolidated beach sediment of one texture class on the cells within a polygon....
unsigned long m_ulThisIterNumPotentialBeachErosionCells
The number of grid cells on which potential beach (unconsolidated sediment) erosion occurs,...
Definition simulation.h:622
bool bIsWithinValidGrid(int const, int const) const
int nDoParallelProfileUnconsErosion(CGeomCoastPolygon *, int const, int const, int const, int const, int const, int const, vector< CGeom2DIPoint > const *, vector< double > const *, double &, double &, double &)
This routine erodes unconsolidated beach sediment (either fine, sand, or coarse) on a parallel profil...
double m_dThisIterBeachDepositionSand
Total beach deposition (sand unconsolidated sediment) for this iteration (depth in m)
Definition simulation.h:862
CGeom2DPoint PtGridCentroidToExt(CGeom2DIPoint const *) const
unsigned long m_ulIter
The number of the current iteration (time step)
Definition simulation.h:598
double m_dCellSide
Length of a cell side (in external CRS units)
Definition simulation.h:658
bool bIsInterventionCell(int const, int const) const
Returns true if the cell is an intervention.
Definition utils.cpp:2946
double m_dDepthOfClosure
Depth of closure (in m) TODO 007 can be calculated using Hallermeier, R.J. (1978) or Birkemeier (1985...
Definition simulation.h:817
static void CalcDeanProfile(vector< double > *, double const, double const, double const, bool const, int const, double const)
Calculates a Dean equilibrium profile h(y) = A * y^(2/3) where h(y) is the distance below the highest...
Definition utils.cpp:2556
double m_dThisIterMeanSWL
The mean still water level for this timestep (does not include tidal changes, but includes any long-t...
Definition simulation.h:715
This file contains global definitions for CoastalME.
int const LF_SUBCAT_DRIFT_BEACH
Definition cme.h:554
int const NO_NONZERO_THICKNESS_LAYERS
Definition cme.h:770
int const INT_NODATA
Definition cme.h:476
T tMin(T a, T b)
Definition cme.h:1259
double const TOLERANCE
Definition cme.h:814
int const RTN_ERR_NO_TOP_LAYER
Definition cme.h:741
int const RTN_ERR_NO_SEAWARD_END_OF_PROFILE_2
Definition cme.h:737
int const LF_CAT_SEDIMENT_INPUT
Definition cme.h:538
string const ERR
Definition cme.h:896
int const LF_CAT_SEDIMENT_INPUT_SUBMERGED
Definition cme.h:539
int const LF_CAT_DRIFT
Definition cme.h:544
int const TEXTURE_COARSE
Definition cme.h:517
int const LOG_FILE_MIDDLE_DETAIL
Definition cme.h:491
int const MIN_INLAND_OFFSET_UNCONS_EROSION
Definition cme.h:482
bool bFPIsEqual(const T d1, const T d2, const T dEpsilon)
Definition cme.h:1297
double const MASS_BALANCE_TOLERANCE
Definition cme.h:817
int const LOG_FILE_HIGH_DETAIL
Definition cme.h:492
int const TEXTURE_FINE
Definition cme.h:515
double const SEDIMENT_ELEV_TOLERANCE
Definition cme.h:816
int const RTN_ERR_NO_SEAWARD_END_OF_PROFILE_4
Definition cme.h:739
int const LOG_FILE_ALL
Definition cme.h:493
int const RTN_OK
Definition cme.h:695
int const MIN_PARALLEL_PROFILE_SIZE
Definition cme.h:483
double const DEAN_POWER
Definition cme.h:808
int const LF_CAT_SEDIMENT_INPUT_NOT_SUBMERGED
Definition cme.h:540
int const TEXTURE_SAND
Definition cme.h:516
int const RTN_ERR_NO_SEAWARD_END_OF_PROFILE_3
Definition cme.h:738
Contains CRWCoast definitions.
Contains CSimulation definitions.