1 /**
2 * openchannel module.
3 */
4 module libs.openchannel;
5 
6 import std.math;
7 import std.algorithm;
8 
9 /++
10 + The base class for all open channels.
11 +/
12 class OpenChannel
13 {
14     //******************************************
15     // Constants
16     //*************************************** */
17     /// Gravitational acceleration in metric.
18     protected const GRAVITY_METRIC = 9.81;
19     /// Trial error max to 0.01%
20     protected const ERROR = 0.0001;
21 
22     // ****************************************
23     // Properties
24     //*************************************** */
25     /**
26     * Units options
27     */
28     enum Units
29     {
30         METRIC,
31         ENGLISH
32     }
33     /**
34     * Flow types. These are the categories in which the calculated froude number
35     * is compared to.
36     */
37     public enum FlowType
38     {
39         CRITICAL,
40         SUBCRITICAL,
41         SUPERCRITICAL
42     }
43 
44     /// General available unknowns for open channel.
45     public enum Unknown
46     {
47         DISCHARGE,
48         BED_SLOPE,
49         WATER_DEPTH,
50         BASE_WIDTH,
51         PIPE_DIAMETER
52     }
53     /** Unit of measurement.\
54      All calculations will be done in metric but both 
55      metric and imperial system are supported.
56     */
57     protected Units unit = Units.METRIC;
58 
59     /// Discharge (Flow Rate)
60     protected double discharge;
61 
62     /// Rise over run of the channel.
63     protected double bedSlope;
64 
65     /// Depth of water measured from the deepest point of the
66     /// channel.
67     protected double waterDepth;
68 
69     /// Manning's roughness coefficient.
70     protected float manningRoughness;
71 
72     /// Total length of the channel section covered with water.
73     protected double wettedPerimeter;
74 
75     /// Total area of the channel section covered with water.
76     protected double wettedArea;
77 
78     /// wettedArea / wettedPerimeter
79     protected double hydraulicRadius;
80 
81     /// Average velocity over the whole cross section of the channel.
82     protected double averageVelocity;
83 
84     /// Froude number.
85     protected float froudeNumber;
86 
87     /// Enum type. (e.g. DISCHARGE, WATER_DEPTH, etc.)
88     protected Unknown unknown;
89 
90     /// Flow type reconned from the Enum type FlowType
91     protected FlowType flowType;
92     /// Hydraulic depth
93     protected double hydraulicDepth;
94     /// Discharge intensity. Discharge divided by the top channel width.
95     protected double dischargeIntensity;
96     /// Depth of flow that will give critical flow.
97     protected double criticalDepth;
98     /// Bed slope that will give critical flow.
99     protected double criticalSlope;
100     /// Available unknowns
101     protected Unknown[] availableUnknowns = [Unknown.DISCHARGE];
102     /// Variable that tells if the calculation has no error.
103     protected bool isCalculationSuccess;
104     /// The error or warning message that helps debug or give
105     /// information about the calculation results.
106     public string errorMessage;
107 
108     //++++++++++++++++++++++++++++++++++++++++++++++ 
109     //               Constructors                  +
110     //+++++++++++++++++++++++++++++++++++++++++++++/
111     
112     /**
113     * Empty constructor.
114     * The unit is automatically set to S.I. (Metric).
115     */
116     this()
117     {
118         this.intialize();
119     }
120 
121     /**
122      Put all the initializations here.
123     */
124     protected void intialize()
125     {
126         unknown = Unknown.DISCHARGE;
127         unit = Units.METRIC;
128     }
129 
130     //++++++++++++++++++++++++++++++++++++++++++++++ 
131     //                 Getters                     +
132     //+++++++++++++++++++++++++++++++++++++++++++++/
133 
134     /** 
135     Returns the rate of flow in either cubic meter per second (metric)
136     or cubic feet per second (english). 
137     */
138     public double getDischarge()
139     {
140         if (unit == Units.ENGLISH)
141         {
142             return discharge * pow(3.28, 3);
143         } else {
144             return discharge;
145         }
146     }
147 
148     /** 
149      Returns the average velocity in the channel in either  meter per second (metric)
150      or feet per second (english). 
151     */
152     public double getAverageVelocity()
153     {
154         if (unit == Units.ENGLISH)
155         {
156             return averageVelocity * 3.28;
157         }
158         return averageVelocity;
159     }
160 
161     /**
162      Returns the bed (bottom) slope of the channel.
163     */
164     public double getBedSlope()
165     {
166         return bedSlope;
167     }
168 
169     /**
170      Returns the water depth in either meter
171      or feet.
172      */
173     public double getWaterDepth()
174     {
175         if (unit == Units.ENGLISH)
176         {
177             return waterDepth * 3.28;
178         }
179         return waterDepth;
180     }
181 
182     /**
183      Returns the wet perimeter in either meter of feet.
184     */
185     public double getWettedPerimeter()
186     {
187         if (unit == Units.ENGLISH)
188         {
189             return wettedPerimeter * 3.28;
190         }
191         return wettedPerimeter;
192     }
193 
194     /**
195      Returns the wet area in either square meter or
196      square foot.
197     */
198     public double getWettedArea()
199     {
200         if (unit == Units.ENGLISH)
201         {
202             return wettedArea * pow(3.28, 2);
203         }
204         return wettedArea;
205     }
206 
207     /**
208      Returns the hydraulic radius in either meters
209      or feet.
210     */
211     public double getHydraulicRadius()
212     {
213         if (unit == Units.ENGLISH)
214         {
215             return hydraulicRadius * 3.28;
216         }
217         return hydraulicRadius;
218     }
219 
220     /**
221      Returns the froude number
222     */
223     public double getFroudeNumber()
224     {
225         return froudeNumber;
226     }
227 
228     /**
229      Retuens the manning's roughness coefficient.
230     */
231     public double getManningRoughness()
232     {
233         return manningRoughness;
234     }
235 
236     /**
237      Returns the string representation of type of flow.
238     */
239     public FlowType getFlowType()
240     {
241         return flowType;
242     }
243 
244     /**
245      Returns the hydraulic depth in either meter
246      or foot.
247     */
248     public double getHydraulicDepth()
249     {   
250         if (unit == Units.ENGLISH)
251         {
252             return hydraulicDepth * 3.28;
253         }
254         return hydraulicDepth;
255     }
256 
257     /**
258      Returns discharge intensity in either cubic meter per second per meter
259      or cubic foot per second per foot.
260     */
261     public double getDischargeIntensity()
262     {
263         if (unit == Units.ENGLISH)
264         {
265             return dischargeIntensity * pow(3.28, 2);
266         }
267         return dischargeIntensity;
268     }
269 
270     /**
271      Returns critical depth in either meters or feet.
272     */
273     public double getCriticalDepth()
274     {
275         if (unit == Units.ENGLISH)
276         {
277             return criticalDepth * 3.28;
278         }
279         return criticalDepth;
280     }
281 
282     /**
283      Returns the slope of the critical flow for the channel.
284     */
285     public double getCriticalSlope()
286     {
287         return criticalSlope;
288     }
289 
290     /**
291     * Check if an error has occurred.
292     * @return isError
293     */
294     public bool isCalculationSuccessful()
295     {
296         return isCalculationSuccessful;
297     }
298 
299     /**
300     * Gets the error message.
301     * @return errMessage
302     */
303     public string getErrMessage()
304     {
305         return errorMessage;
306     }
307 
308     //++++++++++++++++++++++++++++++++++++++++++++++ 
309     //                 Setters                     +
310     //+++++++++++++++++++++++++++++++++++++++++++++/
311 
312     /**
313      Set the bed slope of the channel.
314      Params:
315         pBedSlope = Bed or bottom slope of the channel.
316     */
317     public void setBedSlope(double pBedSlope)
318     {
319         bedSlope = pBedSlope;
320     }
321 
322     /**
323      Sets the discharge.
324      Params:
325         pDeischarge = discharge in either cubic meter per second or
326      cubic foot per second.
327     */
328     public void setDischarge(double pDischarge)
329     {
330         if (unit == Units.ENGLISH)
331         {
332             discharge = pDischarge * pow(1 / 3.28, 3);
333         } 
334         else 
335         {
336             discharge = pDischarge;
337         }
338     }
339 
340     /**
341      Sets the water depth.
342      Params:
343         pWaterDepth = Water depth in either meter or foot.
344     */
345     public void setWaterDepth(double pWaterDepth)
346     {
347         if (unit == Units.ENGLISH)
348         {
349             waterDepth = pWaterDepth / 3.28;
350         } 
351         else
352         {
353             waterDepth = pWaterDepth;
354         }
355     }
356 
357     /**
358      Sets the manning roughness coefficient.
359      Params:
360         pManningRoughness = Manning's roughness coefficient.
361     */
362     public void setManningRoughness(double pManningRoughness)
363     {
364         manningRoughness = pManningRoughness;
365     }
366 
367     /**
368      Sets the unknown based on the available unknowns of a specific channel type.
369      Params:
370         u = Unknown.
371     */
372     public void setUnknown(Unknown u)
373     {
374         unknown = u;
375     }
376 
377     /**
378      Sets the unit.
379      Params:
380         u = Unit
381     */
382     public void setUnit(Units u)
383     {
384         unit = u;
385     }
386 
387     //++++++++++++++++++++++++++++++++++++++++++++++
388     //                  Methods                    +
389     //+++++++++++++++++++++++++++++++++++++++++++++/
390     /**
391      Determines the flow type based on the froude number.
392     */
393     protected void calculateFlowType()
394     {
395         // Flow type
396         if (this.froudeNumber == 1)
397         {
398             flowType = FlowType.CRITICAL;
399         }
400         else if (this.froudeNumber < 1)
401         {
402             flowType = FlowType.SUBCRITICAL;
403         }
404         else
405         {
406             flowType = FlowType.SUPERCRITICAL;
407         }
408     }
409 
410     /+++++++++++++++++++++++++++++++++++++++++++++++
411     +               Error handling                 +
412     +++++++++++++++++++++++++++++++++++++++++++++++/
413 
414     /**
415     * Manning's roughness error checking
416     */
417     protected bool isValidManning()
418     {
419         if (manningRoughness <= 0.0)
420         {
421             errorMessage = "Manning\'s roughness must be set greater than zero.";
422             return false;
423         }
424 
425         if (isNaN(manningRoughness))
426         {
427             errorMessage = "Manning\'s roughness must be numeric.";
428             return false;
429         }
430 
431         // errorMessage = "Valid manning's rougness. Calculation successful.";
432         return true;
433     }
434 
435     /**
436     * Bed slope error checking
437     */
438     protected bool isValidBedSlope(Unknown u)
439     {
440         if (isNaN(bedSlope) && u != Unknown.BED_SLOPE)
441         {
442             errorMessage = "Bed slope must be numeric.";
443             return false;
444         }
445 
446         if (bedSlope <= 0.0 && u != Unknown.BED_SLOPE)
447         {
448             errorMessage = "Bed slope must be set greater than zero.";
449             return false;
450         }
451 
452         // errorMessage = "Valid bed slope. Calculation successful.";
453         return true;
454     }
455 
456     /**
457     *   Water depth error checking
458     */
459     protected bool isValidWaterDepth(Unknown u)
460     {
461         if (isNaN(waterDepth) && u != Unknown.WATER_DEPTH)
462         {
463             errorMessage = "Water depth must be set to numeric.";
464             return false;
465         }
466 
467         if (waterDepth <= 0.0 && u != Unknown.WATER_DEPTH)
468         {
469             errorMessage = "Water depth must be set greater than or equal to zero.";
470             return false;
471         }
472 
473         // errorMessage = "Valid water depth. Calculation successful.";
474         return true;
475     }
476 
477     /**
478      Discharge error checking.
479     */
480     protected bool isValidDischarge(Unknown u)
481     {
482         if (isNaN(discharge) && u != Unknown.DISCHARGE)
483         {
484             errorMessage = "Discharge must be numeric.";
485             return false;
486         }
487 
488         if (discharge < 0 && u != Unknown.DISCHARGE)
489         {
490             errorMessage = "Discharge must be set greater than zero.";
491             return false;
492         }
493 
494         // errorMessage = "Valid discharge. Calculation successful.";
495         return true;
496     }
497 
498     /// Check if all conditions are true
499     protected bool isValidInputs(A...)(A a)
500     {
501         bool res = true;
502         foreach (b; a)
503         {
504             res = res && b;
505         }
506 
507         if (res)
508             errorMessage = "Calculation successful.";
509         return res;
510     }
511 
512 }