src/EditProductTab8.cpp

changeset 359
dfbb012c631c
parent 350
37b3c690b02c
child 361
ec8de79f6ff6
equal deleted inserted replaced
358:d89bc21e2f07 359:dfbb012c631c
159 int AT; 159 int AT;
160 160
161 qDebug() << "calcWater()"; 161 qDebug() << "calcWater()";
162 162
163 ui->w1_hardnessEdit->setValue(Utils::Hardness(product->w1_calcium, product->w1_magnesium)); 163 ui->w1_hardnessEdit->setValue(Utils::Hardness(product->w1_calcium, product->w1_magnesium));
164 ui->w1_raEdit->setValue(Utils::RA_ppm(product->w1_total_alkalinity, product->w1_calcium, product->w1_magnesium)); 164 ui->w1_raEdit->setValue(Utils::ResidualAlkalinity(product->w1_total_alkalinity, product->w1_calcium, product->w1_magnesium));
165 165
166 /* 166 /*
167 * If there is a dilute water source, mix the waters. 167 * If there is a dilute water source, mix the waters.
168 */ 168 */
169 if (product->w2_name != "") { 169 if (product->w2_name != "") {
174 chloride = Utils::mix(product->w1_amount, product->w2_amount, product->w1_chloride, product->w2_chloride); 174 chloride = Utils::mix(product->w1_amount, product->w2_amount, product->w1_chloride, product->w2_chloride);
175 sulfate = Utils::mix(product->w1_amount, product->w2_amount, product->w1_sulfate, product->w2_sulfate); 175 sulfate = Utils::mix(product->w1_amount, product->w2_amount, product->w1_sulfate, product->w2_sulfate);
176 total_alkalinity = Utils::mix(product->w1_amount, product->w2_amount, product->w1_total_alkalinity, product->w2_total_alkalinity); 176 total_alkalinity = Utils::mix(product->w1_amount, product->w2_amount, product->w1_total_alkalinity, product->w2_total_alkalinity);
177 ph = -log10(((pow(10, -product->w1_ph) * product->w1_amount) + (pow(10, -product->w2_ph) * product->w2_amount)) / liters); 177 ph = -log10(((pow(10, -product->w1_ph) * product->w1_amount) + (pow(10, -product->w2_ph) * product->w2_amount)) / liters);
178 ui->w2_hardnessEdit->setValue(Utils::Hardness(product->w2_calcium, product->w2_magnesium)); 178 ui->w2_hardnessEdit->setValue(Utils::Hardness(product->w2_calcium, product->w2_magnesium));
179 ui->w2_raEdit->setValue(Utils::RA_ppm(product->w2_total_alkalinity, product->w2_calcium, product->w2_magnesium)); 179 ui->w2_raEdit->setValue(Utils::ResidualAlkalinity(product->w2_total_alkalinity, product->w2_calcium, product->w2_magnesium));
180 } else { 180 } else {
181 liters = product->w1_amount; 181 liters = product->w1_amount;
182 calcium = product->w1_calcium; 182 calcium = product->w1_calcium;
183 magnesium = product->w1_magnesium; 183 magnesium = product->w1_magnesium;
184 sodium = product->w1_sodium; 184 sodium = product->w1_sodium;
195 product->wg_chloride = round(chloride * 10.0) / 10.0; 195 product->wg_chloride = round(chloride * 10.0) / 10.0;
196 product->wg_sulfate = round(sulfate * 10.0) / 10.0; 196 product->wg_sulfate = round(sulfate * 10.0) / 10.0;
197 product->wg_total_alkalinity = round(total_alkalinity * 10.0) / 10.0; 197 product->wg_total_alkalinity = round(total_alkalinity * 10.0) / 10.0;
198 product->wg_ph = ph; 198 product->wg_ph = ph;
199 199
200 bicarbonate = Utils::Bicarbonate(total_alkalinity, ph);
200 ui->wg_volEdit->setValue(liters); 201 ui->wg_volEdit->setValue(liters);
201 ui->wg_caEdit->setValue(calcium); 202 ui->wg_caEdit->setValue(calcium);
202 ui->wg_mgEdit->setValue(magnesium); 203 ui->wg_mgEdit->setValue(magnesium);
203 ui->wg_hco3Edit->setValue(total_alkalinity * 1.22); 204 ui->wg_hco3Edit->setValue(bicarbonate);
204 ui->wg_caco3Edit->setValue(total_alkalinity); 205 ui->wg_caco3Edit->setValue(total_alkalinity);
205 ui->wg_naEdit->setValue(sodium); 206 ui->wg_naEdit->setValue(sodium);
206 ui->wg_clEdit->setValue(chloride); 207 ui->wg_clEdit->setValue(chloride);
207 ui->wg_so4Edit->setValue(sulfate); 208 ui->wg_so4Edit->setValue(sulfate);
208 ui->wg_phEdit->setValue(ph); 209 ui->wg_phEdit->setValue(ph);
209 ui->wg_hardnessEdit->setValue(Utils::Hardness(calcium, magnesium)); 210 ui->wg_hardnessEdit->setValue(Utils::Hardness(calcium, magnesium));
210 ui->wg_raEdit->setValue(Utils::RA_ppm(total_alkalinity, calcium, magnesium)); 211 ui->wg_raEdit->setValue(Utils::ResidualAlkalinity(total_alkalinity, calcium, magnesium));
211 bicarbonate = total_alkalinity * 1.22;
212 212
213 /* Save mixed water ions for later */ 213 /* Save mixed water ions for later */
214 double wg_calcium = calcium; 214 double wg_calcium = calcium;
215 double wg_sodium = sodium; 215 double wg_sodium = sodium;
216 double wg_total_alkalinity = total_alkalinity; 216 double wg_total_alkalinity = total_alkalinity;
263 Acid = protonDeficit / frac; 263 Acid = protonDeficit / frac;
264 Acid *= my_acids[AT].MolWt; // mg. 264 Acid *= my_acids[AT].MolWt; // mg.
265 Acidmg = Acid; 265 Acidmg = Acid;
266 Acid = Acid / my_acids[AT].AcidSG; 266 Acid = Acid / my_acids[AT].AcidSG;
267 Acid = round((Acid / (product->wa_acid_perc / 100.0)) * 100.0) / 100.0; 267 Acid = round((Acid / (product->wa_acid_perc / 100.0)) * 100.0) / 100.0;
268 qDebug() << " Mash auto Acid final old ml:" << Acid;
269 Acid = Acidmg;
270
271 double RealSG = round(((my_acids[AT].AcidSG - 1000) * (product->wa_acid_perc / 100)) + 1000);
272 Acid /= RealSG;
273 Acid /= my_acids[AT].AcidPrc / 100;
274 Acid = round(Acid * 100.0) / 100.0;
268 qDebug() << " Mash auto Acid final ml:" << Acid; 275 qDebug() << " Mash auto Acid final ml:" << Acid;
269 276
270 QString w = my_acids[AT].name_en + ' ' + my_acids[AT].name_nl; 277 QString w = my_acids[AT].name_en + ' ' + my_acids[AT].name_nl;
271 brewing_salt_sub(w, Acid); 278 brewing_salt_sub(w, Acid, MISC_USES_MASH);
272 ui->mw_acidvolEdit->setValue(Acid); 279 ui->mw_acidvolEdit->setValue(Acid);
273 280
274 bicarbonate = bicarbonate - protonDeficit * frac / liters; 281 bicarbonate = bicarbonate - protonDeficit * frac / liters;
275 total_alkalinity = bicarbonate * 50 / 61; 282 total_alkalinity = bicarbonate * 50 / 61;
276 } 283 }
280 } else { // Manual 287 } else { // Manual
281 /* 288 /*
282 * Manual adjust acid, calculate resulting pH. 289 * Manual adjust acid, calculate resulting pH.
283 */ 290 */
284 double pHa = ph; // Mixed water pH. 291 double pHa = ph; // Mixed water pH.
292 double RealSG = round(((my_acids[AT].AcidSG - 1000) * (product->wa_acid_perc / 100)) + 1000);
285 // Then calculate the new pH with added acids and malts 293 // Then calculate the new pH with added acids and malts
286 qDebug() << " Mash pH:" << pHa; 294 qDebug() << " Mash pH:" << pHa;
287 Acid = my_acids[AT].AcidSG * (product->wa_acid_perc / 100.0); // ml 295 Acid = RealSG;
288 Acid *= ui->mw_acidvolEdit->value(); 296 Acid *= ui->mw_acidvolEdit->value();
297 Acid *= my_acids[AT].AcidPrc / 100;
289 Acid /= my_acids[AT].MolWt; // mg; 298 Acid /= my_acids[AT].MolWt; // mg;
290 Acidmg = Acid; 299 Acidmg = Acid;
291 300
292 //find the pH where the protondeficit = protondeficit by the acid 301 //find the pH where the protondeficit = protondeficit by the acid
293 frac = Utils::CalcFrac(pHa, my_acids[AT].pK1, my_acids[AT].pK2, my_acids[AT].pK3); 302 frac = Utils::CalcFrac(pHa, my_acids[AT].pK1, my_acids[AT].pK2, my_acids[AT].pK3);
294 protonDeficit = Acid * frac; 303 protonDeficit = Acid * frac;
295 //qDebug() << " protonDeficit Acid:" << protonDeficit << "frac:" << frac << "pH:" << pHa; 304 qDebug() << " Acid:" << Acid << "protonDeficit:" << protonDeficit << "frac:" << frac << "pH:" << pHa;
296 305
297 double deltapH = 0.001; 306 double deltapH = 0.001;
298 double deltapd = 0.1; 307 double deltapd = 0.1;
299 double pd = round(ProtonDeficit(pHa) * 1000000.0) / 1000000.0; 308 double pd = round(ProtonDeficit(pHa) * 1000000.0) / 1000000.0;
300 int n = 0; 309 int n = 0;
306 pHa += deltapH; 315 pHa += deltapH;
307 frac = Utils::CalcFrac(pHa, my_acids[AT].pK1, my_acids[AT].pK2, my_acids[AT].pK3); 316 frac = Utils::CalcFrac(pHa, my_acids[AT].pK1, my_acids[AT].pK2, my_acids[AT].pK3);
308 protonDeficit = Acid * frac; 317 protonDeficit = Acid * frac;
309 pd = ProtonDeficit(pHa); 318 pd = ProtonDeficit(pHa);
310 } 319 }
311 //qDebug() << " n:" << n << "pd:" << pd << "protonDeficit:" << protonDeficit << "frac:" << frac << "pHa:" << pHa; 320 qDebug() << " n:" << n << "pd:" << pd << "protonDeficit:" << protonDeficit << "frac:" << frac << "pHa:" << pHa;
312 321
313 bicarbonate = wg_bicarbonate - protonDeficit * frac / liters; 322 bicarbonate = wg_bicarbonate - protonDeficit * frac / liters;
314 total_alkalinity = bicarbonate * 50 / 61; 323 total_alkalinity = bicarbonate * 50 / 61;
315 ph = pHa; 324 ph = pHa;
316 ui->wb_phEdit->setValue(ph); 325 ui->wb_phEdit->setValue(ph);
381 ui->wb_caco3Edit->setValue(total_alkalinity); 390 ui->wb_caco3Edit->setValue(total_alkalinity);
382 ui->wb_naEdit->setValue(sodium); 391 ui->wb_naEdit->setValue(sodium);
383 ui->wb_clEdit->setValue(chloride); 392 ui->wb_clEdit->setValue(chloride);
384 ui->wb_so4Edit->setValue(sulfate); 393 ui->wb_so4Edit->setValue(sulfate);
385 ui->wb_hardnessEdit->setValue(Utils::Hardness(calcium, magnesium)); 394 ui->wb_hardnessEdit->setValue(Utils::Hardness(calcium, magnesium));
386 ui->wb_raEdit->setValue(Utils::RA_ppm(total_alkalinity, calcium, magnesium)); 395 ui->wb_raEdit->setValue(Utils::ResidualAlkalinity(total_alkalinity, calcium, magnesium));
387 396
388 ui->wb_caEdit->setStyleSheet((calcium < 40 || calcium > 150) ? "background-color: red":"background-color: green"); 397 ui->wb_caEdit->setStyleSheet((calcium < 40 || calcium > 150) ? "background-color: red":"background-color: green");
389 ui->wb_mgEdit->setStyleSheet((magnesium < 5 || magnesium > 40) ? "background-color: red":"background-color: green"); 398 ui->wb_mgEdit->setStyleSheet((magnesium < 5 || magnesium > 40) ? "background-color: red":"background-color: green");
390 ui->wb_naEdit->setStyleSheet((sodium > 150) ? "background-color: red":"background-color: green"); 399 ui->wb_naEdit->setStyleSheet((sodium > 150) ? "background-color: red":"background-color: green");
391 /* 400 /*
418 double Source_pH = product->w1_ph; 427 double Source_pH = product->w1_ph;
419 double Source_alkalinity = product->w1_total_alkalinity; 428 double Source_alkalinity = product->w1_total_alkalinity;
420 429
421 qDebug() << "calcSparge()"; 430 qDebug() << "calcSparge()";
422 431
423 const QSignalBlocker blocker1(ui->sp_sourceEdit); 432 const QSignalBlocker blocker2(ui->w1_spButton);
433 const QSignalBlocker blocker3(ui->w2_spButton);
434 const QSignalBlocker blocker4(ui->wg_spButton);
424 435
425 // Select watersource or fallback to the first source. 436 // Select watersource or fallback to the first source.
426 if (product->sparge_source == 1) { // Source 2 437 if (product->sparge_source == 1) { // Source 2
427 if (product->w2_ph > 0.0 && product->w2_amount > 0) { 438 if (product->w2_ph > 0.0 && product->w2_amount > 0) {
428 Source_pH = product->w2_ph; 439 Source_pH = product->w2_ph;
429 Source_alkalinity = product->w2_total_alkalinity; 440 Source_alkalinity = product->w2_total_alkalinity;
441 ui->sp_caEdit->setValue(product->w2_calcium);
442 ui->sp_mgEdit->setValue(product->w2_magnesium);
443 ui->sp_hco3Edit->setValue(Utils::Bicarbonate(product->w2_total_alkalinity, product->w2_ph));
444 ui->sp_caco3Edit->setValue(product->w2_total_alkalinity);
445 ui->sp_naEdit->setValue(product->w2_sodium);
446 ui->sp_clEdit->setValue(product->w2_chloride);
447 ui->sp_so4Edit->setValue(product->w2_sulfate);
448 ui->sp_phShow->setValue(product->w2_ph);
449 ui->sp_hardnessEdit->setValue(Utils::Hardness(product->w2_calcium, product->w2_magnesium));
450 ui->sp_raEdit->setValue(Utils::ResidualAlkalinity(product->w2_total_alkalinity, product->w2_calcium, product->w2_magnesium));
451 ui->w2_spButton->setChecked(true);
430 } else { 452 } else {
431 product->sparge_source = 0; // Source 1 453 product->sparge_source = 0; // Fallback to source 1
432 ui->sp_sourceEdit->setCurrentIndex(0); 454 ui->w1_spButton->setChecked(true);
433 } 455 }
434 } else if (product->sparge_source == 2) { // Mixed 456 } else if (product->sparge_source == 2) { // Mixed
435 if (product->w2_ph > 0.0 && product->w2_amount > 0) { 457 if (product->w2_ph > 0.0 && product->w2_amount > 0) {
436 Source_pH = product->wg_ph; 458 Source_pH = product->wg_ph;
437 Source_alkalinity = product->wg_total_alkalinity; 459 Source_alkalinity = product->wg_total_alkalinity;
460 ui->sp_caEdit->setValue(product->wg_calcium);
461 ui->sp_mgEdit->setValue(product->wg_magnesium);
462 ui->sp_hco3Edit->setValue(Utils::Bicarbonate(product->wg_total_alkalinity, product->wg_ph));
463 ui->sp_caco3Edit->setValue(product->wg_total_alkalinity);
464 ui->sp_naEdit->setValue(product->wg_sodium);
465 ui->sp_clEdit->setValue(product->wg_chloride);
466 ui->sp_so4Edit->setValue(product->wg_sulfate);
467 ui->sp_phShow->setValue(product->wg_ph);
468 ui->sp_hardnessEdit->setValue(Utils::Hardness(product->wg_calcium, product->wg_magnesium));
469 ui->sp_raEdit->setValue(Utils::ResidualAlkalinity(product->wg_total_alkalinity, product->wg_calcium, product->wg_magnesium));
470 ui->wg_spButton->setChecked(true);
438 } else { 471 } else {
439 product->sparge_source = 0; // Source 1 472 product->sparge_source = 0; // Fallback to source 1
440 ui->sp_sourceEdit->setCurrentIndex(0); 473 ui->w1_spButton->setChecked(true);
441 } 474 }
442 } 475 }
443 476 if (product->sparge_source == 0) {
444 // Step 1: Compute the mole fractions of carbonic (f1o), bicarbonate (f2o) and carbonate(f3o) at the water pH 477 ui->sp_caEdit->setValue(product->w1_calcium);
445 double r1 = pow(10, Source_pH - 6.35); 478 ui->sp_mgEdit->setValue(product->w1_magnesium);
446 double r2 = pow(10, Source_pH - 10.33); 479 ui->sp_hco3Edit->setValue(Utils::Bicarbonate(product->w1_total_alkalinity, product->w1_ph));
447 double d = 1 + r1 + r1 * r2; 480 ui->sp_caco3Edit->setValue(product->w1_total_alkalinity);
448 double f1 = 1 / d; 481 ui->sp_naEdit->setValue(product->w1_sodium);
449 double f3 = r1 * r2 / d; 482 ui->sp_clEdit->setValue(product->w1_chloride);
450 483 ui->sp_so4Edit->setValue(product->w1_sulfate);
451 // Step 2. Compute the mole fractions at pH = 4.3 (the pH which defines alkalinity) 484 ui->sp_phShow->setValue(product->w1_ph);
452 double r143 = pow(10, 4.3 - 6.35); 485 ui->sp_hardnessEdit->setValue(Utils::Hardness(product->w1_calcium, product->w1_magnesium));
453 double r243 = pow(10, 4.3 - 10.33); 486 ui->sp_raEdit->setValue(Utils::ResidualAlkalinity(product->w1_total_alkalinity, product->w1_calcium, product->w1_magnesium));
454 double d43 = 1 + r143 + r143 * r243; 487 ui->w1_spButton->setChecked(true);
455 double f143 = 1 / d43; 488 }
456 double f343 = r143 * r243 / d43; 489 // The spargewater is set.
457 490
458 // Step 4. Solve
459 //double Ct = (Source_alkalinity - 1000 * (pow(10, -4.3) - pow(10, -Source_pH))) / ((f143 - f1) + (f3 - f343));
460 double Ct = Source_alkalinity / 50 / ((f143 - f1) + (f3 - f343));
461
462 // Step 5. Compute mole fractions at desired pH
463 double r1g = pow(10, TargetpH - 6.35);
464 double r2g = pow(10, TargetpH - 10.33);
465 double dg = 1 + r1g + r1g * r2g;
466 double f1g = 1 / dg;
467 double f3g = r1g * r2g / dg;
468
469 // Step 6. Use these to compute the milliequivalents acid required per liter (mEq/L)
470 double Acid = Ct * ((f1g - f1) + (f3 - f3g)) + pow(10, -TargetpH) - pow(10, -Source_pH); //mEq/l
471 Acid += 0.01; // Add acid that would be required for distilled water.
472
473 //Step 8. Get the acid data.
474 int AT = product->sparge_acid_type; 491 int AT = product->sparge_acid_type;
475 if (AT < 0 || AT >= my_acids.size()) { 492 if (AT < 0 || AT >= my_acids.size()) {
476 AT = 0; 493 AT = 0;
477 product->sparge_acid_type = 0; 494 product->sparge_acid_type = 0;
478 ui->sp_acidtypeEdit->setCurrentIndex(0); 495 ui->sp_acidtypeEdit->setCurrentIndex(0);
479 product->sparge_acid_perc = my_acids[0].AcidPrc; 496 product->sparge_acid_perc = my_acids[0].AcidPrc;
480 ui->sp_acidpercEdit->setValue(product->sparge_acid_perc); 497 ui->sp_acidpercEdit->setValue(product->sparge_acid_perc);
481 } 498 }
482 double fract = Utils::CalcFrac(TargetpH, my_acids[AT].pK1, my_acids[AT].pK2, my_acids[AT].pK3); 499
483 500 /*
484 // Step 9. Now divide the mEq required by the "fraction". This is the required number of moles of acid. 501 * Auto calculate the required acid
485 Acid /= fract; 502 */
486 503 if (product->calc_acid) {
487 // Step 10. Multiply by molecular weight of the acid 504 // Step 1: Compute the mole fractions of carbonic (f1o), bicarbonate (f2o) and carbonate(f3o) at the water pH
488 Acid *= my_acids[AT].MolWt; //mg 505 double r1 = pow(10, Source_pH - 6.35);
489 506 double r2 = pow(10, Source_pH - 10.33);
490 // Step 11. Divide by Specific Gravity and Percentage to get the final ml. 507 double d = 1 + r1 + r1 * r2;
491 Acid = Acid / my_acids[AT].AcidSG / (product->sparge_acid_perc / 100); //ml 508 double f1 = 1 / d;
492 Acid *= product->sparge_volume; //ml acid total 509 double f3 = r1 * r2 / d;
493 Acid = round(Acid * 100.0) / 100.0; 510
494 product->sparge_acid_amount = Acid / 1000; 511 // Step 2. Compute the mole fractions at pH = 4.3 (the pH which defines alkalinity)
495 ui->sp_acidvolEdit->setValue(Acid); 512 double r143 = pow(10, 4.3 - 6.35);
496 513 double r243 = pow(10, 4.3 - 10.33);
514 double d43 = 1 + r143 + r143 * r243;
515 double f143 = 1 / d43;
516 double f343 = r143 * r243 / d43;
517
518 // Step 4. Solve
519 double Ct = Source_alkalinity / 50 / ((f143 - f1) + (f3 - f343));
520
521 // Step 5. Compute mole fractions at desired pH
522 double r1g = pow(10, TargetpH - 6.35);
523 double r2g = pow(10, TargetpH - 10.33);
524 double dg = 1 + r1g + r1g * r2g;
525 double f1g = 1 / dg;
526 double f3g = r1g * r2g / dg;
527
528 // Step 6. Use these to compute the milliequivalents acid required per liter (mEq/L)
529 double Acid = Ct * ((f1g - f1) + (f3 - f3g)) + pow(10, -TargetpH) - pow(10, -Source_pH); //mEq/l
530 Acid += 0.01; // Add acid that would be required for distilled water.
531
532 // Step 7. There is no step 7.
533
534 // Step 8. Get the acid data.
535 double fract = Utils::CalcFrac(TargetpH, my_acids[AT].pK1, my_acids[AT].pK2, my_acids[AT].pK3);
536
537 // Step 9. Now divide the mEq required by the "fraction". This is the required number of moles of acid.
538 Acid /= fract;
539
540 // Step 10. Multiply by molecular weight of the acid
541 Acid *= my_acids[AT].MolWt; //mg
542
543 // Step 11. Divide by Specific Gravity and Percentage to get the final ml.
544 double RealSG = round(((my_acids[AT].AcidSG - 1000) * (product->sparge_acid_perc / 100)) + 1000);
545 Acid = Acid / RealSG; //ml
546 Acid *= product->sparge_volume; //ml acid total at 100%
547 Acid /= my_acids[AT].AcidPrc / 100; //ml acid at supplied strength
548 Acid = round(Acid * 100.0) / 100.0;
549 product->sparge_acid_amount = Acid / 1000;
550 QString w = my_acids[AT].name_en + ' ' + my_acids[AT].name_nl;
551 brewing_salt_sub(w, Acid, MISC_USES_SPARGE); // Put it in the miscs table.
552 ui->sp_acidvolEdit->setValue(Acid);
553 }
554
555 ui->sp_phShow->setValue(product->sparge_ph);
497 // Finally calculate the estimate preboil pH 556 // Finally calculate the estimate preboil pH
498 product->est_preboil_ph = -log10(((pow(10, -product->mash_ph) * product->wg_amount) + (pow(10, -product->sparge_ph) * product->brew_sparge_est)) / 557 product->est_preboil_ph = -log10(((pow(10, -product->mash_ph) * product->wg_amount) + (pow(10, -product->sparge_ph) * product->brew_sparge_est)) /
499 (product->wg_amount + product->brew_sparge_est)); 558 (product->wg_amount + product->brew_sparge_est));
500 ui->preboil_phEdit->setValue(product->est_preboil_ph); 559 ui->preboil_phEdit->setValue(product->est_preboil_ph);
501 ui->brew_preboilphShow->setValue(product->est_preboil_ph); 560 ui->brew_preboilphShow->setValue(product->est_preboil_ph);
502 } 561 }
503 562
504 563
505 void EditProduct::sp_source_changed(int val) 564 void EditProduct::sp_group_changed(int val)
506 { 565 {
507 product->sparge_source = val; 566 if (val != product->sparge_source) {
508 calcSparge(); 567 product->sparge_source = val;
509 is_changed(); 568 calcSparge();
569 is_changed();
570 }
510 } 571 }
511 572
512 573
513 void EditProduct::sp_volume_changed(double val) 574 void EditProduct::sp_volume_changed(double val)
514 { 575 {
520 581
521 582
522 void EditProduct::sp_temp_changed(double val) 583 void EditProduct::sp_temp_changed(double val)
523 { 584 {
524 product->sparge_temp = val; 585 product->sparge_temp = val;
525 ui->brew_spargetempShow->setValue(val);
526 calcSparge(); 586 calcSparge();
527 is_changed(); 587 is_changed();
528 } 588 }
529 589
530 590
531 void EditProduct::sp_type_changed(int val) 591 void EditProduct::sp_type_changed(int val)
532 { 592 {
593 if (val == product->sparge_acid_type)
594 return;
595
596 qDebug() << "sp_type_changed" << val << "old" << product->sparge_acid_type;
597 /*
598 * First remove current acid.
599 */
600 QString w = my_acids[product->sparge_acid_type].name_en + ' ' + my_acids[product->sparge_acid_type].name_nl;
601 brewing_salt_sub(w, 0, MISC_USES_SPARGE);
602
533 product->sparge_acid_type = val; 603 product->sparge_acid_type = val;
604 w = my_acids[product->sparge_acid_type].name_en + ' ' + my_acids[product->sparge_acid_type].name_nl;
605
534 product->sparge_acid_perc = my_acids[val].AcidPrc; 606 product->sparge_acid_perc = my_acids[val].AcidPrc;
535 ui->sp_acidpercEdit->setValue(product->sparge_acid_perc); 607 ui->sp_acidpercEdit->setValue(product->sparge_acid_perc);
608 brewing_salt_sub(w, ui->sp_acidvolEdit->value(), MISC_USES_SPARGE); // For now, set old amount.
609
536 calcSparge(); 610 calcSparge();
537 is_changed(); 611 is_changed();
538 } 612 }
539 613
540 614
542 { 616 {
543 product->sparge_ph = val; 617 product->sparge_ph = val;
544 ui->brew_spargephShow->setValue(product->sparge_ph); 618 ui->brew_spargephShow->setValue(product->sparge_ph);
545 calcSparge(); 619 calcSparge();
546 is_changed(); 620 is_changed();
621 }
622
623
624 void EditProduct::sp_acid_changed(double val)
625 {
626 if (product->calc_acid)
627 return;
628
629 qDebug() << "sp_acid_changed" << val << product->sparge_acid_amount * 1000.0;
630
631 double TargetpH = product->sparge_ph;
632 double Source_pH = product->w1_ph;
633 double Source_alkalinity = product->w1_total_alkalinity;
634
635 if (product->sparge_source == 1) { // Source 2
636 if (product->w2_ph > 0.0 && product->w2_amount > 0) {
637 Source_pH = product->w2_ph;
638 Source_alkalinity = product->w2_total_alkalinity;
639 }
640 } else if (product->sparge_source == 2) { // Mixed
641 if (product->w2_ph > 0.0 && product->w2_amount > 0) {
642 Source_pH = product->wg_ph;
643 Source_alkalinity = product->wg_total_alkalinity;
644 }
645 }
646
647 int AT = product->sparge_acid_type;
648 if (AT < 0 || AT >= my_acids.size()) {
649 AT = 0;
650 product->sparge_acid_type = 0;
651 ui->sp_acidtypeEdit->setCurrentIndex(0);
652 product->sparge_acid_perc = my_acids[0].AcidPrc;
653 ui->sp_acidpercEdit->setValue(product->sparge_acid_perc);
654 }
655
656 bool go_up = (val < (product->sparge_acid_amount * 1000.0));
657 bool loop = true;
658
659 while (loop) {
660
661 if (go_up)
662 TargetpH += 0.001;
663 else
664 TargetpH -= 0.001;
665 //qDebug() << " TargetpH" << TargetpH << "up" << go_up;
666
667 // Step 1: Compute the mole fractions of carbonic (f1o), bicarbonate (f2o) and carbonate(f3o) at the water pH
668 double r1 = pow(10, Source_pH - 6.35);
669 double r2 = pow(10, Source_pH - 10.33);
670 double d = 1 + r1 + r1 * r2;
671 double f1 = 1 / d;
672 double f3 = r1 * r2 / d;
673
674 // Step 2. Compute the mole fractions at pH = 4.3 (the pH which defines alkalinity)
675 double r143 = pow(10, 4.3 - 6.35);
676 double r243 = pow(10, 4.3 - 10.33);
677 double d43 = 1 + r143 + r143 * r243;
678 double f143 = 1 / d43;
679 double f343 = r143 * r243 / d43;
680
681 // Step 4. Solve
682 double Ct = Source_alkalinity / 50 / ((f143 - f1) + (f3 - f343));
683
684 // Step 5. Compute mole fractions at desired pH
685 double r1g = pow(10, TargetpH - 6.35);
686 double r2g = pow(10, TargetpH - 10.33);
687 double dg = 1 + r1g + r1g * r2g;
688 double f1g = 1 / dg;
689 double f3g = r1g * r2g / dg;
690
691 // Step 6. Use these to compute the milliequivalents acid required per liter (mEq/L)
692 double Acid = Ct * ((f1g - f1) + (f3 - f3g)) + pow(10, -TargetpH) - pow(10, -Source_pH); //mEq/l
693 Acid += 0.01; // Add acid that would be required for distilled water.
694
695 // Step 7. There is no step 7.
696
697 // Step 8. Get the acid data.
698 double fract = Utils::CalcFrac(TargetpH, my_acids[AT].pK1, my_acids[AT].pK2, my_acids[AT].pK3);
699
700 // Step 9. Now divide the mEq required by the "fraction". This is the required number of moles of acid.
701 Acid /= fract;
702
703 // Step 10. Multiply by molecular weight of the acid
704 Acid *= my_acids[AT].MolWt; //mg
705
706 // Step 11. Divide by Specific Gravity and Percentage to get the final ml.
707 double RealSG = round(((my_acids[AT].AcidSG - 1000) * (product->sparge_acid_perc / 100)) + 1000);
708 Acid = Acid / RealSG; //ml
709 Acid *= product->sparge_volume; //ml acid total at 100%
710 Acid /= my_acids[AT].AcidPrc / 100; //ml acid at supplied strength
711 Acid = round(Acid * 100.0) / 100.0;
712 product->sparge_acid_amount = Acid / 1000;
713 //qDebug() << " acid" << product->sparge_acid_amount;
714
715 if (go_up && (val > (product->sparge_acid_amount * 1000.0)))
716 loop = false;
717 else if (! go_up && (val < (product->sparge_acid_amount * 1000.0)))
718 loop = false;
719
720 //qDebug() << " test" << loop << go_up << val << product->sparge_acid_amount * 1000.0;
721 }
722
723 const QSignalBlocker blocker1(ui->sp_phEdit);
724 product->sparge_ph = round(TargetpH * 100) / 100;
725 ui->sp_phEdit->setValue(product->sparge_ph);
726 ui->sp_phShow->setValue(product->sparge_ph);
727
728 QString w = my_acids[AT].name_en + ' ' + my_acids[AT].name_nl;
729 set_brewing_salt(w, val, MISC_USES_SPARGE);
730 //qDebug() << " new" << product->sparge_ph << val;
547 } 731 }
548 732
549 733
550 double EditProduct::GetBUGU() 734 double EditProduct::GetBUGU()
551 { 735 {
573 ui->mw_autoEdit->setChecked(product->calc_acid); 757 ui->mw_autoEdit->setChecked(product->calc_acid);
574 ui->mw_phEdit->setReadOnly(! product->calc_acid); 758 ui->mw_phEdit->setReadOnly(! product->calc_acid);
575 ui->mw_phEdit->setButtonSymbols(product->calc_acid ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons); 759 ui->mw_phEdit->setButtonSymbols(product->calc_acid ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
576 ui->mw_acidvolEdit->setReadOnly(product->calc_acid); 760 ui->mw_acidvolEdit->setReadOnly(product->calc_acid);
577 ui->mw_acidvolEdit->setButtonSymbols(product->calc_acid ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows); 761 ui->mw_acidvolEdit->setButtonSymbols(product->calc_acid ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
762 ui->sp_phEdit->setReadOnly(! product->calc_acid);
763 ui->sp_phEdit->setButtonSymbols(product->calc_acid ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
764 ui->sp_acidvolEdit->setReadOnly(product->calc_acid);
765 ui->sp_acidvolEdit->setButtonSymbols(product->calc_acid ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
578 is_changed(); 766 is_changed();
579 calcWater(); 767 calcWater();
580 } 768 }
581 769
582 770
599 if (product->calc_acid) 787 if (product->calc_acid)
600 return; 788 return;
601 789
602 qDebug() << "on_mw_acid_changed" << val; 790 qDebug() << "on_mw_acid_changed" << val;
603 QString w = my_acids[product->wa_acid_name].name_en + ' ' + my_acids[product->wa_acid_name].name_nl; 791 QString w = my_acids[product->wa_acid_name].name_en + ' ' + my_acids[product->wa_acid_name].name_nl;
604 set_brewing_salt(w, val); 792 set_brewing_salt(w, val, MISC_USES_MASH);
605 } 793 }
606 794
607 795
608 void EditProduct::mw_type_changed(int val) 796 void EditProduct::mw_type_changed(int val)
609 { 797 {
613 qDebug() << "on_mw_type_changed" << val << "old" << product->wa_acid_name; 801 qDebug() << "on_mw_type_changed" << val << "old" << product->wa_acid_name;
614 /* 802 /*
615 * First remove current acid. 803 * First remove current acid.
616 */ 804 */
617 QString w = my_acids[product->wa_acid_name].name_en + ' ' + my_acids[product->wa_acid_name].name_nl; 805 QString w = my_acids[product->wa_acid_name].name_en + ' ' + my_acids[product->wa_acid_name].name_nl;
618 brewing_salt_sub(w, 0); 806 brewing_salt_sub(w, 0, MISC_USES_MASH);
619 807
620 product->wa_acid_name = val; 808 product->wa_acid_name = val;
621 w = my_acids[product->wa_acid_name].name_en + ' ' + my_acids[product->wa_acid_name].name_nl; 809 w = my_acids[product->wa_acid_name].name_en + ' ' + my_acids[product->wa_acid_name].name_nl;
622 810
623 product->wa_acid_perc = my_acids.at(val).AcidPrc; 811 product->wa_acid_perc = my_acids.at(val).AcidPrc;
624 ui->mw_acidpercEdit->setValue(my_acids.at(val).AcidPrc); 812 ui->mw_acidpercEdit->setValue(my_acids.at(val).AcidPrc);
625 brewing_salt_sub(w, ui->mw_acidvolEdit->value()); // For now, set old amount. 813 brewing_salt_sub(w, ui->mw_acidvolEdit->value(), MISC_USES_MASH); // For now, set old amount.
626 814
627 is_changed(); 815 is_changed();
628 calcWater(); 816 calcWater();
629 } 817 }
630 818
682 if (query.first()) { 870 if (query.first()) {
683 if ((query.value("unlimited_stock").toInt() == 0) && (query.value("inventory").toDouble() < product->w2_amount)) { 871 if ((query.value("unlimited_stock").toInt() == 0) && (query.value("inventory").toDouble() < product->w2_amount)) {
684 product->waters_ok = false; 872 product->waters_ok = false;
685 qDebug() << "w2_amount too low"; 873 qDebug() << "w2_amount too low";
686 } 874 }
875 ui->w2_spButton->setEnabled(true);
876 ui->wg_spButton->setEnabled(true);
687 } 877 }
878 } else {
879 /*
880 * Block selecting sparge water 2 and mixed water.
881 */
882 ui->w2_spButton->setEnabled(false);
883 ui->wg_spButton->setEnabled(false);
884 product->sparge_source = 0; // Only water source 1
688 } 885 }
689 } 886 }
690 887
691 888
692 void EditProduct::w1_name_changed(int val) 889 void EditProduct::w1_name_changed(int val)
720 product->w1_sulfate = query.value("sulfate").toDouble(); 917 product->w1_sulfate = query.value("sulfate").toDouble();
721 product->w1_ph = query.value("ph").toDouble(); 918 product->w1_ph = query.value("ph").toDouble();
722 919
723 ui->w1_caEdit->setValue(product->w1_calcium); 920 ui->w1_caEdit->setValue(product->w1_calcium);
724 ui->w1_mgEdit->setValue(product->w1_magnesium); 921 ui->w1_mgEdit->setValue(product->w1_magnesium);
725 ui->w1_hco3Edit->setValue(product->w1_total_alkalinity * 1.22); 922 ui->w1_hco3Edit->setValue(Utils::Bicarbonate(product->w1_total_alkalinity, product->w1_ph));
726 ui->w1_caco3Edit->setValue(product->w1_total_alkalinity); 923 ui->w1_caco3Edit->setValue(product->w1_total_alkalinity);
727 ui->w1_naEdit->setValue(product->w1_sodium); 924 ui->w1_naEdit->setValue(product->w1_sodium);
728 ui->w1_clEdit->setValue(product->w1_chloride); 925 ui->w1_clEdit->setValue(product->w1_chloride);
729 ui->w1_so4Edit->setValue(product->w1_sulfate); 926 ui->w1_so4Edit->setValue(product->w1_sulfate);
730 ui->w1_phEdit->setValue(product->w1_ph); 927 ui->w1_phEdit->setValue(product->w1_ph);
731 ui->w1_hardnessEdit->setValue(Utils::Hardness(product->w1_calcium, product->w1_magnesium)); 928 ui->w1_hardnessEdit->setValue(Utils::Hardness(product->w1_calcium, product->w1_magnesium));
732 ui->w1_raEdit->setValue(Utils::RA_ppm(product->w1_total_alkalinity, product->w1_calcium, product->w1_magnesium)); 929 ui->w1_raEdit->setValue(Utils::ResidualAlkalinity(product->w1_total_alkalinity, product->w1_calcium, product->w1_magnesium));
733 930
734 check_waters(); 931 check_waters();
735 is_changed(); 932 is_changed();
736 calcWater(); 933 calcWater();
737 } 934 }
772 product->w2_sodium = query.value(7).toDouble(); 969 product->w2_sodium = query.value(7).toDouble();
773 product->w2_chloride = query.value(6).toDouble(); 970 product->w2_chloride = query.value(6).toDouble();
774 product->w2_sulfate = query.value(5).toDouble(); 971 product->w2_sulfate = query.value(5).toDouble();
775 product->w2_ph = query.value(9).toDouble(); 972 product->w2_ph = query.value(9).toDouble();
776 hardness = Utils::Hardness(product->w2_calcium, product->w2_magnesium); 973 hardness = Utils::Hardness(product->w2_calcium, product->w2_magnesium);
777 ra_ppm = Utils::RA_ppm(product->w2_total_alkalinity, product->w2_calcium, product->w2_magnesium); 974 ra_ppm = Utils::ResidualAlkalinity(product->w2_total_alkalinity, product->w2_calcium, product->w2_magnesium);
778 } 975 }
779 ui->w1_volEdit->setValue(product->w1_amount); 976 ui->w1_volEdit->setValue(product->w1_amount);
780 ui->w2_volEdit->setValue(product->w2_amount); 977 ui->w2_volEdit->setValue(product->w2_amount);
781 ui->w2_caEdit->setValue(product->w2_calcium); 978 ui->w2_caEdit->setValue(product->w2_calcium);
782 ui->w2_mgEdit->setValue(product->w2_magnesium); 979 ui->w2_mgEdit->setValue(product->w2_magnesium);
783 ui->w2_hco3Edit->setValue(product->w2_total_alkalinity * 1.22); 980 ui->w2_hco3Edit->setValue(Utils::Bicarbonate(product->w2_total_alkalinity, product->w2_ph));
784 ui->w2_caco3Edit->setValue(product->w2_total_alkalinity); 981 ui->w2_caco3Edit->setValue(product->w2_total_alkalinity);
785 ui->w2_naEdit->setValue(product->w2_sodium); 982 ui->w2_naEdit->setValue(product->w2_sodium);
786 ui->w2_clEdit->setValue(product->w2_chloride); 983 ui->w2_clEdit->setValue(product->w2_chloride);
787 ui->w2_so4Edit->setValue(product->w2_sulfate); 984 ui->w2_so4Edit->setValue(product->w2_sulfate);
788 ui->w2_phEdit->setValue(product->w2_ph); 985 ui->w2_phEdit->setValue(product->w2_ph);
823 ui->wt_caco3Edit->setValue(query.value("total_alkalinity").toDouble()); 1020 ui->wt_caco3Edit->setValue(query.value("total_alkalinity").toDouble());
824 ui->wt_naEdit->setValue(query.value("sodium").toDouble()); 1021 ui->wt_naEdit->setValue(query.value("sodium").toDouble());
825 ui->wt_clEdit->setValue(query.value("chloride").toDouble()); 1022 ui->wt_clEdit->setValue(query.value("chloride").toDouble());
826 ui->wt_so4Edit->setValue(query.value("sulfate").toDouble()); 1023 ui->wt_so4Edit->setValue(query.value("sulfate").toDouble());
827 ui->wt_hardnessEdit->setValue(Utils::Hardness(query.value("calcium").toDouble(), query.value("magnesium").toDouble())); 1024 ui->wt_hardnessEdit->setValue(Utils::Hardness(query.value("calcium").toDouble(), query.value("magnesium").toDouble()));
828 ui->wt_raEdit->setValue(Utils::RA_ppm(query.value("total_alkalinity").toDouble(), query.value("calcium").toDouble(), query.value("magnesium").toDouble())); 1025 ui->wt_raEdit->setValue(Utils::ResidualAlkalinity(query.value("total_alkalinity").toDouble(), query.value("calcium").toDouble(), query.value("magnesium").toDouble()));
829 } 1026 }
830 calcWater(); 1027 calcWater();
831 } 1028 }
832 1029
833 1030
866 product->wg_amount = mash_infuse; 1063 product->wg_amount = mash_infuse;
867 ui->wg_volEdit->setValue(mash_infuse); 1064 ui->wg_volEdit->setValue(mash_infuse);
868 } 1065 }
869 1066
870 1067
871 void EditProduct::wb_cacl2_changed(double val) { set_brewing_salt("CaCl2", val); } 1068 void EditProduct::wb_cacl2_changed(double val) { set_brewing_salt("CaCl2", val, MISC_USES_MASH); }
872 void EditProduct::wb_caso4_changed(double val) { set_brewing_salt("CaSO4", val); } 1069 void EditProduct::wb_caso4_changed(double val) { set_brewing_salt("CaSO4", val, MISC_USES_MASH); }
873 void EditProduct::wb_mgso4_changed(double val) { set_brewing_salt("MgSO4", val); } 1070 void EditProduct::wb_mgso4_changed(double val) { set_brewing_salt("MgSO4", val, MISC_USES_MASH); }
874 void EditProduct::wb_nacl_changed(double val) { set_brewing_salt("NaCl", val); } 1071 void EditProduct::wb_nacl_changed(double val) { set_brewing_salt("NaCl", val, MISC_USES_MASH); }
875 void EditProduct::wb_mgcl2_changed(double val) { set_brewing_salt("MgCl2", val); } 1072 void EditProduct::wb_mgcl2_changed(double val) { set_brewing_salt("MgCl2", val, MISC_USES_MASH); }
876 void EditProduct::wb_nahco3_changed(double val) { set_brewing_salt("NaHCO3", val); } 1073 void EditProduct::wb_nahco3_changed(double val) { set_brewing_salt("NaHCO3", val, MISC_USES_MASH); }
877 void EditProduct::wb_caco3_changed(double val) { set_brewing_salt("CaCO3", val); } 1074 void EditProduct::wb_caco3_changed(double val) { set_brewing_salt("CaCO3", val, MISC_USES_MASH); }
878 1075 void EditProduct::sp_cacl2_changed(double val) { set_brewing_salt("CaCl2", val, MISC_USES_SPARGE); }
879 1076 void EditProduct::sp_caso4_changed(double val) { set_brewing_salt("CaSO4", val, MISC_USES_SPARGE); }
1077 void EditProduct::sp_mgso4_changed(double val) { set_brewing_salt("MgSO4", val, MISC_USES_SPARGE); }
1078 void EditProduct::sp_nacl_changed(double val) { set_brewing_salt("NaCl", val, MISC_USES_SPARGE); }
1079 void EditProduct::sp_mgcl2_changed(double val) { set_brewing_salt("MgCl2", val, MISC_USES_SPARGE); }
1080

mercurial