#!/usr/bin/env perl -w require Tk; use Tk; use Tk::Font; use Tk::Text; use Tk::ROText; use English; use strict; use warnings; our %density = ( DI => "1.0", HF => "1.16", NH4OH => "0.9", H202 => "1.11", HCl => "1.18", H2SO4 => "1.84", Citric => "1", NH4F => "1.01", TMAH => "1.0", Nitric => "1.415", Acetic => "1.05", Phosphoric => "1.7", IPA => "0.79" ); our %concentration =( DI => "1.0", HF => "0.49", NH4OH => "0.29", H202 => "0.3", HCl => "0.37", H2SO4 => ".98", Citric => "0.5", NH4F => "0.4", TMAH => "0.25", Nitric => "0.7", Acetic => "0.8", Phosphoric => "0.85", IPA => "1.0" ); my $mw = MainWindow->new; $mw -> title("BathCalc Selection"); $mw -> geometry("+200+200"); #Setting frames in main window. my $menuframe = $mw -> Frame( -relief => "groove", -borderwidth => 2 )->pack( -side => "top", -fill => "x", ); my $topframe = $mw -> Frame()->pack( -side => "top", -fill => "x", -padx => 10, -pady => 5 ); my $midframe = $mw -> Frame()->pack( -side => "top", -fill => "x", -padx => 10, ); my $botframe = $mw -> Frame()->pack( -side => "top", -fill => "x", -padx => 10, -pady => 5 ); #command to make a file menubutton my $file_mw = $menuframe -> Menubutton ( -text => "File", -activeforeground => "grey" ) -> pack (-side => 'left'); $file_mw -> command( -label => "Exit", -command => sub{$mw -> destroy} ); my $help_mw = $menuframe -> Menubutton ( -text => "Help", -activeforeground => "grey" ) -> pack (-side => 'right'); $help_mw -> command( -label => "About", -command => sub{&ABOUT}); #setting up selections as to where to go next my $rb; my $r1=$midframe->Radiobutton( -text=>"Calculate Amount of Material to Pour a Bath", -value=>"1", -variable=>\$rb ) -> pack(-side => 'top', -anchor => 'w'); my $r2=$midframe->Radiobutton( -text=>"Convert Chemical Ratio to Mass Percent", -value=>"2", -variable=>\$rb ) -> pack(-side => 'top', -anchor => 'w'); my $r3=$midframe->Radiobutton( -text=>"Display Assumptions", -value=>"3", -variable=>\$rb ) -> pack(-side => 'top', -anchor => 'w'); my $text1 = $topframe->Label ( -text => "Selection:", -font => '{times new roman} 14' ) -> pack(-side => 'top', -anchor => 'w'); my $actionButton = $botframe -> Button( -text => "Go", -command => \&CHOOSE ) -> pack(-side => 'left', -padx => '50', -pady => '20'); my $exitButton = $botframe -> Button( -text => "Quit", -command => sub{exit} ) -> pack(-side => 'right', -padx => '50', -pady => '20'); MainLoop (); sub CHOOSE { if ($rb == 1) { &MAKE_BATH; } elsif ($rb == 2) { &RATIO; } elsif ($rb == 3) { &ASSUME; } } ###################################################################### +###### ###################################################################### +###### # This creates the window for the make bath screen # # This subroutine will generate a new window that will require user i +nput to calculate volumes # density will be displayed and allow users to change if they need to + do so. # required to pour up a bath of known size and concentration. The de +fault concentration and # # # MAIN -> MB ###################################################################### +##### sub MAKE_BATH { my $mb = MainWindow -> new; $mb -> title("Bath Pour Up"); $mb -> geometry("+200+200"); #this frame is going to be the menu bar. my $frame1 = $mb -> Frame( -relief => "groove", -borderwidth => 3 )->pack( -side => "top", -fill => "x" ); my $file_mb = $frame1 -> Menubutton ( -text => "File", -activeforeground => "grey" ) -> pack (-side => 'left'); $file_mb -> command( -label => "Exit", -command => sub{$mb -> destroy}); my $help_mb = $frame1 -> Menubutton ( -text => "Help", -activeforeground => "grey" ) -> pack (-side => 'right'); $help_mb -> command( -label => "Help", -command => sub{&MBHELP} ); $help_mb -> separator(); $help_mb -> command( -label => "About", -command => sub{&ABOUT} #The next section sets up all of the frames I will need, many, many fr +ames... ); my $midhold = $mb -> Frame()->pack( -side => "top", -fill => "x", -padx => 3 ); my $frame2 = $midhold -> Frame()->pack( -side => "top", -anchor => "n" ); my $frame3 = $midhold -> Frame()->pack( -side => "top", -anchor => "n" ); my $calcVolframe = $mb -> Frame( -borderwidth => 3 )->pack( -side => "top", -fill => 'x', ); my $frame12 = $mb -> Frame( #this is the bottom frame with the st +atus button in it. -relief => "raised", -borderwidth => 3 )->pack( -side => "bottom", -fill => 'x', ); our $totalvolume; my $voltext = $calcVolframe -> Entry( -textvariable => \$totalvolume, -width => 5 ) -> pack( -side => 'right', -padx => 36); my $volLbl = $calcVolframe ->Label( -text => "Bath Volume (L):" ) -> pack(-side=>'right'); #------------------------------------------------------------ #Calculate Button Below #------------------------------------------------------------ my $calcButton = $calcVolframe -> Button( -text => "Calculate", -command => \&VOLCALC ) -> pack(-side => 'left', -padx => '50', -pady => '10'); #------------------------------------------------------------ #Calculate Button Above #------------------------------------------------------------ our $i = 0; our(@wtpercent, @wtpercentbox, @concentration, $isSolv, @volume, @ +density, %chemname, @volumebox); my (@concentrationbox, @densitybox); #need to make sure that concentration and density are always in th +e same order. my $j = 0; foreach (sort keys(%concentration)){ $concentration[$j] = $concentration{$_}; $density[$j] = $density{$_}; $chemname{$_} = $j; $wtpercent[$j] = 0; $j++; }; my $headingOne = $frame3 ->Label( -text => "Solvent", -relief => "raised" ) -> grid (-column=>0, -row => 1); my $headingTwo = $frame3 ->Label( -relief => "raised", -text => "Chemical Name" ) -> grid (-column=>1, -row => 1); my $headingThree = $frame3 ->Label( -relief => "raised", -text => "Density (g/mL)" ) -> grid (-column=>2, -row => 1); my $headingFour = $frame3 ->Label( -text => "Concentration (%)", -relief => "raised" ) -> grid (-column=>3, -row => 1); my $headingFive = $frame3 ->Label( -text => "Wt %", -relief => "raised", -width => 5 ) -> grid (-column=>4, -row => 1); my $headingSix = $frame3 ->Label( -text => "Calculated Volume (L)", -relief => "raised" ) -> grid (-column=>5, -row => 1); for my $x (sort keys %density) { my $row = $i+2; $frame3->Radiobutton( -value=>$i, -variable => \$isSolv, -command=>[\&colorme, $i])->grid(-row=>$row,-column=>0); $frame3->Label(-text=>$x)->grid(-row=>$row,-column=>1); $densitybox[$i] = $frame3->Entry(-bg=>'grey', -width => 5, -te +xtvariable => \$density[$i])->grid(-row=>$row,-column=>2); $concentrationbox[$i] = $frame3->Entry(-bg=>'grey', -width => +5, -textvariable => \$concentration[$i])->grid(-row=>$row,-column=>3) +; $wtpercentbox[$i] = $frame3->Entry(-bg=>'white', -width => 5, +-textvariable => \$wtpercent[$i])->grid(-row=>$row,-column=>4); $volumebox[$i] = $frame3->Entry(-bg=>'grey', -width => 7, -tex +tvariable => \$volume[$i])->grid(-row=>$row,-column=>5); $i++; } our $statustext = "Please enter desired weight percent and sol +vent."; my $statuslabel = $frame12 -> Label( -text => "Status: " ) -> pack(-side => "left"); my $status =$frame12 -> Entry( -textvariable => \$statustext, -foreground => 'red', -width => 60 ) -> pack(-side => "left"); } ###################################################################### +###### ###################################################################### +###### # This creates the window for the ratio screen # # MAIN -> RATIO ###################################################################### +##### sub RATIO { my $rt = MainWindow -> new; $rt -> title("Ratio to Weight Percent"); $rt -> geometry("+200+200"); #this frame is going to be the menu bar. my $frame1 = $rt -> Frame( -relief => "groove", -borderwidth => 3 )->pack( -side => "top", -fill => "x" ); my $file_rt = $frame1 -> Menubutton ( -text => "File", -activeforeground => "grey" ) -> pack (-side => 'left'); $file_rt -> command( -label => "Exit", -command => sub{$rt -> destroy}); my $help_rt = $frame1 -> Menubutton ( -text => "Help", -activeforeground => "grey" ) -> pack (-side => 'right'); $help_rt -> command( -label => "Help", -command => sub{&RTHELP} ); $help_rt -> separator(); $help_rt -> command( -label => "About", -command => sub{&ABOUT} ); #The next section sets up all of the frames I will need, many, many fr +ames... my $midhold = $rt -> Frame()->pack( -side => "top", -fill => "x", -padx => 3 ); my $frame2 = $midhold -> Frame()->pack( -side => "top", -anchor => "n" ); our $rtframe3 = $midhold -> Frame()->pack( -side => "top", -anchor => "n" ); our $calcVolframe = $rt -> Frame( -borderwidth => 3 )->pack( -side => "top", -fill => 'x', ); my $frame12 = $rt -> Frame( #this is the bottom frame with the st +atus button in it. -relief => "raised", -borderwidth => 3 )->pack( -side => "bottom", -fill => 'x', ); our $VolButton = $calcVolframe -> Button( -text => "Bath Volume >>", -command => \&RATIOSUP ) -> pack(-side => 'right', -padx => '5', -pady => '5'); our $mOrv; my $mOrvbutton = $calcVolframe -> Radiobutton( -variable => \$mOrv, -value => "M", -width => 5 ) -> pack( -side => 'right'); my $massText = $calcVolframe -> Label( -text => "Mass Ratio ", -padx => 2) -> pack(-side => "right"); my $mOrvbutton2 = $calcVolframe -> Radiobutton( -variable => \$mOrv, -value => "V", -width => 5 ) -> pack( -side => 'right'); my $volLbl = $calcVolframe ->Label( -text => "Volume Ratio:" ) -> pack(-side=>'right'); #------------------------------------------------------------ #Calculate Button Below #------------------------------------------------------------ my $calcButton = $calcVolframe -> Button( -text => "Calculate", -command => \&RATIOCALC ) -> pack(-side => 'left', -padx => '50', -pady => '10'); #------------------------------------------------------------ #Calculate Button Above #------------------------------------------------------------ our(@ratio, @ratiobox, @concentration, @wtPercent, @density, %chem +name, @wtpercentbox, @ratioVolbox, @ratioVol); my (@concentrationbox, @densitybox); #need to make sure that concentration and density are always in th +e same order. my $j = 0; foreach (sort keys(%concentration)){ $concentration[$j] = $concentration{$_}; $density[$j] = $density{$_}; $chemname{$_} = $j; $ratio[$j] = 0; $wtPercent[$j] = 0; $j++; }; my $headingTwo = $rtframe3 ->Label( -relief => "raised", -text => "Chemical Name" ) -> grid (-column=>1, -row => 1, -padx => 3, -pady =>2); my $headingThree = $rtframe3 ->Label( -relief => "raised", -text => "Density (g/mL)" ) -> grid (-column=>2, -row => 1, -padx => 3, -pady =>2); my $headingFour = $rtframe3 ->Label( -text => "Concentration", -relief => "raised" ) -> grid (-column=>3, -row => 1, -padx => 3, -pady =>2); + my $headingFive = $rtframe3 ->Label( -text => "Ratio", -relief => "raised", -width => 5 ) -> grid (-column=>4, -row => 1, -padx => 3, -pady =>2); my $headingSix = $rtframe3 ->Label( -text => "Calculated Wt Percent", -relief => "raised" ) -> grid (-column=>5, -row => 1, -padx => 3, -pady =>2); my $i = 0; for my $chems (sort keys %density) { my $row = $i+2; $rtframe3->Label(-text=>$chems)->grid(-row=>$row,-column=>1); $densitybox[$i] = $rtframe3->Entry(-bg=>'grey', -width => 5, - +textvariable => \$density[$i], -justify => "center")->grid(-row=>$row +,-column=>2); $concentrationbox[$i] = $rtframe3->Entry(-bg=>'grey', -width = +> 5, -textvariable => \$concentration[$i], -justify => "center")->gri +d(-row=>$row,-column=>3); $ratiobox[$i] = $rtframe3->Entry(-bg=>'white', -width => 5, -t +extvariable => \$ratio[$i], -justify => "center")->grid(-row=>$row,-c +olumn=>4); $wtpercentbox[$i] = $rtframe3->Entry(-bg=>'grey', -textvariabl +e => \$wtPercent[$i], -width => 5, -justify => "center")->grid(-row= +>$row,-column=>5); $i++; } our $statustext = "Please enter desired ratio and whether wt o +r vol percent."; my $statuslabel = $frame12 -> Label( -text => "Status: " ) -> pack(-side => "left"); my $status =$frame12 -> Entry( -textvariable => \$statustext, -foreground => 'red', -width => 60 ) -> pack(-side => "left"); } ###################################################################### +###### ###################################################################### +###### # This sub is responsible for calculating the wt percents of the che +micals # supplied in the ratio screen # MAIN -> MB -> VOLCALC ###################################################################### +##### sub VOLCALC { our(@wtpercent, @wtpercentbox, @concentration, @volume, @density, +%chemname, @volumebox, $isSolv, $statustext, $totalvolume); my @densityfraction; if (defined($totalvolume)){ if (defined($isSolv)){ my @chemname = (sort keys(our %density)); my $solventname = $chemname[$isSolv]; $statustext = "Calculating"; my @concRatio; $wtpercent[$isSolv] = 0; for (my $i=0; $i <= $#chemname; $i++){ $concRatio[$i] = (.01 * $wtpercent[$i]) / $concentrati +on[$i]; $densityfraction[$i] = $concRatio[$i] * $density[$i]; } my $percentsolvent = 1 - sum(@concRatio); my $densityfractionsolvent = $percentsolvent * $density[$i +sSolv]; $densityfraction[$isSolv] = $densityfractionsolvent; my $estdensity = sum(@densityfraction); my $totalmass = $totalvolume * $estdensity; my @componentmass = map{$_ * $totalmass}@concRatio; my $i; for ($i=0; $i <= $#componentmass; $i++){ $volume[$i] = $componentmass[$i] / $density[$i]; } my $volumewithoutsolvent = sum(@volume); $volume[$isSolv] = $totalvolume - $volumewithoutsolvent; $statustext = ("Calculation Complete"); my $l = 0; foreach (@volume){ $volume[$l] = sprintf("%.3f", $volume[$l]); $l++; }; foreach (@volume){ if ($_ < 0){ $statustext = "You screwed up somewhere!" } } } else { $statustext = "You need to select a solvent" } } else { $statustext = "You need to provide a bath volume"; } }; ###################################################################### +###### ###################################################################### +###### # This sub is responsible for calculating the wt percents of the che +micals # supplied in the ratio screen # MAIN -> RT -> RATIOCALC ###################################################################### +##### sub RATIOCALC { our ($mOrv, @ratio, @density, @concentration, %chemname, @wtPercen +t, $statustext, @wtpercentbox); our (@volratio, $totalVol, @ratioVol); my (@wtPureAmt, @residualDI); if (defined($mOrv)){ $statustext = "Calculating..."; if ($mOrv eq "V"){ for (my $i = 0; $i <= $#ratio; $i++){ $ratio[$i] = $ratio[$i] * $density[$i]; $mOrv = "M"; }; }; for (my $j = 0; $j <= $#ratio; $j++){ $wtPureAmt[$j] = $ratio[$j] * $concentration[$j]; }; for (my $k = 0; $k <= $#ratio; $k++){ $residualDI[$k] = $ratio[$k] * (1 - $concentration[$k]); }; my $totalmass = sum(@ratio); my $diIndex = $chemname{'DI'}; if ($totalmass != 0){@wtPercent = map{$_ / $totalmass}@wtPureA +mt}else{$statustext = "You need to give me numbers!"}; if ($wtPureAmt[$diIndex] == 0) { $wtPercent[$diIndex] = sum(@residualDI) / $totalmass; } else { $wtPercent[$diIndex] = (sum(@residualDI) + $wtPureAmt[$diI +ndex]) / $totalmass; } $statustext = "Calculation Complete"; }else{ $statustext = "You need to select weight or volume ratio!" }; my $l = 0; foreach (@wtPercent){ $wtPercent[$l] = sprintf("%.3f", $wtPercent[$l]); $wtPercent[$l] = $wtPercent[$l] * 100; $wtpercentbox[$l] -> configure( -textvariable => \$wtPercent[$ +l]); $l++; }; if ($totalVol != 0){ if (our $volEntryOpen == 1){ if ($mOrv eq "M"){ for (my $i = 0; $i <= $#ratio; $i++){ $volratio[$i] = $ratio[$i] / $density[$i]; }; }; my $j; for ($j=0; $j <= $#volratio; $j++){ $ratioVol[$j] = $totalVol * ($volratio[$j] / sum(@volr +atio)); $ratioVol[$j] = sprintf("%.3f", $ratioVol[$j]); }; } } else { $statustext = "You need to provide a total volume in liters." }; } ###################################################################### +###### ###################################################################### +###### # this subroutine sums the numbers passed to it. Returns a single v +alue. # # ###################################################################### +##### sub sum { my $sum = 0; foreach my $line (@_) { $sum += $line; } return $sum; } ###################################################################### +###### ###################################################################### +###### # This subroutine disables and colors the wtpercentbox of the selecte +d # solvent in the Make Bath calculation window # MAIN -> MB -> COLORME ###################################################################### +##### sub colorme { our @wtpercentbox; my $i = shift; map{$_->configure(-bg=>'white')}@wtpercentbox; $wtpercentbox[$i]->configure(-bg=>'black'); map{$_->configure(-state=>'normal')}@wtpercentbox; $wtpercentbox[$i]->configure(-state => 'disabled'); } ###################################################################### +###### ###################################################################### +###### # This window is created when the Bath Volume button is pushed in the + # ratio window calculation screen. It will provide the volumes of ch +emical # to add to create a bath of known volume # RT -> RATIO -> RATIOSUP ###################################################################### +##### sub RATIOSUP { our (@ratio, $rtframe3, @ratioVol, @ratioVolbox, $VolButton, $calc +Volframe, $totalVol, $statustext, $mOrv, @density); my ($row, @volratio); my $headingSeven = $rtframe3 ->Label( -text => "Pour Up Volume (L)", -relief => "raised" ) -> grid (-column=>6, -row => 1, -padx => 3, -pady =>2); $VolButton -> packForget; $statustext = "You need to provide a total volume"; my $i = 0; foreach my $line (@ratio) { $row = $i+2; $ratioVolbox[$i] = $rtframe3->Entry(-bg=>'grey', -width => + 7, -textvariable => \$ratioVol[$i], -justify => 'center')->grid(-row +=>$row,-column=>6); $i++; } my $newrow = $row +1; our $totvolbox = $rtframe3 -> Entry(-bg => 'white', -width => 7, - +textvariable => \$totalVol, -justify => 'center') -> grid (-row=>$new +row, -column => 6, -pady => 3); my $totvolLab = $rtframe3 -> Label(-text => "Total Volume (L)") -> + grid (-row=>$newrow, -column => 5, -pady => 3); our $volEntryOpen = 1; } ###################################################################### +###### ###################################################################### +###### # This window is the about box for all windows # # MAIN -> ABOUT ###################################################################### +##### sub ABOUT #The about box in the help menu! { my $aboutwin = MainWindow -> new; $aboutwin -> title("About"); $aboutwin -> geometry("+210+210"); my $aboutleftframe = $aboutwin -> Frame() -> pack(-side => "left") +; my $aboutrightframe = $aboutwin -> Frame() -> pack(-side => "left" +); my $exitButton = $aboutrightframe -> Button( -text => "Close", -command => sub{destroy $aboutwin} ) -> pack(-side => 'right', -padx => '10', -pady => '10'); my $words = qq( BathCalc ver.2.0 Written by David Daycock. August 2004 Send bugs to: david\@netboise.com); my $aboutText = $aboutleftframe->Scrolled('ROText', -height => '10', -width => '20', -wrap => "word", -scrollbars => 'osoe', ); $aboutText -> insert('end', $words); $aboutText -> pack(-side => "left", -padx => '10', -pady => '10'); } ###################################################################### +###### ###################################################################### +###### # This is the HELP MENU in the RATIO CALC window ###################################################################### +##### sub RTHELP { my $rthelpwin = MainWindow -> new; $rthelpwin -> title("Help"); $rthelpwin -> geometry("+210+210"); my $rthelpleftframe = $rthelpwin -> Frame() -> pack(-side => "left +"); my $rthelprightframe = $rthelpwin -> Frame() -> pack(-side => "lef +t"); my $words = qq( This utility will help you calculate mass percentages and volumes to p +our up baths. The concentration and the densities have been provided based on standa +rd concentrated chemicals. These values are able to be modified by t +he user. Concentrations are provided in weight fraction, and density + in grams per mL. When you click the "Make Bath" button, you will be prompted to enter a + total bath volume in liters. ); my $rthelpText = $rthelpleftframe->Scrolled('ROText', -height => '25', -width => '100', -wrap => "word", -scrollbars => 'osoe', ); $rthelpText -> insert('end', $words); $rthelpText -> pack(-side => "left", -padx => '10', -pady => '10'); } ###################################################################### +###### ###################################################################### +###### # This is the HELP MENU in the MAKE BATH CALC window ###################################################################### +##### sub MBHELP { my $mbhelpwin = MainWindow -> new; $mbhelpwin -> title("Help"); $mbhelpwin -> geometry("+210+210"); my $mbhelpframe = $mbhelpwin -> Frame() -> pack(-side => "left"); my $words = qq( This utility will calculate pour up volumes if you have desired final +wt percent goal. The wt percent column should be entered as mass fraction * 100. (0.02 + mass fraction of component A = 2 (wt %)); You will need to provide a total bath volume, then select the solvent. + For instance, if I want to pour up 12L of 2% TMAH in DI, you would +first type in 12 in the Bath Volume box, then click the DI radio butt +on, then type "2" in wt % box in the TMAH row. Results are supplied in Liters rounded to the nearest mL. ); my $mbhelpText = $mbhelpframe->Scrolled('ROText', -height => '25', -width => '100', -wrap => "word", -scrollbars => 'osoe', ); $mbhelpText -> insert('end', $words); $mbhelpText -> pack(-side => "left", -padx => '10', -pady => '10'); } ###################################################################### +###### ###################################################################### +###### # This is the Assumptions window from the top main window ###################################################################### +##### sub ASSUME { my $assumewin = MainWindow -> new; $assumewin -> title("Assumptions"); $assumewin -> geometry("+210+210"); my $assumeframe = $assumewin -> Frame() -> pack(-side => "left"); my $words = qq( The only assumption you can not modify is this: When calculating bath + pour up based on desired weight pecent, the denisty of the total sol +ution is assumed to be the mass percent weighted averages of the comp +onents' density. ); my $assumeText = $assumeframe->Scrolled('ROText', -height => '25', -width => '50', -wrap => "word", -scrollbars => 'osoe', ); $assumeText -> insert('end', $words); $assumeText -> pack(-side => "left", -padx => '10', -pady => '10'); }
In reply to BathCalc 2.0 by ~~David~~
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |