1 module libs.irregular_section_open_channel; 2 3 /// Standard modules 4 import std.math; 5 import std.stdio; 6 import std.algorithm; 7 8 // Custom modules 9 import libs.openchannel; 10 import libs.utils.point; 11 import libs.utils.geometry_calculators; 12 13 class IrregularSectionOpenChannel : OpenChannel 14 { 15 /+++++++++++++++++++++++++++++++++++++++++++++++ 16 + Properties + 17 +++++++++++++++++++++++++++++++++++++++++++++++/ 18 private Point[] points; 19 private Point[] newPoints; 20 private float maxWaterElevation; 21 private float waterElevation; 22 private double trialDischarge; 23 24 Unknown[] availableUnknowns = [Unknown.DISCHARGE]; 25 26 /+++++++++++++++++++++++++++++++++++++++++++++++ 27 + Setters + 28 +++++++++++++++++++++++++++++++++++++++++++++++/ 29 /** 30 * Set the points with an array of Point object. 31 */ 32 void setPoints(Point[] pts) 33 { 34 points = pts; 35 } 36 37 /** 38 * Sets the water elevation. 39 */ 40 void setWaterElevation(float we) 41 { 42 waterElevation = we; 43 } 44 45 /+++++++++++++++++++++++++++++++++++++++++++++++ 46 + Getters + 47 +++++++++++++++++++++++++++++++++++++++++++++++/ 48 49 /** Returns the list of points */ 50 Point[] getPoints() 51 { 52 return points; 53 } 54 55 /** Returns the adjusted points. */ 56 Point[] getNewPoints() 57 { 58 return newPoints; 59 } 60 61 float getMaxWaterElevation() 62 { 63 return maxWaterElevation; 64 } 65 66 float getWaterElevation() 67 { 68 return waterElevation; 69 } 70 71 Unknown[] getAvailableUnknowns() 72 { 73 return availableUnknowns; 74 } 75 76 /+++++++++++++++++++++++++++++++++++++++++++++++ 77 + Constructors + 78 +++++++++++++++++++++++++++++++++++++++++++++++/ 79 /// Empty constructor 80 this() 81 { 82 unknown = Unknown.DISCHARGE; 83 } 84 85 /// Constructor specifying the unknown. 86 this(Unknown u) 87 { 88 unknown = u; 89 } 90 91 /+++++++++++++++++++++++++++++++++++++++++++++++ 92 + Methods + 93 +++++++++++++++++++++++++++++++++++++++++++++++/ 94 /// Add a single point 95 void addPoint(Point p) 96 { 97 int lastIndex = cast(int) points.length; 98 points.length = points.length + 1; 99 points[lastIndex] = p; 100 } 101 102 /// Solution summary. 103 /// To be called in the application API 104 bool solve() 105 { 106 newPoints = null; // Reset newPoints array 107 newPoints.length = 1; // Set length to 1 to give room for the first element of points array 108 109 if (!canFind(availableUnknowns, unknown)) 110 { 111 errorMessage = "The specified unknown is not included in the available unknowns."; 112 return false; 113 } 114 115 switch (unknown) 116 { 117 case Unknown.DISCHARGE: 118 if (solveForDischarge) 119 return true; 120 break; 121 default: 122 break; 123 } 124 return false; 125 } 126 127 /// Solve for the unknown discharge 128 private bool solveForDischarge() 129 { 130 if (isValidInputs(isValidBedSlope(Unknown.DISCHARGE))) 131 { 132 // Number of intersections 133 int leftIntersection = 0, rightIntersection = 0; 134 135 float x1, y1, x2, y2, x3; 136 137 // Collect all points including original ones 138 // and the intersection between section and waterElevation. 139 140 newPoints[0] = points[0]; 141 142 for (int i = 1; i < points.length; i++) 143 { 144 // Look for the intersection at the left side of the channel 145 if (leftIntersection == 0) 146 { 147 if (points[i].y <= waterElevation && i > 0) 148 { 149 leftIntersection++; 150 // Solve for the intersection point using interpolation 151 x1 = points[i - 1].x; 152 y1 = points[i - 1].y; 153 x2 = points[i].x; 154 y2 = points[i].y; 155 x3 = (waterElevation - y1) * (x2 - x1) / (y2 - y1) + x1; 156 newPoints.length = newPoints.length + 1; 157 newPoints[cast(int) newPoints.length - 1] = new Point(x3, 158 this.waterElevation); 159 } 160 } 161 162 // Get the water intersection at right bank 163 if (rightIntersection == 0) 164 { 165 if (points[i].y >= waterElevation && i > 0) 166 { 167 rightIntersection++; 168 // Solve for the intersection point using interpolation 169 x1 = points[i - 1].x; 170 y1 = points[i - 1].y; 171 x2 = points[i].x; 172 y2 = points[i].y; 173 x3 = (waterElevation - y1) * (x2 - x1) / (y2 - y1) + x1; 174 newPoints.length = newPoints.length + 1; 175 newPoints[cast(int) newPoints.length - 1] = new Point(x3, 176 this.waterElevation); 177 } 178 } 179 180 newPoints.length = newPoints.length + 1; 181 newPoints[cast(int) newPoints.length - 1] = points[i]; 182 } 183 184 // Now, remove all points above waterElevation 185 for (int i = 0; i < newPoints.length; i++) 186 { 187 if (newPoints[i].y > waterElevation) 188 { 189 // Using remove from std.algorithm 190 newPoints = newPoints.remove(i); 191 } 192 } 193 194 // Hydraulic elements 195 wettedArea = polygonArea(newPoints); 196 wettedPerimeter = polygonPerimeter(newPoints); 197 hydraulicRadius = wettedArea / wettedPerimeter; 198 199 averageVelocity = (1.0 / manningRoughness) * sqrt(bedSlope) * pow(hydraulicRadius, 200 (2.0 / 3)); 201 discharge = averageVelocity * wettedArea; 202 203 return true; 204 205 } 206 207 return false; 208 } 209 210 /// Finds the elevation of the lowest point from the cross section. 211 private float calculateLowestElevation() 212 { 213 float[] elevations; 214 float lowest = points[0].y; 215 216 // Collect all elevations 217 foreach (Point p; points) 218 { 219 elevations.length = elevations.length + 1; 220 elevations[cast(int) elevations.length - 1] = p.y; 221 } 222 223 // Compare each elevation 224 foreach (float el; elevations) 225 { 226 if (lowest > el) 227 { 228 lowest = el; 229 } 230 } 231 return lowest; 232 } 233 234 }