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