15 * |
15 * |
16 * You should have received a copy of the GNU General Public License |
16 * You should have received a copy of the GNU General Public License |
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 */ |
18 */ |
19 |
19 |
|
20 double EditProduct::ResCO2(double T) |
|
21 { |
|
22 double F = T * 1.8 + 32; |
|
23 return round((3.0378 - 0.050062 * F + 0.00026555 * F * F) * 1000000.0) / 1000000.0; |
|
24 } |
|
25 |
|
26 |
|
27 double EditProduct::CarbCO2toS(double CO2, double T, double SFactor) |
|
28 { |
|
29 //var sugar = SFactor * (CO2 - ResCO2(CO2, T)) / 0.286; |
|
30 double sugar = round((SFactor * (CO2 - ResCO2(T)) * 4.014094) * 1000000.0) / 1000000.0; |
|
31 if (sugar < 0) |
|
32 sugar = 0; |
|
33 return sugar; //Round(sugar, 3); |
|
34 } |
|
35 |
|
36 |
|
37 double EditProduct::GetPressure(double CO2, double T1, double T2) |
|
38 { |
|
39 double V = CO2 - ResCO2(T1); |
|
40 V = CO2; // TODO: temp only total pressure, testing |
|
41 if (V < 0) |
|
42 return 0; |
|
43 |
|
44 double P = -1.09145427669121 + 0.00800006989646477 * T2 + 0.000260276315484684 * T2 * T2 + 0.0215142075945119 * T2 * V + |
|
45 0.674996600795854 * V + -0.00471757220150754 * V * V; |
|
46 if (P < 0) |
|
47 P = 0; |
|
48 P = round((P * 1.01325) * 100.0) / 100.0; // atm to bar |
|
49 qDebug() << " GetPressure(" << CO2 << "," << T1 << "," << T2 << ") V:" << V << "Bar:" << P << "ignored ResCO2:" << ResCO2(T1); |
|
50 return P; |
|
51 } |
|
52 |
|
53 |
|
54 double EditProduct::CarbCO2ToPressure(double CO2, double T) |
|
55 { |
|
56 return (CO2 - (-0.000005594056 * pow(T, 4) + 0.000144357886 * pow(T, 3) + |
|
57 0.000362999168 * T * T - 0.064872987645 * T + 1.641145175049)) / |
|
58 (0.00000498031 * pow(T, 4) - 0.00024358267 * pow(T, 3) + 0.00385867329 * T * T - 0.05671206825 * T + 1.53801423376); |
|
59 } |
|
60 |
20 |
61 |
21 void EditProduct::calcPack() |
62 void EditProduct::calcPack() |
22 { |
63 { |
23 // qDebug() << "calcPack()" << product->package_volume << product->package_abv << "inf" << product->package_infuse_amount << product->package_infuse_abv; |
64 int i, j; |
|
65 bool found1, found2; |
|
66 QSqlQuery query; |
|
67 double TSec, SFactor; |
|
68 |
|
69 qDebug() << "calcPack()" << product->package_volume << product->package_abv << "inf" << product->package_infuse_amount << product->package_infuse_abv; |
|
70 |
|
71 if (product->package_volume < 1) { |
|
72 /* |
|
73 * If there is not enough to package, then don't |
|
74 * do any calculations and clear the rest of the form. |
|
75 */ |
|
76 product->package_volume = 0; |
|
77 ui->pack_finalabvShow->setValue(0); |
|
78 |
|
79 return; |
|
80 } |
24 |
81 |
25 double bvol = product->package_volume - (product->package_abv * product->package_volume) / 100.0; |
82 double bvol = product->package_volume - (product->package_abv * product->package_volume) / 100.0; |
26 double balc = product->package_volume - bvol; |
83 double balc = product->package_volume - bvol; |
27 double mvol = product->package_infuse_amount - (product->package_infuse_abv * product->package_infuse_amount) / 100.0; |
84 double mvol = product->package_infuse_amount - (product->package_infuse_abv * product->package_infuse_amount) / 100.0; |
28 double malc = product->package_infuse_amount - mvol; |
85 double malc = product->package_infuse_amount - mvol; |
29 double talc = balc + malc; |
86 double talc = balc + malc; |
30 double tvol = bvol + mvol; |
87 double tvol = bvol + mvol; |
31 |
88 |
32 product->final_abv = round(talc / (tvol + talc) * 10000.0) / 100.0; |
89 product->final_abv = round(talc / (tvol + talc) * 10000.0) / 100.0; |
33 ui->pack_finalabvShow->setValue(product->final_abv); |
90 ui->pack_finalabvShow->setValue(product->final_abv); |
|
91 |
|
92 TSec = product->secondary_temp; |
|
93 if (TSec < 1) |
|
94 TSec = product->primary_end_temp; |
|
95 if (TSec < 1) |
|
96 TSec = 18; |
|
97 |
|
98 /* |
|
99 * For bottles and kegs use the following complicated procedure to |
|
100 * find the needed priming sugars. |
|
101 * |
|
102 * 1. If we need a priming sugar then first see in the fermentables |
|
103 * table if there is one selected. If not, clear sugars and done. |
|
104 * 2. Then, we update the data from the fermentables inventory. |
|
105 * 3. Set the found sugar in the pulldown menu. |
|
106 * 4. Calculate the sugar in gr/L and total amount need. |
|
107 * 5. Calculate the ABV in the bottles/kegs. |
|
108 * 6. Calculate the pressure build by the refermentation. |
|
109 * |
|
110 * Note that this is all a leftover from the web based application that |
|
111 * did work like this. It's a bit strange but it will allways give |
|
112 * the right data and sugar concentrations. |
|
113 * Sometimes bugs have good things. |
|
114 */ |
|
115 found1 = false; |
|
116 if (product->bottle_amount) { |
|
117 for (i = 0; i < product->fermentables.size(); i++) { |
|
118 if (product->fermentables.at(i).f_added == FERMENTABLE_ADDED_BOTTLE) { |
|
119 found1 = true; |
|
120 break; |
|
121 } |
|
122 } |
|
123 if (found1) { |
|
124 SFactor = 1 / ((product->fermentables.at(i).f_yield / 100) * (1 - product->fermentables.at(i).f_moisture / 100)); |
|
125 qDebug() << " bottle sugar" << product->fermentables.at(i).f_name << SFactor << TSec; |
|
126 |
|
127 query.prepare("SELECT name,supplier FROM inventory_fermentables WHERE type = '1' OR type = '3' ORDER BY name"); // Sugars or dry extract |
|
128 query.exec(); |
|
129 j = 0; |
|
130 found2 = false; |
|
131 while (query.next()) { |
|
132 j++; |
|
133 if (query.value(0).toString() == product->fermentables.at(i).f_name && query.value(1).toString() == product->fermentables.at(i).f_supplier) { |
|
134 ui->bottle_sugarEdit->setCurrentIndex(j); |
|
135 product->bottle_priming_sugar = j; |
|
136 found2 = true; |
|
137 break; |
|
138 } |
|
139 } |
|
140 if (! found2) { |
|
141 ui->bottle_sugarEdit->setCurrentIndex(0); // Make sure not selected |
|
142 product->fermentables.removeAt(i); // Remove false fermentable |
|
143 refreshFermentables(); |
|
144 } else { |
|
145 product->bottle_priming_amount = CarbCO2toS(product->bottle_carbonation, TSec, SFactor); |
|
146 ui->bottle_sug_amountShow->setValue(product->bottle_priming_amount); |
|
147 double total = round(product->bottle_priming_amount * product->bottle_amount * 100.0) / 100000.0; |
|
148 qDebug() << " total" << total << product->fermentables.at(i).f_amount; |
|
149 if (total != product->fermentables.at(i).f_amount) { |
|
150 qDebug() << " update priming sugar" << total; |
|
151 product->fermentables[i].f_amount = total; |
|
152 refreshFermentables(); |
|
153 ui->bottle_sug_weightShow->setValue(total * 1000); |
|
154 is_changed(); |
|
155 } |
|
156 |
|
157 double pabv = product->final_abv + product->bottle_priming_amount * 0.47 / 7.907; |
|
158 double pvol = product->bottle_amount - (pabv * product->bottle_amount) / 100; |
|
159 talc = product->bottle_amount - pvol; |
|
160 tvol = pvol + product->bottle_priming_water; |
|
161 ui->bottle_abvShow->setValue(talc / (tvol + talc) * 100); |
|
162 ui->bottle_barShow->setValue(GetPressure(product->bottle_carbonation, TSec, product->bottle_carbonation_temp)); |
|
163 } |
|
164 } |
|
165 } |
|
166 if (! found1) { |
|
167 qDebug() << " no bottle priming"; |
|
168 ui->bottle_sug_amountShow->setValue(0); |
|
169 ui->bottle_sug_weightShow->setValue(0); |
|
170 ui->bottle_abvShow->setValue(0); |
|
171 ui->bottle_barShow->setValue(0); |
|
172 } |
|
173 |
|
174 // keg_amount keg_carbonation keg_priming_sugar keg_priming_amount keg_priming_water keg_carbonation_temp keg_forced_carb keg_pressure |
34 } |
175 } |
35 |
176 |
36 |
177 |
37 /* |
178 /* |
38 * Triggered by writing to ui->pack_abvShow |
179 * Triggered by writing to ui->pack_abvShow |