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
28#include <cfloat>
29
30#include <iostream>
31using std::cout;
32using std::endl;
33
34#include <algorithm>
35using std::shuffle;
36
37#include "cme.h"
38#include "simulation.h"
39#include "coast.h"
40
41//===============================================================================================================================
43//===============================================================================================================================
44int CSimulation::nDoUnconsErosionOnPolygon(int const nCoast, CGeomCoastPolygon* pPolygon, int const nTexture, double const dErosionTargetOnPolygon, double &dEroded)
45{
46 string strTexture;
47
48 if (nTexture == TEXTURE_FINE)
49 strTexture = "fine";
50
51 else if (nTexture == TEXTURE_SAND)
52 strTexture = "sand";
53
54 else if (nTexture == TEXTURE_COARSE)
55 strTexture = "coarse";
56
57 // Intialise
58 double dStillToErodeOnPolygon = dErosionTargetOnPolygon;
59 dEroded = 0;
60
61 // Get the up-coast and down-coast boundary details
62 int nUpCoastProfile = pPolygon->nGetUpCoastProfile();
63 CGeomProfile* pUpCoastProfile = m_VCoast[nCoast].pGetProfile(nUpCoastProfile);
64
65 int nDownCoastProfile = pPolygon->nGetDownCoastProfile();
66 CGeomProfile const* pDownCoastProfile = m_VCoast[nCoast].pGetProfile(nDownCoastProfile);
67
68 // 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
69 int nIndex = pUpCoastProfile->nGetCellGivenDepth(m_pRasterGrid, m_dDepthOfClosure);
70
71 if (nIndex == INT_NODATA)
72 {
74 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;
75
77 }
78
79 // The part-profile length is one greater than nIndex, since pPtiGetCellGivenDepth() returns the index of the cell at the depth of closure
80 int nUpCoastPartProfileLen = nIndex + 1;
81
82 // assert(bIsWithinValidGrid(&PtiUpCoastPartProfileSeawardEnd));
83
84 // 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)
85 vector<CGeom2DIPoint> PtiVUpCoastPartProfileCell;
86
87 // for (int n = 0; n < nUpCoastPartProfileLen; n++)
88 // PtiVUpCoastPartProfileCell.push_back(*pUpCoastProfile->pPtiGetCellInProfile(nUpCoastPartProfileLen - n - 1));
89 for (int n = nUpCoastPartProfileLen - 1; n >= 0; n--)
90 {
91 CGeom2DIPoint Pti = * pUpCoastProfile->pPtiGetCellInProfile(n);
92 PtiVUpCoastPartProfileCell.push_back(Pti);
93 }
94
95 int nUpCoastProfileCoastPoint = pUpCoastProfile->nGetCoastPoint();
96 int nDownCoastProfileCoastPoint = pDownCoastProfile->nGetCoastPoint();
97 int nXUpCoastProfileExistingCoastPoint = m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(nUpCoastProfileCoastPoint)->nGetX();
98 int nYUpCoastProfileExistingCoastPoint = m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(nUpCoastProfileCoastPoint)->nGetY();
99 int nCoastSegLen;
100
101 // Store the coast point numbers for this polygon so that we can shuffle them
102 vector<int> nVCoastPoint;
103
104 if (nDownCoastProfileCoastPoint == m_VCoast[nCoast].nGetCoastlineSize() - 1)
105 {
106 // This is the final down-coast polygon, so also include the down-coast polygon boundary
107 nCoastSegLen = nDownCoastProfileCoastPoint - nUpCoastProfileCoastPoint + 1;
108
109 for (int nCoastPoint = nUpCoastProfileCoastPoint; nCoastPoint <= nDownCoastProfileCoastPoint; nCoastPoint++)
110 nVCoastPoint.push_back(nCoastPoint);
111 }
112
113 else
114 {
115 // This is not the final down-coast polygon, so do not include the polygon's down-coast boundary
116 nCoastSegLen = nDownCoastProfileCoastPoint - nUpCoastProfileCoastPoint;
117
118 for (int nCoastPoint = nUpCoastProfileCoastPoint; nCoastPoint < nDownCoastProfileCoastPoint; nCoastPoint++)
119 nVCoastPoint.push_back(nCoastPoint);
120 }
121
122 // Estimate the volume of sediment which is to be eroded from each parallel profile
123 double dAllTargetPerProfile = dErosionTargetOnPolygon / nCoastSegLen;
124
125 // Shuffle the coast points, this is necessary so that leaving the loop does not create sequence-related artefacts
126 shuffle(nVCoastPoint.begin(), nVCoastPoint.begin() + nCoastSegLen, m_Rand[1]);
127
128 // 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
129 for (int n = 0; n < nCoastSegLen; n++)
130 {
131 // Get the coast point
132 int nCoastPoint = nVCoastPoint[n];
133
134 CGeom2DIPoint PtiCoastPoint = * m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(nCoastPoint);
135 int nCoastX = PtiCoastPoint.nGetX();
136 int nCoastY = PtiCoastPoint.nGetY();
137
138 // LogStream << m_ulIter << ": nCoastX = " << nCoastX << ", nCoastY = " << nCoastY << ", this is {" << dGridCentroidXToExtCRSX(nCoastX) << ", " << dGridCentroidYToExtCRSY(nCoastY) << "}" << endl;
139
140 // Is the coast cell an intervention structure?
141 if (bIsInterventionCell(nCoastX, nCoastY))
142 {
143 // No erosion possible on this parallel profile, so move on
144 // LogStream << m_ulIter << ": intervention structure at coast point [" << nCoastX << "][" << nCoastY << "] = {" << dGridCentroidXToExtCRSX(nCoastX) << ", " << dGridCentroidYToExtCRSY(nCoastY) << "}, cannot erode this parallel profile" << endl;
145
146 continue;
147 }
148
149 // 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;
150
151 // Not an intervention structure, so calculate the x-y offset between this coast point, and the coast point of the up-coast normal
152 int nXOffset = nCoastX - PtiVUpCoastPartProfileCell.back().nGetX();
153 int nYOffset = nCoastY - PtiVUpCoastPartProfileCell.back().nGetY();
154
155 // 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)
156 vector<CGeom2DIPoint> VPtiParProfile;
157
158 for (int m = 0; m < nUpCoastPartProfileLen; m++)
159 {
160 // TODO 017 Check that each point is within valid grid, do same for other similar places in rest of model
161 CGeom2DIPoint PtiTmp(PtiVUpCoastPartProfileCell[m].nGetX() + nXOffset, PtiVUpCoastPartProfileCell[m].nGetY() + nYOffset);
162 VPtiParProfile.push_back(PtiTmp);
163 }
164
165 // 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)
166 int nParProfEndX = VPtiParProfile[0].nGetX();
167 int nParProfEndY = VPtiParProfile[0].nGetY();
168
169 // Safety check
170 if (! bIsWithinValidGrid(nParProfEndX, nParProfEndY))
171 {
172 // if (m_nLogFileDetail >= LOG_FILE_ALL)
173 // 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;
174
175 KeepWithinValidGrid(nCoastX, nCoastY, nParProfEndX, nParProfEndY);
176 VPtiParProfile[0].SetX(nParProfEndX);
177 VPtiParProfile[0].SetY(nParProfEndY);
178 }
179
180 bool bHitEdge = false;
181 bool bEndProfile = false;
182 bool bZeroGradient = false;
183 bool bEnoughEroded = false;
184
185 int nParProfLen;
186 int nInlandOffset = -1;
187
188 double dParProfCoastElev = m_pRasterGrid->m_Cell[nCoastX][nCoastY].dGetSedimentTopElev();
189 double dParProfEndElev = m_pRasterGrid->m_Cell[nParProfEndX][nParProfEndY].dGetSedimentTopElev();
190
191 vector<double> VdParProfileDeanElev;
192
193 // These are for saving values for each offset
194 vector<int> VnParProfLenEachOffset;
195 vector<double> VdAmountEachOffset;
196 vector<vector<CGeom2DIPoint>> VVPtiParProfileEachOffset;
197 vector<vector<double>> VVdParProfileDeanElevEachOffset;
198
199 // OK, loop either until we can erode sufficient unconsolidated sediment, or until the landwards-moving parallel profile hits the grid edge
200 while (true)
201 {
202 // Move inland by one cell
203 nInlandOffset++;
204
205 if (nInlandOffset > 0)
206 {
207 if (nInlandOffset > (pUpCoastProfile->nGetNumCellsInProfile() - 1))
208 {
210 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;
211
212 bEndProfile = true;
213 break;
214 }
215
216 // 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
217 CGeom2DIPoint PtiUpCoastTmp = * pUpCoastProfile->pPtiGetCellInProfile(nInlandOffset);
218
219 // 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
220 int nXUpCoastStartOffset = PtiUpCoastTmp.nGetX() - nXUpCoastProfileExistingCoastPoint;
221 int nYUpCoastStartOffset = PtiUpCoastTmp.nGetY() - nYUpCoastProfileExistingCoastPoint;
222 int nXUpCoastThisStart = nCoastX - nXUpCoastStartOffset;
223 int nYUpCoastThisStart = nCoastY - nYUpCoastStartOffset;
224
225 // Is the new landwards point within the raster grid?
226 if (! bIsWithinValidGrid(nXUpCoastThisStart, nYUpCoastThisStart))
227 {
228 // It isn't
229 // 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;
230
231 // TODO 018 Need to improve this: at present we just abandon erosion on this coast point and move to another coast point
232 bHitEdge = true;
233 break;
234 }
235
236 // CGeom2DIPoint PtiThisUpCoastStart(nXUpCoastThisStart, nYUpCoastThisStart);
237
238 // Calculate the coordinates of a possible new landwards cell for the parallel profile
239 int
240 nXParNew = nXUpCoastThisStart + nXOffset,
241 nYParNew = nYUpCoastThisStart + nYOffset;
242
243 // Safety check
244 if (! bIsWithinValidGrid(nXParNew, nYParNew))
245 {
246 // 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 [";
247
248 KeepWithinValidGrid(nCoastX, nCoastY, nXParNew, nYParNew);
249
250 // LogStream << "[" << nXParNew << "][" << nYParNew << "] = {" << dGridCentroidXToExtCRSX(nXParNew) << ", " << dGridCentroidYToExtCRSY(nYParNew) << "}" << endl;
251
252 // Is this cell already in the parallel profile?
253 if ((VPtiParProfile.back().nGetX() != nXParNew) || (VPtiParProfile.back().nGetY() != nYParNew))
254 {
255 // It isn't, so append it to the parallel profile
256 CGeom2DIPoint PtiTmp(nXParNew, nYParNew);
257 VPtiParProfile.push_back(PtiTmp);
258 }
259 }
260
261 else
262 {
263 // No problem, so just append this to the parallel profile
264 CGeom2DIPoint PtiTmp(nXParNew, nYParNew);
265 VPtiParProfile.push_back(PtiTmp);
266 }
267 }
268
269 nParProfLen = static_cast<int>(VPtiParProfile.size());
270
271 if (nParProfLen < MIN_PARALLEL_PROFILE_SIZE)
272 {
273 // Can't have a meaningful parallel profile with very few points
274 // LogStream << m_ulIter << ": only " << nParProfLen << " points in parallel profile, min is " << MIN_PARALLEL_PROFILE_SIZE << ", abandoning" << endl;
275
276 continue;
277 }
278
279 // for (int m = 0; m < static_cast<int>(VPtiParProfile.size()); m++)
280 // LogStream << "[" << VPtiParProfile[m].nGetX() << "][" << VPtiParProfile[m].nGetY() << "] ";
281 // LogStream << endl;
282
283 // 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
284 CGeom2DPoint PtStart = PtGridCentroidToExt(&VPtiParProfile.back());
285 CGeom2DPoint PtEnd = PtGridCentroidToExt(&VPtiParProfile[0]);
286
287 // Calculate the length of the parallel profile
288 double dParProfileLen = dGetDistanceBetween(&PtStart, &PtEnd);
289
290 // Calculate the elevation difference between the start and end of the parallel profile
291 double dElevDiff = dParProfCoastElev - dParProfEndElev;
292
293 if (bFPIsEqual(dElevDiff, 0.0, TOLERANCE))
294 {
295 // Can't have a meaningful Dean profile with a near-zero elevation difference
296 // TODO 019 Need to improve this: at present we just abandon erosion on this coast point and move to another coast point
297 // LogStream << m_ulIter << ": zero gradient on parallel profile, abandoning" << endl;
298
299 bZeroGradient = true;
300 break;
301 }
302
303 // Safety check
304 if (dParProfileLen <= 0)
305 dParProfileLen = 1;
306
307 // 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
308 double dParProfA = dElevDiff / pow(dParProfileLen, DEAN_POWER);
309 VdParProfileDeanElev.resize(nParProfLen, 0);
310 double dInc = dParProfileLen / (nParProfLen - 1);
311
312 // 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
313 CalcDeanProfile(&VdParProfileDeanElev, dInc, dParProfCoastElev, dParProfA, false, 0, 0);
314
315 vector<double> dVParProfileNow(nParProfLen, 0);
316 vector<bool> bVProfileValid(nParProfLen, true);
317
318 for (int m = 0; m < nParProfLen; m++)
319 {
320 int nX = VPtiParProfile[nParProfLen - m - 1].nGetX();
321 int nY = VPtiParProfile[nParProfLen - m - 1].nGetY();
322
323 // Safety check
324 if (! bIsWithinValidGrid(nX, nY))
325 {
326 // if (m_nLogFileDetail >= LOG_FILE_ALL)
327 // 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;
328
329 bVProfileValid[m] = false;
330 continue;
331 }
332
333 // Don't erode intervention cells
334 if (bIsInterventionCell(nX, nY))
335 bVProfileValid[m] = false;
336
337 dVParProfileNow[m] = m_pRasterGrid->m_Cell[nX][nY].dGetSedimentTopElev();
338 }
339
340 // Get the total difference in elevation (present profile - Dean profile)
341 double dParProfTotDiff = dSubtractProfiles(&dVParProfileNow, &VdParProfileDeanElev, &bVProfileValid);
342
343 // // DEBUG CODE -----------------------------------------------------
344 // 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;
345
346 // LogStream << "Profile now:" << endl;
347 // for (int n = 0; n < nParProfLen; n++)
348 // {
349 // if (bVProfileValid[n])
350 // LogStream << dVParProfileNow[n] << " ";
351 // else
352 // LogStream << "XXX ";
353 // }
354 // LogStream << endl << endl;;
355 //
356 // LogStream << "Parallel Dean profile for erosion:" << endl;
357 // for (int n = 0; n < nParProfLen; n++)
358 // {
359 // if (bVProfileValid[n])
360 // LogStream << VdParProfileDeanElev[n] << " ";
361 // else
362 // LogStream << "XXX ";
363 // }
364 // LogStream << endl << endl;
365 //
366 // LogStream << "Difference (present profile minus Dean profile):" << endl;
367 // for (int n = 0; n < nParProfLen; n++)
368 // {
369 // if (bVProfileValid[n])
370 // LogStream << dVParProfileNow[n] - VdParProfileDeanElev[n] << " ";
371 // else
372 // LogStream << "XXX ";
373 // }
374 // LogStream << endl << endl;
375 //
376 // LogStream << "dParProfTotDiff = " << dParProfTotDiff << " dAllTargetPerProfile = " << dAllTargetPerProfile << endl;
377 // // DEBUG CODE -----------------------------------------------------
378
379 // So will we be able to erode as much as is needed?
380 if (dParProfTotDiff > dAllTargetPerProfile)
381 {
382 // 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;
383
384 bEnoughEroded = true;
385 break;
386 }
387
388 // 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
389 if ((nInlandOffset >= MIN_INLAND_OFFSET_UNCONS_EROSION) && (bFPIsEqual(dParProfTotDiff, 0.0, TOLERANCE)))
390 {
392 LogStream << m_ulIter << ": leaving loop because nInlandOffset (" << nInlandOffset << ") >= MIN_INLAND_OFFSET_UNCONS_EROSION) and dParProfTotDiff = " << dParProfTotDiff << endl;
393
394 break;
395 }
396
397 // Save the amount which can be eroded for this offset
398 VdAmountEachOffset.push_back(dParProfTotDiff);
399 VnParProfLenEachOffset.push_back(nParProfLen);
400 VVPtiParProfileEachOffset.push_back(VPtiParProfile);
401 VVdParProfileDeanElevEachOffset.push_back(VdParProfileDeanElev);
402 }
403
404 // 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
405 // TODO 019 TODO 018 Improve this, see above
406 if (bHitEdge || bEndProfile || bZeroGradient)
407 continue;
408
409 // OK we will do some erosion on this parallel profile, set the target for this profile to be the full target amount
410 double dStillToErodeOnProfile = dAllTargetPerProfile;
411
412 if (! bEnoughEroded)
413 {
414 // 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
415 int nOffsetForLargestPossible = -1;
416 double dLargestPossibleErosion = 0;
417
418 for (unsigned int nn = 0; nn < VdAmountEachOffset.size(); nn++)
419 {
420 if (VdAmountEachOffset[nn] > dLargestPossibleErosion)
421 {
422 dLargestPossibleErosion = VdAmountEachOffset[nn];
423 nOffsetForLargestPossible = nn;
424 }
425 }
426
427 // If every offset gave zero erosion then abandon this profile and do the next parallel profile
428 if (nOffsetForLargestPossible < 0)
429 continue;
430
431 // OK, we have an offset which gives us the largest possible erosion (but less than the full target amount), continue with this
432 nInlandOffset = nOffsetForLargestPossible;
433 dStillToErodeOnProfile = dLargestPossibleErosion;
434 nParProfLen = VnParProfLenEachOffset[nInlandOffset];
435 VPtiParProfile = VVPtiParProfileEachOffset[nInlandOffset];
436 VdParProfileDeanElev = VVdParProfileDeanElevEachOffset[nInlandOffset];
437
438 // 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;
439 }
440
441 // 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()
442 int nRet = nDoParallelProfileUnconsErosion(pPolygon, nCoastPoint, nCoastX, nCoastY, nTexture, nInlandOffset, nParProfLen, &VPtiParProfile, &VdParProfileDeanElev, dStillToErodeOnProfile, dStillToErodeOnPolygon, dEroded);
443
444 if (nRet != RTN_OK)
445 return nRet;
446
447 // LogStream << m_ulIter << ": eroding polygon " << nPoly << ": finished at coast point " << nCoastPoint << " dStillToErodeOnProfile = " << dStillToErodeOnProfile << " dStillToErodeOnPolygon = " << dStillToErodeOnPolygon << " dAllTargetPerProfile = " << dAllTargetPerProfile << endl;
448
449 // if (dStillToErodeOnProfile > 0)
450 // {
451 // // LogStream << " X Still to erode on profile = " << dStillToErodeOnProfile << " dStillToErodeOnPolygon WAS = " << dStillToErodeOnPolygon;
452 // dStillToErodeOnPolygon += dStillToErodeOnProfile;
453 // dAllTargetPerProfile += (dStillToErodeOnProfile / (nCoastSegLen - n));
454 // // LogStream << " dStillToErodeOnPolygon NOW = " << dStillToErodeOnPolygon << endl;
455 // }
456
457 if (dStillToErodeOnPolygon <= 0)
458 {
459 // LogStream << m_ulIter << ": YYYYYYYYYYYYYYY in polygon " << nPoly << ", leaving loop because dStillToErodeOnPolygon = " << dStillToErodeOnPolygon << endl;
460 break;
461 }
462 }
463
464 // How much have we been able to erode?
465 // LogStream << m_ulIter << ": nPoly = " << nPoly << " dEroded = " << dEroded << endl;
466
467 // // Is the depth eroded within TOLERANCE of the target depth-equivalent?
468 // if (bFPIsEqual(dEroded, dErosionTargetOnPolygon, TOLERANCE))
469 // {
470 // if (m_nLogFileDetail >= LOG_FILE_MIDDLE_DETAIL)
471 // LogStream << m_ulIter << ": polygon " << nPoly << " actual erosion of " + strTexture + " sediment is approximately equal to estimate, actual = " << dEroded * m_dCellArea << " estimate = " << dErosionTargetOnPolygon * m_dCellArea << endl;
472 // }
473 // else
474 // {
475 // if (dEroded < dErosionTargetOnPolygon)
476 // {
477 // if (m_nLogFileDetail >= LOG_FILE_MIDDLE_DETAIL)
478 // 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;
479 // }
480 // else
481 // {
482 // if (m_nLogFileDetail >= LOG_FILE_MIDDLE_DETAIL)
483 // 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;
484 // }
485 // }
486
487 return RTN_OK;
488}
489
490//===============================================================================================================================
492//===============================================================================================================================
493int 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)
494{
495 for (int nDistSeawardFromNewCoast = 0; nDistSeawardFromNewCoast < nParProfLen; nDistSeawardFromNewCoast++)
496 {
497 // Leave the loop if we have eroded enough for this polygon
498 if (dStillToErodeOnPolygon <= 0)
499 {
501 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;
502
503 break;
504 }
505
506 // Leave the loop if we have eroded enough for this parallel profile
507 if (dStillToErodeOnProfile <= 0)
508 {
510 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;
511
512 break;
513 }
514
515 CGeom2DIPoint PtiTmp = pVPtiParProfile->at(nParProfLen - nDistSeawardFromNewCoast - 1);
516 int
517 nX = PtiTmp.nGetX(),
518 nY = PtiTmp.nGetY();
519
520 // Safety check
521 if (! bIsWithinValidGrid(nX, nY))
522 {
523 // 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;
524
525 KeepWithinValidGrid(nCoastX, nCoastY, nX, nY);
526 PtiTmp.SetX(nX);
527 PtiTmp.SetY(nY);
528 }
529
530 // Don't do anything to intervention cells
531 if (bIsInterventionCell(nX, nY))
532 continue;
533
534 // Don't do cells twice
535 if (! m_pRasterGrid->m_Cell[nX][nY].bBeachErosionOrDepositionThisIter())
536 {
537 // Get this cell's current elevation
538 double dThisElevNow = m_pRasterGrid->m_Cell[nX][nY].dGetSedimentTopElev();
539
540// LogStream << "\tnPoly = " << nPoly << ", [" << nX << "][" << nY << "] = {" << dGridCentroidXToExtCRSX(nX) << ", " << dGridCentroidYToExtCRSY(nY) << "} nCoastPoint = " << nCoastPoint << " nDistSeawardFromNewCoast = " << nDistSeawardFromNewCoast << " dThisElevNow = " << dThisElevNow << " Dean Elev = " << VdParProfileDeanElev[nDistSeawardFromNewCoast] << endl;
541
542 // Subtract the two elevations
543 double dElevDiff = dThisElevNow - pVdParProfileDeanElev->at(nDistSeawardFromNewCoast);
544
545 if ((dElevDiff > 0) && (m_pRasterGrid->m_Cell[nX][nY].bIsInContiguousSea()))
546 {
547 // 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
548// 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;
549
550 // Now get the number of the highest layer with non-zero thickness
551 int nThisLayer = m_pRasterGrid->m_Cell[nX][nY].nGetTopNonZeroLayerAboveBasement();
552
553 // Safety check
554 if (nThisLayer == INT_NODATA)
556
557 if (nThisLayer != NO_NONZERO_THICKNESS_LAYERS)
558 {
559 // 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
560 double dToErode = tMin(dElevDiff, dStillToErodeOnProfile, dStillToErodeOnPolygon);
561 double dRemoved = 0;
562
563// assert(dToErode > 0);
564
565 // Erode this sediment size class
566 ErodeCellBeachSedimentSupplyLimited(nX, nY, nThisLayer, nTexture, dToErode, dRemoved);
567
568 if (dRemoved > 0)
569 {
570 // Update totals for the polygon and the profile
571 dTotEroded += dRemoved;
572 dStillToErodeOnProfile -= dRemoved;
573 dStillToErodeOnPolygon -= dRemoved;
574
575 // Update this-timestep totals
577
578 // LogStream << m_ulIter << ": in polygon " << nPoly << ", actual beach erosion = " << dTmpTot << " at [" << nX << "][" << nY << "] = {" << dGridCentroidXToExtCRSX(nX) << ", " << dGridCentroidYToExtCRSY(nY) << "} nCoastPoint = " << nCoastPoint << " nDistSeawardFromNewCoast = " << nDistSeawardFromNewCoast << endl;
579
580 // // DEBUG CODE ==================================================================================================
581 // if (nTexture == TEXTURE_SAND)
582 // {
583 // 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;
584 // }
585 // else
586 // {
587 // 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;
588 // }
589 // // DEBUG CODE ==================================================================================================
590
591 // Store the this-polygon depth of sediment eroded during Dean profile deposition of beach unconsolidated sediment
592 if (nTexture == TEXTURE_SAND)
593 pPolygon->AddBeachSandErodedDeanProfile(dRemoved);
594
595 else
596 pPolygon->AddBeachCoarseErodedDeanProfile(dRemoved);
597
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 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 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 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 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 dLowering = dErodibility * dMaxToErode;
719
720 // Make sure we don't get -ve amounts left on the cell
721 dRemoved = tMin(dExistingAvailable, dLowering);
722 double 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 nUpCoastProfile = pPolygon->nGetUpCoastProfile();
785 int 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 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 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 nUpCoastProfileCoastPoint = pUpCoastProfile->nGetCoastPoint();
815 int nDownCoastProfileCoastPoint = pDownCoastProfile->nGetCoastPoint();
816 int nXUpCoastProfileExistingCoastPoint = m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(nUpCoastProfileCoastPoint)->nGetX();
817 int 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 nCoastPoint = nVCoastPoint[n];
891 CGeom2DIPoint PtiCoastPoint = * m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(nCoastPoint);
892 int nCoastX = PtiCoastPoint.nGetX();
893 int 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 nXOffset = nCoastX - nXUpCoastProfileExistingCoastPoint;
897 int 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 PtiProf = * pUpCoastProfile->pPtiGetCellInProfile(m);
927 CGeom2DIPoint 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 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 dParProfStartElev = m_dThisIterMeanSWL + m_dDeanProfileStartAboveSWL;
950
951 // Calculate the total length of the parallel profile, including any seaward offset
952 double 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 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 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 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 dTmpElev = m_pRasterGrid->m_Cell[nX][nY].dGetSedimentTopElev();
1005 double 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 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 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 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 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 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 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 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 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 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 nXDownCoastProfileExistingCoastPoint = m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(nDownCoastProfileCoastPoint)->nGetX();
1350 int 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 nCoastPoint = nVCoastPoint[n];
1393 CGeom2DIPoint PtiCoastPoint = * m_VCoast[nCoast].pPtiGetCellMarkedAsCoastline(nCoastPoint);
1394 int nCoastX = PtiCoastPoint.nGetX();
1395 int 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 nXOffset = nCoastX - nXDownCoastProfileExistingCoastPoint;
1399 int 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 PtiProf = * pDownCoastProfile->pPtiGetCellInProfile(m);
1429 CGeom2DIPoint 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 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 dParProfStartElev = m_dThisIterMeanSWL + m_dDeanProfileStartAboveSWL;
1451
1452 // Calculate the total length of the parallel profile, including any seaward offset
1453 double 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 dParProfA = (dParProfStartElev - dParProfEndElev) / pow(dParProfDeanLen, DEAN_POWER);
1464
1465 nParProfLen = static_cast<int>(PtiVParProfile.size());
1466 VdParProfileDeanElev.resize(nParProfLen, 0);
1467
1468 double 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 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 dTmpElev = m_pRasterGrid->m_Cell[nX][nY].dGetSedimentTopElev();
1502 double 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 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 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 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 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 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 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 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
1772 else if (nTexture == TEXTURE_COARSE)
1773 {
1774 double dCoarseRemoved = 0;
1775 ErodeCellBeachSedimentSupplyLimited(nX, nY, nThisLayer, TEXTURE_COARSE, -dElevDiff, dCoarseRemoved);
1776
1777 // Update total for this parallel profile
1778 dDepositedOnProfile -= dCoarseRemoved;
1779 dStillToDepositOnProfile += dCoarseRemoved;
1780
1781 // 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
1782 dDepositedOnPoly -= dCoarseRemoved;
1783 dStillToDepositOnPoly += dCoarseRemoved;
1784
1785 // Update this-timestep totals
1787
1788 // // DEBUG CODE ==============================================================================================
1789 // 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;
1790 // // DEBUG CODE ==============================================================================================
1791
1792 // Store the this-polygon depth of coarse sediment eroded during Dean profile deposition of beach unconsolidated sediment
1793 pPolygon->AddBeachCoarseErodedDeanProfile(dCoarseRemoved);
1794 }
1795 }
1796
1797 // if (dDepositedOnPoly > dTargetToDepositOnPoly)
1798 // {
1799 // // LogStream << "££££££ 4 nPoly = " << nPoly << " texture = " << strTexture << " dDepositedOnPoly = " << dDepositedOnPoly << " dTargetToDepositOnPoly = " << dTargetToDepositOnPoly << endl;
1800 // }
1801
1802 // LogStream << m_ulIter << ": in polygon " << nPoly << " have net deposition for " << strTexture << ", actual beach erosion = " << dSand + dCoarse << " at [" << nX << "][" << nY << "]" << endl;
1803 }
1804 }
1805 }
1806 }
1807 }
1808
1809 // Store amounts deposited on this polygon
1810 if (nTexture == TEXTURE_SAND)
1811 {
1812 pPolygon->SetBeachDepositionUnconsSand(dDepositedOnPoly);
1813
1814 // Check mass balance for sand deposited
1816 if (! bFPIsEqual(pPolygon->dGetToDoBeachDepositionUnconsSand(), dDepositedOnPoly, MASS_BALANCE_TOLERANCE))
1817 LogStream << m_ulIter << ": polygon " << pPolygon->nGetCoastID() << " NOT equal SAND dGetToDoBeachDepositionUnconsSand() = " << pPolygon->dGetToDoBeachDepositionUnconsSand() << " dDepositedOnPoly = " << dDepositedOnPoly << endl;
1818
1820
1821 }
1822
1823 else if (nTexture == TEXTURE_COARSE)
1824 {
1825 pPolygon->SetBeachDepositionUnconsCoarse(dDepositedOnPoly);
1826
1827 // Check mass balance for coarse deposited
1829 if (! bFPIsEqual(pPolygon->dGetToDoBeachDepositionUnconsCoarse(), dDepositedOnPoly, MASS_BALANCE_TOLERANCE))
1830 LogStream << m_ulIter << ": polygon " << pPolygon->nGetCoastID() << " NOT equal COARSE dGetToDoBeachDepositionUnconsCoarse() = " << pPolygon->dGetToDoBeachDepositionUnconsCoarse() << " dDepositedOnPoly = " << dDepositedOnPoly << endl;
1831
1833 }
1834
1835 // // DEBUG CODE #####################
1836 // if (m_ulIter == 5)
1837 // {
1838 // LogStream << m_ulIter << ": leaving nDoUnconsDepositionOnPolygon() nCoast = " << nCoast << " nPoly = " << nPoly << " strTexture = " << strTexture << " dTargetToDepositOnPoly = " << dTargetToDepositOnPoly * m_dCellArea << " dDepositedOnPoly = " << dDepositedOnPoly * m_dCellArea << endl;
1839 //
1840 // double dTmpSandUncons = 0;
1841 // for (int nX1 = 0; nX1 < m_nXGridSize; nX1++)
1842 // {
1843 // for (int nY1 = 0; nY1 < m_nYGridSize; nY1++)
1844 // {
1845 // dTmpSandUncons += m_pRasterGrid->m_Cell[nX1][nY1].dGetTotUnconsSand();
1846 // }
1847 // }
1848 //
1849 // LogStream << m_ulIter << ": leaving nDoUnconsDepositionOnPolygon() for nPoly = " << nPoly << " TOTAL UNCONSOLIDATED SAND ON ALL CELLS = " << dTmpSandUncons * m_dCellArea << endl;
1850 // }
1851 // // DEBUG CODE #####################
1852
1853 return RTN_OK;
1854}
1855
1856//===============================================================================================================================
1858//===============================================================================================================================
1859bool CSimulation::bElevAboveDeanElev(int const nX, int const nY, double const dElevDiff, CRWCellLandform const* pLandform)
1860{
1861 // TODO 075 What if it is bedrock that sticks above Dean profile?
1862 if (dElevDiff <= 0)
1863 {
1864 if (m_pRasterGrid->m_Cell[nX][nY].bIsInContiguousSea())
1865 return true;
1866
1867 int nCat = pLandform->nGetLFCategory();
1868
1869 if (nCat == LF_CAT_DRIFT)
1870 return true;
1871
1873 return true;
1874 }
1875
1876 return false;
1877}
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:72
int nGetY(void) const
Returns the CGeom2DIPoint object's integer Y coordinate.
Definition 2di_point.cpp:48
void SetX(int const)
The integer parameter sets a value for the CGeom2DIPoint object's X coordinate.
Definition 2di_point.cpp:66
int nGetX(void) const
Returns the CGeom2DIPoint object's integer X coordinate.
Definition 2di_point.cpp:42
Geometry class used to represent 2D point objects with floating-point coordinates.
Definition 2d_point.h:27
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:35
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:544
int nGetCoastPoint(void) const
Returns the coast point at which the profile starts.
Definition profile.cpp:79
CGeom2DIPoint * pPtiGetCellInProfile(int const)
Returns a single cell in the profile.
Definition profile.cpp:503
int nGetNumCellsInProfile(void) const
Returns the number of cells in the profile.
Definition profile.cpp:517
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
Definition simulation.h:591
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:834
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:840
void KeepWithinValidGrid(int &, int &) const
Constrains the supplied point (in the grid CRS) to be a valid cell within the raster grid.
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:2569
unsigned long m_ulThisIterNumBeachDepositionCells
Definition simulation.h:653
double m_dDeanProfileStartAboveSWL
Berm height i.e. height above SWL of start of depositional Dean profile.
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:837
double m_dThisIterBeachDepositionCoarse
Definition simulation.h:910
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
Definition simulation.h:649
vector< bool > m_bUnconsChangedThisIter
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
Definition simulation.h:645
bool bIsWithinValidGrid(int const, int const) const
Checks whether the supplied point (an x-y pair, in the grid CRS) is within the raster grid,...
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
Definition simulation.h:906
CGeom2DPoint PtGridCentroidToExt(CGeom2DIPoint const *) const
Transforms a pointer to a CGeom2DIPoint in the raster grid CRS (assumed to be the centroid of a cell)...
Definition gis_utils.cpp:78
unsigned long m_ulIter
The number of the current iteration (time step)
Definition simulation.h:618
double m_dCellSide
Length of a cell side (in external CRS units)
Definition simulation.h:689
bool bIsInterventionCell(int const, int const) const
Returns true if the cell is an intervention.
Definition utils.cpp:2918
double m_dDepthOfClosure
Definition simulation.h:858
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:2528
double m_dThisIterMeanSWL
Definition simulation.h:752
This file contains global definitions for CoastalME.
int const LF_SUBCAT_DRIFT_BEACH
Definition cme.h:552
int const NO_NONZERO_THICKNESS_LAYERS
Definition cme.h:767
int const INT_NODATA
Definition cme.h:474
T tMin(T a, T b)
Definition cme.h:1251
double const TOLERANCE
Definition cme.h:811
int const RTN_ERR_NO_TOP_LAYER
Definition cme.h:738
int const RTN_ERR_NO_SEAWARD_END_OF_PROFILE_2
Definition cme.h:734
int const LF_CAT_SEDIMENT_INPUT
Definition cme.h:536
string const ERR
Definition cme.h:890
int const LF_CAT_SEDIMENT_INPUT_SUBMERGED
Definition cme.h:537
int const LF_CAT_DRIFT
Definition cme.h:542
int const TEXTURE_COARSE
Definition cme.h:515
int const LOG_FILE_MIDDLE_DETAIL
Definition cme.h:489
int const MIN_INLAND_OFFSET_UNCONS_EROSION
Definition cme.h:480
bool bFPIsEqual(const T d1, const T d2, const T dEpsilon)
Definition cme.h:1284
double const MASS_BALANCE_TOLERANCE
Definition cme.h:814
int const LOG_FILE_HIGH_DETAIL
Definition cme.h:490
int const TEXTURE_FINE
Definition cme.h:513
double const SEDIMENT_ELEV_TOLERANCE
Definition cme.h:813
int const RTN_ERR_NO_SEAWARD_END_OF_PROFILE_4
Definition cme.h:736
int const LOG_FILE_ALL
Definition cme.h:491
int const RTN_OK
Definition cme.h:692
int const MIN_PARALLEL_PROFILE_SIZE
Definition cme.h:481
double const DEAN_POWER
Definition cme.h:805
int const LF_CAT_SEDIMENT_INPUT_NOT_SUBMERGED
Definition cme.h:538
int const TEXTURE_SAND
Definition cme.h:514
int const RTN_ERR_NO_SEAWARD_END_OF_PROFILE_3
Definition cme.h:735
Contains CRWCoast definitions.
Contains CSimulation definitions.