Sun, 11 Nov 2018 23:15:46 +0100
OG and FG are now calculated from the grist. The printed report has a summary an notes section at the end. The formulas are in the global formulas script.
--- a/www/import/from_brouwhulp.php Sun Nov 11 17:53:33 2018 +0100 +++ b/www/import/from_brouwhulp.php Sun Nov 11 23:15:46 2018 +0100 @@ -452,6 +452,9 @@ $f_sugars = 0; $efficiency = 75; $batch_size = 20; + $pCara = 0; + $pSugar = 0; + $svg = 77; $sql = "INSERT INTO recipes SET name='" . mysqli_real_escape_string($db, $recipe->NAME); if ($recipe->NOTES) @@ -473,10 +476,7 @@ $efficiency = floatval($recipe->EFFICIENCY); $sql .= "', efficiency='" . $efficiency; /* Don't use $recipe->EST_OG but recalculate it */ - if ($recipe->EST_FG) - $sql .= "', est_fg='" . floatval($recipe->EST_FG); - else - $sql .= "', est_fg='1.000"; + /* Don't use $recipe->EST_FG but recalculate it */ if ($recipe->EST_COLOR) { $srm = floatval($recipe->EST_COLOR); $ebc = srm_to_ebc($srm); @@ -555,7 +555,8 @@ $famount = floatval($fermentable->AMOUNT); $fermentables .= ',"f_amount":' . $famount; $fermentables .= ',"f_cost":' . floatval($fermentable->COST); - $fermentables .= ',"f_type":"' . mysqli_real_escape_string($db, $fermentable->TYPE) . '"'; + $ftype = mysqli_real_escape_string($db, $fermentable->TYPE); + $fermentables .= ',"f_type":"' . $ftype . '"'; $fyield = floatval($fermentable->YIELD); $fermentables .= ',"f_yield":' . $fyield; if ($fermentable->COLOR) { @@ -584,10 +585,12 @@ $fermentables .= ',"f_max_in_batch":' . floatval($fermentable->MAX_IN_BATCH); else $fermentables .= ',"f_max_in_batch":100.0'; + $fgraintype = mysqli_real_escape_string($db, $fermentable->GRAINTYPE); if ($fermentable->GRAINTYPE) - $fermentables .= ',"f_graintype":"' . mysqli_real_escape_string($db, $fermentable->GRAINTYPE) . '"'; + $fgraintype = mysqli_real_escape_string($db, $fermentable->GRAINTYPE); else - $fermentables .= ',"f_graintype":"Base"'; + $fgraintype = "Base"; + $fermentables .= ',"f_graintype":"' . $fgraintype . '"'; if ($fermentable->ADDED) $fadded = mysqli_real_escape_string($db, $fermentable->ADDED); else @@ -600,7 +603,8 @@ else $fermentables .= ',"f_dissolved_protein":0'; ($fermentable->ADJUST_TO_TOTAL_100 == "TRUE") ? $fermentables .= ',"f_adjust_to_total_100":true' : $fermentables .= ',"f_adjust_to_total_100":false'; - $fermentables .= ',"f_percentage":' . floatval($fermentable->PERCENTAGE); + $percent = floatval($fermentable->PERCENTAGE); + $fermentables .= ',"f_percentage":' . $percent; if ($fermentable->DI_pH) $fermentables .= ',"f_di_ph":' . floatval($fermentable->DI_pH); else @@ -611,6 +615,10 @@ if ($fadded == "Mash") $d = floatval($efficiency) / 100 * $d; $f_sugars += $d; + if ($fgraintype == "Crystal") + $pCara += $percent; + if ($ftype == "Sugar") + $pSugar += $percent; } $fermentables .= ']'; @@ -722,6 +730,7 @@ ($yeast->AMOUNT_IS_WEIGHT== "TRUE") ? $yeasts .= ',"y_amount_is_weight":true' : $yeasts.= ',"y_amount_is_weight":false'; if ($yeast->ADD_TO_SECONDARY=="FALSE") { $yeasts .= ',"y_use":"Primary"'; + $svg = floatval($yeast->ATTENUATION); } else if ($yeast->PRODUCT_ID=="F2") { $yeasts .= ',"y_use":"Bottle"'; } else { @@ -824,15 +833,10 @@ * Added the calculated values * OG, FG, color, IBU */ - $plato = 100 * $f_sugars / $batch_size; - $sg = plato_to_sg($plato); - /* Average loops, HansH 5x. Brouwhulp 20x, about 10x is enough so keep 20. */ - for ($i = 0; $i < 20; $i++) { - if ($sg > 0) - $plato = 100 * $f_sugars / ($batch_size * $sg); - $sg = plato_to_sg($plato); - } - $sql .= "', est_og='" . floatval($sg); + $og = estimate_og($f_sugars, $batch_size); + $sql .= "', est_og='" . floatval($og); + $fg = estimate_fg($pSugar, $pCara, 0, 0, 0, $svg, $og); + $sql .= "', est_fg='" . floatval($fg); $sql .= "';"; if (! $result = mysqli_query($db, $sql)) {
--- a/www/includes/formulas.php Sun Nov 11 17:53:33 2018 +0100 +++ b/www/includes/formulas.php Sun Nov 11 23:15:46 2018 +0100 @@ -127,6 +127,49 @@ /* + * sugars is the total extract weight of sugars. + */ +function estimate_og($sugars, $batch_size) { + $plato = 100 * $sugars / $batch_size; + $sg = plato_to_sg($plato); + + /* Average loops, HansH 5x. Brouwhulp 20x, about 10x is enough so keep 20. */ + for ($i = 0; $i < 20; $i++) { + if ($sg > 0) + $plato = 100 * $sugars / ($batch_size * $sg); + $sg = plato_to_sg($plato); + } + return $sg; +} + + + +function estimate_fg($percSugar, $percCara, $WGratio, $TotTme, $Temp, $attenuation, $og) { + if ($percSugar > 40) + $percSugar = 0; + if ($percCara > 50) + $percCara = 0; + if (($WGratio > 0) && ($TotTme > 0)) { + $BD = $WGratio; + $BD = max(2, min(5.5, $BD)); + $Temp = max(60, min(72, $Temp)); + } else { + $BD = 3.5; + $Temp = 67; + $TotTme = 75; + } + if ($attenuation < 30) + $attenuation = 77; + + $AttBeer = 0.00825 * $attenuation + 0.00817 * $BD - 0.00684 * $Temp + 0.00026 * $TotTme - 0.00356 * $percCara + 0.00553 * $percSugar + 0.547; + $fg = 1 + (1 - $AttBeer) * ($og - 1); +// echo $percSugar.' '.$percCara.' '.$attenuation.' attn '.$AttBeer.' FG '.$fg.PHP_EOL; + return $fg; +} + + + +/* Brouwhulp data.pas @@ -589,152 +632,7 @@ -procedure TRecipe.CalcOG; -var - i, j, k: integer; - v, v2, sg, d, tot, tot2, vol, vol1, vol2, sugF, sug, sug2, p, x: double; - mass1, mass2 : double; - F: TFermentable; -begin - for j := 1 to 1 do - begin - sug:= 0; - sugf:= 0; - sug2:= 0; - tot := 0; - tot2:= 0; - vol:= 0; - FEfficiency.Value := GetEfficiency; - for i := 0 to NumFermentables - 1 do - begin - F := TFermentable(Fermentable[i]); - if (F.AddedType = atMash) or (F.AddedType = atBoil) then - begin - d := F.Amount.Value * (F.Yield.Value / 100) * (1 - F.Moisture.Value / 100); - if (F.AddedType = atMash) then - d := FEfficiency.Value / 100 * d; - sugf := sugf + d; - tot := tot + F.Amount.Value; - end - else - begin - x:= (F.Yield.Value / 100) * (1 - F.Moisture.Value / 100); - sug2:= sug2 + F.Amount.Value * x; - tot2:= tot2 + F.Amount.Value; - tot := tot + F.Amount.Value; - vol:= vol + F.Amount.Value / (x * SugarDensity + (1 - x) * 1); - end; - end; - if tot > 0 then - for i := 0 to NumFermentables - 1 do - begin - F := Fermentable[i]; - F.Percentage.Value := 100 * F.Amount.Value / tot; - end; - if (FEquipment <> NIL) and (FBatchSize.Value > 0) then - begin - vol1:= FBatchSize.Value - FEquipment.TrubChillerLoss.Value; - vol2:= vol1 + FEquipment.TopUpWater.Value + vol; - sug:= sugf * vol1 / FBatchSize.Value; //kg - sug:= sug + sug2; //kg - if vol2 > 0 then - sug:= sug / vol2; //kg/l - p:= 100 * sug; - sg:= PlatoToSG(p); - for k:= 1 to 30 do - begin - if sg > 0 then - p := 100 * sug / sg; //deg. Plato - sg := PlatoToSG(p); - end; - FEstOG.Value:= sg; - end - else if FBatchSize.Value <> 0 then - begin - p := 100 * sugf / FBatchSize.Value; //deg. Plato - sg := PlatoToSG(p); - for k:= 1 to 20 do - begin - if sg > 0 then - p := 100 * sugf / (FBatchSize.Value * sg); //deg. Plato - sg := PlatoToSG(p); - end; - FEstOG.Value := sg; - end - else - FEstOG.Value := 1.0; - end; - - CalcWaterBalance; -end; - - - -procedure TRecipe.EstimateFG; -var - i: integer; - percS, percCara, BD, Att, AttBeer, sg: double; - Temp, TotTme: double; - Y: TYeast; -// Eq: TEquipment; -begin - percS := GetPercSugar; - //if PercS > 40 then PercS:= 0; - percCara := GetPercCrystalMalt; - if percCara > 50 then PercCara:= 0; - if (Mash <> nil) and (Mash.MashStep[0] <> nil) then - begin - BD := Mash.MashStep[0].WaterToGrainRatio; - BD:= Max(2, Min(5.5, BD)); - Temp := Mash.AverageTemperature; - Temp:= Max(60, Min(72, Temp)); - TotTme := Mash.TotalMashTime; - TotTme:= Max(20, Min(90, TotTme)); - end - else - begin - BD := 3.5; - Temp := 67; - TotTme := 75; - end; - Y := Yeast[0]; - if Y <> nil then - begin - Att := Y.Attenuation.Value; - if Att < 30 then Att:= 77; - end - else - Att := 77; - AttBeer := 0.00825 * Att + 0.00817 * BD - 0.00684 * Temp + 0.00026 * - TotTme - 0.00356 * PercCara + 0.00553 * PercS + 0.547; - -{ Eq := nil; - if FEquipment <> nil then - Eq := TEquipment(Equipments.FindByName(FEquipment.Name.Value)); - if Eq <> nil then - AttBeer2 := Eq.EstimateFG(Att, BD, Temp, TotTme, PercCara, PercS);} - - FEstFG.Value := 1 + (1 - AttBeer) * (FEstOG.Value - 1); - CalcOGFermenter; - if FOGFermenter.Value > 1.001 then - begin - sg:= FOGFermenter.Value; - FEstFG2.Value := 1 + (1 - AttBeer) * (sg - 1); - FEstABV.Value := ABVol(FEstOG.Value, FEstFG.Value); - end - else if FOG.Value > 1.001 then - begin - sg:= FOG.Value; - FEstFG2.Value := 1 + (1 - AttBeer) * (sg - 1); - FEstABV.Value := ABVol(FEstOG.Value, FEstFG.Value); - end - else - begin - FEstFG2.Value := 1 + (1 - AttBeer) * (FEstOG.Value - 1); - FEstABV.Value := ABVol(FEstOG.Value, FEstFG.Value); - end; -end; Procedure TRecipe.CalcCalories; var sug, alc, org, fig : double;
--- a/www/rec_print.php Sun Nov 11 17:53:33 2018 +0100 +++ b/www/rec_print.php Sun Nov 11 23:15:46 2018 +0100 @@ -24,6 +24,9 @@ $cost_hops = 0.0; $cost_yeasts = 0.0; $cost_miscs = 0.0; +$pSugar = 0; +$pCara = 0; +$svg = 77; class PDF_MySQL_Table extends FPDF @@ -84,39 +87,6 @@ $this->Cell(35,5,'Brouwzaal rendement',0,0,'L',true); $this->Cell(25,5,$row['efficiency'].' %',0,0,'L',true); $this->Cell(25,5,'',0,0,'L',true); - $this->Ln(); - - $this->SetX($this->TableX); - $this->Cell(35,5,'Start SG',0,0,'L',true); - $this->Cell(25,5,sprintf("%.3f",$row['est_og']),0,0,'L',true); - $this->Cell(25,5,'('.sprintf("%.3f",$row['st_og_min']).' - '.sprintf("%.3f",$row['st_og_max']).')',0,0,'L',true); - $this->Cell($vul,5,'',0,0,'L',false); - $this->Cell(35,5,'Eind SG',0,0,'L',true); - $this->Cell(25,5,sprintf("%.3f",$row['est_fg']),0,0,'L',true); - $this->Cell(25,5,'('.sprintf("%.3f",$row['st_fg_min']).' - '.sprintf("%.3f",$row['st_fg_max']).')',0,0,'L',true); - $this->Ln(); - - $this->SetX($this->TableX); - $this->Cell(35,5,'Geschat alcohol',0,0,'L',true); - $this->Cell(25,5,sprintf("%.1f",$row['est_abv']).'%',0,0,'L',true); - $this->Cell(25,5,'('.sprintf("%.1f",$row['st_abv_min']).' - '.sprintf("%.1f",$row['st_abv_max']).'%)',0,0,'L',true); - $this->Cell($vul,5,'',0,0,'L',false); - $this->Cell(35,5,'CO2',0,0,'L',true); - $this->Cell(25,5,sprintf("%.1f",$row['est_carb']).'%',0,0,'L',true); - $this->Cell(25,5,'('.sprintf("%.1f",$row['st_carb_min']).' - '.sprintf("%.1f",$row['st_carb_max']).'%)',0,0,'L',true); - $this->Ln(); - - $this->SetX($this->TableX); - $this->Cell(35,5,'Kleur ('.$row['color_method'].')',0,0,'L',true); - $beercolor = ebc_to_color($row['est_color']); - $this->SetFillColor($beercolor[0],$beercolor[1],$beercolor[2]); - $this->Cell(25,5,$row['est_color'].' EBC',0,0,'L',true); - $this->Cell(25,5,'('.$row['st_color_min'].' - '.$row['st_color_max'].' EBC)',0,0,'L',true); - $this->SetFillColor(210,245,255); - $this->Cell($vul,5,'',0,0,'L',false); - $this->Cell(35,5,'Bitterheid ('.$row['ibu_method'].')',0,0,'L',true); - $this->Cell(25,5,sprintf("%.0f",$row['est_ibu']).' IBU',0,0,'L',true); - $this->Cell(25,5,'('.$row['st_ibu_min'].' - '.$row['st_ibu_max'].' IBU)',0,0,'L',true); $this->Ln(10); $this->cMargin=$cMargin; @@ -125,6 +95,8 @@ function TableFermentables($row) { global $cost_fermentables; global $total_fermentables; + global $pSugar; + global $pCara; $vul = $this->w - $this->rMargin - $this->lMargin - 132; $this->AddCol($vul,'Grondstof','L'); $this->AddCol(30,'Leverancier','L'); @@ -142,7 +114,6 @@ $this->ProcessingTable=true; $sugf = 0; -// $tot = 0; $this->SetFont('Helvetica','',9); $this->SetFillColor(250, 195, 65); $arr = json_decode($row['json_fermentables'], true); @@ -150,12 +121,20 @@ $name = iconv('UTF-8','windows-1252',$item['f_name']); $supplier = iconv('UTF-8','windows-1252',$item['f_supplier']); $added = iconv('UTF-8','windows-1252',$item['f_added']); + $type = iconv('UTF-8','windows-1252',$item['f_type']); + $graintype = iconv('UTF-8','windows-1252',$item['f_graintype']); $amount = floatval($item['f_amount']); $costkg = floatval($item['f_cost']); $yield = floatval($item['f_yield']); $moisture = floatval($item['f_moisture']); $color = floatval($item['f_color']); $percent = floatval($item['f_percentage']); + + if ($type == "Sugar") + $pSugar += $percent; + if ($graintype == "Crystal") + $pCara += $percent; + $cost = $amount * $costkg; $cost_fermentables += $cost; $total_fermentables += $amount; @@ -164,10 +143,6 @@ if ($added == "Mash") $d = floatval($row['efficiency']) / 100 * $d; $sugf += $d; -// $tot += $amount; - //$plato = 100 * $d / $amount; - //$this->Cell(0,5,$tot.' sugf: '.$sugf.' d: '.$d.' pt: '.$plato.' moisture: '.$moisture,0,0,'L',false); - //$this->Ln(); $this->Cell($vul,5,$name,0,0,'L',true); $this->Cell(30,5,$supplier,0,0,'L',true); @@ -180,17 +155,9 @@ $this->Ln(); } - $plato = 100 * $sugf / floatval($row['batch_size']); - $sg = plato_to_sg($plato); - /* Average loops, HansH 5x. Brouwhulp 20x, about 10x is enough so keep 20. */ - for ($i = 0; $i < 20; $i++) { - if ($sg > 0) - $plato = 100 * $sugf / (floatval($row['batch_size']) * $sg); - $sg = plato_to_sg($plato); - } + $row['est_og'] = estimate_og($sugf, floatval($row['batch_size'])); $this->SetFillColor(210,245,255); - $this->Cell($vul,5,sprintf("%.1f",$plato).' Plato, OG: '.sprintf("%.3f",$sg),0,0,'L',true); - $this->Cell(62,5,'',0,0,'L',false); + $this->Cell($vul+62,5,'',0,0,'L',false); $this->Cell(20,5,sprintf("%8.3f",$total_fermentables),0,0,'R',true); $this->Cell(30,5,'',0,0,'L',false); $this->Cell(20,5,sprintf("%8.3f",$cost_fermentables).EURO,0,0,'R',true); @@ -290,6 +257,7 @@ function TableYeasts($row) { global $cost_yeasts; + global $svg; $vul = $this->w - $this->rMargin - $this->lMargin - 140; $this->AddCol(27,'Laboratorium','L'); $this->AddCol(18,'Product','L'); @@ -308,7 +276,6 @@ $this->SetFont('Helvetica','',9); $this->SetFillColor(175, 175, 255); - $svg = 70; /* Conservative SVG% as default */ $arr = json_decode($row['json_yeasts'], true); foreach($arr as $item) { //foreach element in $arr @@ -340,11 +307,6 @@ $this->SetFillColor(210,245,255); $this->Cell($vul+120,5,'',0,0,'L',false); $this->Cell(20,5,sprintf("%8.3f",$cost_yeasts).EURO,0,0,'R',true); - $this->Ln(); - - $og = floatval($row['est_og']); - $fg = $og - ($svg * ($og - 1.0)) / 100; - $this->Cell(0,5,'FG: '.sprintf("%5.3f",$fg),0,0,'L',false); $this->Ln(10); $this->ProcessingTable=false; $this->cMargin=$cMargin; @@ -415,6 +377,62 @@ } // Watercolor $this->SetFillColor(120,255,250); + + function TableSummary($row) { + global $pSugar; + global $pCara; + global $svg; + /* 2 Columns */ + $vul = $this->w - $this->rMargin - $this->lMargin - 170; + $cMargin=$this->cMargin; + $this->cMargin=2; + $this->TableX=$this->lMargin; + $this->SetFont('Helvetica','B',9); + $this->SetX($this->TableX); + $this->SetFillColor(255,150,100); + $this->Cell(0, 5, 'Recept samenvatting',0,0,'C',true); + $this->Ln(); + + $this->SetFont('Helvetica','',9); + $this->SetFillColor(210,245,255); + + $row['est_fg'] = estimate_fg($pSugar, $pCara, 0, 0, 0, $svg, $row['est_og']); + + $this->SetX($this->TableX); + $this->Cell(35,5,'Start SG',0,0,'L',true); + $this->Cell(25,5,sprintf("%.3f",$row['est_og']),0,0,'L',true); + $this->Cell(25,5,'('.sprintf("%.3f",$row['st_og_min']).' - '.sprintf("%.3f",$row['st_og_max']).')',0,0,'L',true); + $this->Cell($vul,5,'',0,0,'L',false); + $this->Cell(35,5,'Eind SG',0,0,'L',true); + $this->Cell(25,5,sprintf("%.3f",$row['est_fg']),0,0,'L',true); + $this->Cell(25,5,'('.sprintf("%.3f",$row['st_fg_min']).' - '.sprintf("%.3f",$row['st_fg_max']).')',0,0,'L',true); + $this->Ln(); + + $this->SetX($this->TableX); + $this->Cell(35,5,'Geschat alcohol',0,0,'L',true); + $this->Cell(25,5,sprintf("%.1f",$row['est_abv']).'%',0,0,'L',true); + $this->Cell(25,5,'('.sprintf("%.1f",$row['st_abv_min']).' - '.sprintf("%.1f",$row['st_abv_max']).'%)',0,0,'L',true); + $this->Cell($vul,5,'',0,0,'L',false); + $this->Cell(35,5,'CO2',0,0,'L',true); + $this->Cell(25,5,sprintf("%.1f",$row['est_carb']).'%',0,0,'L',true); + $this->Cell(25,5,'('.sprintf("%.1f",$row['st_carb_min']).' - '.sprintf("%.1f",$row['st_carb_max']).'%)',0,0,'L',true); + $this->Ln(); + + $this->SetX($this->TableX); + $this->Cell(35,5,'Kleur ('.$row['color_method'].')',0,0,'L',true); + $beercolor = ebc_to_color($row['est_color']); + $this->SetFillColor($beercolor[0],$beercolor[1],$beercolor[2]); + $this->Cell(25,5,$row['est_color'].' EBC',0,0,'L',true); + $this->Cell(25,5,'('.$row['st_color_min'].' - '.$row['st_color_max'].' EBC)',0,0,'L',true); + $this->SetFillColor(210,245,255); + $this->Cell($vul,5,'',0,0,'L',false); + $this->Cell(35,5,'Bitterheid ('.$row['ibu_method'].')',0,0,'L',true); + $this->Cell(25,5,sprintf("%.0f",$row['est_ibu']).' IBU',0,0,'L',true); + $this->Cell(25,5,'('.$row['st_ibu_min'].' - '.$row['st_ibu_max'].' IBU)',0,0,'L',true); + $this->Ln(10); + // Kostprijs per liter, calorieren + $this->cMargin=$cMargin; + } } @@ -444,9 +462,14 @@ $pdf->TableHops($row); $pdf->TableYeasts($row); $pdf->TableMiscs($row); - -//$pdf->SetFont('Helvetica','',10); -//$pdf->Cell(0,10,'Receptje '.$record,0,1,'C'); -// Disclaimer toeveogen dat dit alleen recept ontwikkeling is. -// Footer sectie met berekende/geschatte uitkomsten zoals FG, ABV, kostprijs per liter enz. +$pdf->TableSummary($row); +if (strlen($row['notes'])) { + $pdf->SetFillColor(255,150,100); + $pdf->Cell(0, 5, 'Recept opmerkingen',0,0,'C',true); + $pdf->Ln(); + $pdf->SetFillColor(210,245,255); + $pdf->MultiCell(0,4,$row['notes'],0,'L',true); +} +// Disclaimer toevoegen dat dit alleen recept ontwikkeling is. Uitkomsten zoals IBU zijn een berekende schatting. +// Footer sectie met berekende/geschatte uitkomsten zoals ABV, kostprijs per liter enz. $pdf->Output();