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