1 /**
2     libs.weirs.sharpcrested module
3     Module for hydraulic analysis of sharp crested weirs used in diversion dams.
4 */
5 module libs.weirs.broadcrested;
6 
7 import libs.weirs.weir;
8 import libs.utils.constants;
9 import libs.utils.hydraulics;
10 import libs.utils.geometry_calculators;
11 
12 import std.math: abs, pow, sqrt, isNaN;
13 import std.stdio;
14 
15 /**
16     SharpCrestedWeir class.
17     Contains fields and methods for hydraulic calculations
18     of sharp crested weirs.
19 */
20 class BroadCrestedWeir : Weir
21 {
22     ///////////////////////////////////////
23     //  Properties                       //
24     ///////////////////////////////////////
25 
26     double dA,              // Depth at approach
27             vA,             // Velocity at approach
28             hA,             // Height at approach
29             eE,             // Energy elevation
30             ho,             
31             h1,
32             h2,
33             h2_h1,
34             co,
35             correction,
36             cs;
37     
38     /**
39         Empty constructor.
40     */
41     this()
42     {
43 
44     }
45 
46     //++++++++++++++++++++++++++++++++++++++++++++++
47     //                  Methods                    +
48     //+++++++++++++++++++++++++++++++++++++++++++++/
49 
50     /**
51         Performs the hydraulic analysis for sharp-crested (gated) weirs/diversion dams.
52     */
53     bool analysis()
54     {
55         if (!isValidInputs) 
56         {
57             return false;
58         }
59 
60         // Reset values
61         TRIAL_INCREMENT = 0.0001;
62         calculatedDischargeIntensity = 0;
63 
64         dischargeIntensity = discharge / crestLength;
65 
66         // Afflux elevation initial assumption
67         affluxElevation = crestElev > tailwaterElev ? crestElev : tailwaterElev;
68 
69         // Accuracy closure
70         const allowedDiff = discharge * ERROR;
71 
72         // Calculation for the afflux elevation
73         while (abs(dischargeIntensity - calculatedDischargeIntensity) > allowedDiff) 
74         {
75             affluxElevation += TRIAL_INCREMENT;
76             dA = affluxElevation - usApronElev;
77             vA = dischargeIntensity / dA;
78             hA = velocityHead(vA);
79             eE = affluxElevation + hA;
80             ho = eE - crestElev;
81             co = 3.087;
82             h1 = affluxElevation - crestElev;
83             h2 = tailwaterElev - crestElev;
84             h2_h1 = h2 / h1;
85             if (h2 <= 0)
86             {
87                 correction = 1;
88             }
89             else
90             {
91                 // correction = pow((1 - pow(h2_h1, (3.0/2.0))), 0.385);
92                 // APply correction for broad crested weirs
93                 correction = broadCrestedWeirCorrection(h2_h1);
94             }
95             cs = co * correction;
96             calculatedDischargeIntensity = cs / 1.811 * pow(ho, (3.0 / 2.0));
97 
98             // My root-finding acceleration
99             if (calculatedDischargeIntensity < dischargeIntensity)
100             {
101                 TRIAL_INCREMENT *= 2.1;
102             }
103             else
104             {
105                 affluxElevation -= TRIAL_INCREMENT;
106                 TRIAL_INCREMENT *= 0.75;
107             }
108             // End of root finding acceleration
109         }
110 
111         // Calculation for the hydraulic jump
112         double d1,                      // Pre-jump height
113                 d2,                     // Hydraulic jump height
114                 he,
115                 he2 = 0,                // Pre-jump height to energy grade elevation
116                 v1,
117                 hv1;
118         float f;                        // Froude number
119         
120         TRIAL_INCREMENT = 0.0001;       // Reset
121         d1 = 0;
122         he = eE - dsApronElev;
123 
124         // Froude number calculation
125         // Hydraulic jump calculation
126         while (abs(he - he2) > ERROR)
127         {
128             d1 += TRIAL_INCREMENT;
129             v1 = dischargeIntensity / d1;
130             hv1 = velocityHead(v1);
131             he2 = d1 + hv1;
132             d2 = (-1 * d1 / 2) + sqrt((pow(d1, 2) / 4.0) + (2 * pow(v1, 2) * d1 / GRAVITY));
133             f = v1 / sqrt(d1 * GRAVITY);
134         }
135 
136         // Length of hydraulic jump
137         if (f < 1.6)
138         {
139             lengthOfHydraulicJump = 4 * d2;
140         } else {
141             lengthOfHydraulicJump = hydraulicJump(f);
142         }
143 
144         preJumpElev = dsApronElev + d1;
145         jumpElev = dsApronElev + d2;
146 
147         errorMessage = "Calculation successful.";
148         return true;
149     }
150 
151     private bool isValidInputs()
152     {
153         // Check for each input
154         if (isNaN(discharge))
155         {
156             errorMessage = "Discharge must be set.";
157             return false;
158         }
159 
160         if (isNaN(crestElev))
161         {
162             errorMessage = "Crest elevation must be set.";
163             return false;
164         }
165 
166         if (isNaN(crestLength))
167         {
168             errorMessage = "Crest length must be set.";
169             return false;
170         }
171 
172         if (isNaN(usApronElev))
173         {
174             errorMessage = "Elevation of upstream apron must be set.";
175             return false;
176         }
177 
178         if (isNaN(dsApronElev))
179         {
180             errorMessage = "Elevation of downstream apron must be set.";
181             return false;
182         }
183 
184         if (isNaN(tailwaterElev))
185         {
186             errorMessage = "Elevation of tail water must be set.";
187             return false;
188         }
189 
190         // Check if tailwater if lower than downstream apron
191         if (tailwaterElev < dsApronElev) 
192         {
193             errorMessage = "Tailwater elevation must be set higher or the same as downstream apron.";
194             return false;
195         }
196 
197         // Check crest is lower than upstream apron
198         if (crestElev < usApronElev)
199         {
200             errorMessage = "Crest elevation must be the same or higher then upstream apron.";
201             return false;
202         }
203 
204         return true;
205     }
206 
207     private double broadCrestedWeirCorrection(double h2_h1)
208     {
209         // hs/hc = []
210         // Cs/C = []
211         double correction = 0;
212         const double[11][2] cs_c = [
213             [
214                 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1
215             ],
216             [
217                 1, 0.991, 0.983, 0.972, 0.956, 0.937, 0.907, 0.856, 0.778, 0.621, 0
218             ]
219         ];
220 
221         for (int i = 0; i < (cs_c.length - 1); i++)
222         {
223             if (h2_h1 >= cs_c[0][i] && h2_h1 < cs_c[0][i+1])
224         {
225             correction = interpolate(cs_c[1][i],
226                                 cs_c[1][i + 1],
227                                 cs_c[0][i],
228                                 h2_h1,
229                                 cs_c[0][i + 1]);
230             }
231         }
232 
233         return correction;
234     }
235 }