Loading Xelera Calculator...
\`; const blob = new Blob([html], {type: 'text/html'}); const url = URL.createObjectURL(blob); const win = window.open(url, '_blank'); // Clean up the blob URL after the window loads if (win) win.addEventListener('load', () => URL.revokeObjectURL(url)); } function PDFButton({ onClick }) { return (
); } // ─── COOLING TOWER ──────────────────────────────────────────────────────────── function CoolingPage() { const init = { towerTonnage:"",gpmRR:"",deltaT:"10",percentLoad:"100",volume:"",cycles:"", inhibitorName:"",inhibitorPrice:"",inhibitorDensity:"",inhibitorDosage:"",inhibitorHrsDay:"",inhibitorDaysYr:"", bio1Name:"",bio1Price:"",bio1Density:"",bio1Dosage:"",bio1Freq:"",bio1WeeksYr:"", bio2Name:"",bio2Price:"",bio2Density:"",bio2Dosage:"",bio2Freq:"",bio2WeeksYr:"", cityWaterCost:"",sewerCost:"", }; const [v,setV]=useState(init); const set=(k)=>(val)=>setV(p=>({...p,[k]:val})); const tons=n(v.towerTonnage), rr=tons>0?tons*3:n(v.gpmRR); const derivedTons=rr>0&&tons===0?rr/3:tons; const pctLoad=n(v.percentLoad)/100||1, dT=n(v.deltaT)||10; const cycles=n(v.cycles), vol=n(v.volume); const evap=rr>0?rr*0.01*(dT/10)*pctLoad:null; const mu=evap!=null&&cycles>1?evap*cycles/(cycles-1):null; const bd=evap!=null&&cycles>1?evap/(cycles-1):null; const hti=vol>0&&bd!=null&&bd>0?(0.7*vol)/(bd*60):null; const iPrice=n(v.inhibitorPrice),iDens=n(v.inhibitorDensity),iDosage=n(v.inhibitorDosage); const iHrsDay=n(v.inhibitorHrsDay),iDaysYr=n(v.inhibitorDaysYr); const iLbDay=mu!=null&&cycles>0&&iDosage>0?(iDosage/cycles/120)*(mu*1440)/1000:null; const iLbYr=iLbDay!=null&&iDaysYr>0?iLbDay*iDaysYr*(iHrsDay/24):null; const iGalDay=iLbDay!=null&&iDens>0?iLbDay/iDens:null; const iGalYr=iLbYr!=null&&iDens>0?iLbYr/iDens:null; const iCostYr=iGalYr!=null&&iPrice>0&&iDens>0?iGalYr*iPrice*iDens:null; const bio=(price,dens,dosage,freq,wk)=>{ const p=n(price),d=n(dens),ppm=n(dosage),f=n(freq),w=n(wk); if(vol<=0||ppm<=0) return {}; const lbFeed=(ppm/120)*(vol/1000),lbYr=lbFeed*f*w; return{lbFeed,lbYr,galFeed:d>0?lbFeed/d:null,galYr:d>0?lbYr/d:null,cost:d>0&&p>0?(lbYr/d)*p*d:null}; }; const b1=bio(v.bio1Price,v.bio1Density,v.bio1Dosage,v.bio1Freq,v.bio1WeeksYr); const b2=bio(v.bio2Price,v.bio2Density,v.bio2Dosage,v.bio2Freq,v.bio2WeeksYr); const muGalYr=mu!=null&&iDaysYr>0?mu*1440*iDaysYr*(iHrsDay/24):null; const cw=n(v.cityWaterCost)/1000,sw=n(v.sewerCost)/1000; const annMUWater=muGalYr!=null&&cw>0?muGalYr*cw:null; const annSewer=muGalYr!=null&&sw>0?muGalYr*sw:null; const evapGalYr=evap!=null&&iDaysYr>0?evap*1440*iDaysYr*(iHrsDay/24):null; const evapCredit=evapGalYr!=null&&cw>0?evapGalYr*cw:null; const totalWater=annMUWater!=null&&annSewer!=null&&evapCredit!=null?annMUWater+annSewer-evapCredit:null; const totalChem=iCostYr!=null?(iCostYr||0)+(b1.cost||0)+(b2.cost||0):null; const handlePDF=()=>{ const summary=[ {label:"Tower Tonnage",value:fmt(derivedTons>0?derivedTons:null,0),unit:"tons"}, {label:"GPM Recirculation",value:fmt(rr>0?rr:null,1),unit:"gpm"}, {label:"Evaporation",value:fmt(evap,2),unit:"gpm"}, {label:"Make Up (MU)",value:fmt(mu,2),unit:"gpm"}, {label:"Blow Down (BD)",value:fmt(bd,2),unit:"gpm"}, {label:"HTI",value:fmt(hti,1),unit:"hrs"}, {label:"Annual Chemical Cost",value:fmtMoney(totalChem),unit:""}, {label:"Annual Net Water Cost",value:fmtMoney(totalWater),unit:""}, ]; const detail=[ {title:"System Parameters",rows:[ {label:"Tower Tonnage",unit:"tons",display:v.towerTonnage||"—",type:"input"}, {label:"GPM Recirculation",unit:"gpm",display:v.gpmRR||"—",type:"input"}, {label:"Delta T",unit:"°F",display:v.deltaT,type:"input"}, {label:"Percent Load",unit:"%",display:v.percentLoad,type:"input"}, {label:"System Volume",unit:"gal",display:v.volume||"—",type:"input"}, {label:"Cycles of Concentration",unit:"COC",display:v.cycles||"—",type:"input"}, ]}, {title:"Water Balance",rows:[ {label:"Tower Tonnage",unit:"tons",display:fmt(derivedTons>0?derivedTons:null,0),type:"output"}, {label:"GPM Recirculation",unit:"gpm",display:fmt(rr>0?rr:null,1),type:"output"}, {label:"Evaporation (E)",unit:"gpm",display:fmt(evap,2),type:"output"}, {label:"Make Up (MU)",unit:"gpm",display:fmt(mu,2),type:"output"}, {label:"Blow Down (BD)",unit:"gpm",display:fmt(bd,2),type:"output"}, {label:"Holding Time Index (HTI)",unit:"hrs",display:fmt(hti,1),type:"output"}, ]}, {title:\`Inhibitor\${v.inhibitorName?" — "+v.inhibitorName:""}\`,rows:[ {label:"Price",unit:"$/lb",display:v.inhibitorPrice||"—",type:"input"}, {label:"Density",unit:"lb/gal",display:v.inhibitorDensity||"—",type:"input"}, {label:"Dosage",unit:"ppm",display:v.inhibitorDosage||"—",type:"input"}, {label:"Hrs/Day",unit:"hrs",display:v.inhibitorHrsDay||"—",type:"input"}, {label:"Days/Year",unit:"days",display:v.inhibitorDaysYr||"—",type:"input"}, {label:"Lb / Day",unit:"lbs",display:fmt(iLbDay,2),type:"output"}, {label:"Lb / Year",unit:"lbs",display:fmt(iLbYr,0),type:"output"}, {label:"Gals / Day",unit:"gal",display:fmt(iGalDay,2),type:"output"}, {label:"Gals / Year",unit:"gal",display:fmt(iGalYr,0),type:"output"}, {label:"Annual Cost",unit:"$",display:fmtMoney(iCostYr),type:"output"}, ]}, {title:\`Biocide #1\${v.bio1Name?" — "+v.bio1Name:""}\`,rows:[ {label:"Price",unit:"$/lb",display:v.bio1Price||"—",type:"input"}, {label:"Density",unit:"lb/gal",display:v.bio1Density||"—",type:"input"}, {label:"Dosage",unit:"ppm",display:v.bio1Dosage||"—",type:"input"}, {label:"Frequency",unit:"#/week",display:v.bio1Freq||"—",type:"input"}, {label:"Weeks/Year",unit:"wks",display:v.bio1WeeksYr||"—",type:"input"}, {label:"Lb / Feed",unit:"lbs",display:fmt(b1.lbFeed,2),type:"output"}, {label:"Lb / Year",unit:"lbs",display:fmt(b1.lbYr,0),type:"output"}, {label:"Gals / Feed",unit:"gal",display:fmt(b1.galFeed,2),type:"output"}, {label:"Annual Cost",unit:"$",display:fmtMoney(b1.cost),type:"output"}, ]}, {title:\`Biocide #2\${v.bio2Name?" — "+v.bio2Name:""}\`,rows:[ {label:"Price",unit:"$/lb",display:v.bio2Price||"—",type:"input"}, {label:"Density",unit:"lb/gal",display:v.bio2Density||"—",type:"input"}, {label:"Dosage",unit:"ppm",display:v.bio2Dosage||"—",type:"input"}, {label:"Frequency",unit:"#/week",display:v.bio2Freq||"—",type:"input"}, {label:"Weeks/Year",unit:"wks",display:v.bio2WeeksYr||"—",type:"input"}, {label:"Lb / Feed",unit:"lbs",display:fmt(b2.lbFeed,2),type:"output"}, {label:"Lb / Year",unit:"lbs",display:fmt(b2.lbYr,0),type:"output"}, {label:"Gals / Feed",unit:"gal",display:fmt(b2.galFeed,2),type:"output"}, {label:"Annual Cost",unit:"$",display:fmtMoney(b2.cost),type:"output"}, ]}, {title:"Water Costs",rows:[ {label:"City Water Cost",unit:"$/1k gal",display:v.cityWaterCost||"—",type:"input"}, {label:"Sewer Cost",unit:"$/1k gal",display:v.sewerCost||"—",type:"input"}, {label:"Annual MU Water Cost",unit:"$",display:fmtMoney(annMUWater),type:"output"}, {label:"Annual Sewer Cost",unit:"$",display:fmtMoney(annSewer),type:"output"}, {label:"Annual Evap Credit",unit:"$",display:fmtMoney(evapCredit),type:"output"}, {label:"Annual Net Water Cost",unit:"$",display:fmtMoney(totalWater),type:"output"}, {label:"Total Chemical Program",unit:"$",display:fmtMoney(totalChem),type:"output"}, ]}, ]; generatePDF("Cooling Tower",summary,detail); }; return (
setV(init)}/>
0?derivedTons:null} decimals={0}/> 0?rr:null} decimals={1}/>
Formulas per AWT field standards · Xelera Water Treatment
); } // ─── BOILER ─────────────────────────────────────────────────────────────────── function BoilerPage() { const init={boilerHP:"",avgSteamLoad:"",hrsDay:"",daysYr:"",cityWaterCost:"",muConductivity:"",fwConductivity:"",condensateConductivity:"",boilerConductivity:"",operatingMinutes:"",inhibitorName:"",inhibitorPrice:"",inhibitorDensity:"",inhibitorDosage:""}; const [v,setV]=useState(init); const set=(k)=>(val)=>setV(p=>({...p,[k]:val})); const hp=n(v.boilerHP),avgLoad=n(v.avgSteamLoad),hrsDay=n(v.hrsDay),daysYr=n(v.daysYr); const cwCost=n(v.cityWaterCost),muCond=n(v.muConductivity),fwCond=n(v.fwConductivity); const condCond=n(v.condensateConductivity),bwCond=n(v.boilerConductivity),opMin=n(v.operatingMinutes); const steamLbHr=avgLoad>0?avgLoad:hp>0?hp*34.5:null; const cycles=bwCond>0&&fwCond>0?bwCond/fwCond:null; const steamGpm=steamLbHr!=null?steamLbHr/500:null; const fwGpm=steamGpm!=null&&cycles!=null&&cycles>1?steamGpm*(cycles/(cycles-1)):steamGpm; const bdGpm=fwGpm!=null&&cycles!=null&&cycles>1?fwGpm/(cycles-1):null; const pctCond=fwCond>0&&muCond>0&&fwCond!==condCond?((fwCond-muCond)/(fwCond-condCond))*100:null; const condGpm=fwGpm!=null&&pctCond!=null?fwGpm*(pctCond/100):null; const muGpm=fwGpm!=null&&condGpm!=null?fwGpm-condGpm:fwGpm; const annOpMin=hrsDay>0&&daysYr>0?hrsDay*60*daysYr:opMin>0?opMin:null; const annMU=muGpm!=null&&annOpMin!=null?muGpm*annOpMin:null; const annBD=bdGpm!=null&&annOpMin!=null?bdGpm*annOpMin:null; const mmLbs=fwGpm!=null&&annOpMin!=null?(fwGpm*annOpMin*8.33)/1e6:null; const annWater=annMU!=null&&cwCost>0?(annMU/1000)*cwCost:null; const iPrice=n(v.inhibitorPrice),iDens=n(v.inhibitorDensity),iDosage=n(v.inhibitorDosage); const iLbDay=muGpm!=null&&cycles!=null&&cycles>0&&iDosage>0?(iDosage/cycles/120)*(muGpm*1440)/1000:null; const iLbYr=iLbDay!=null&&hrsDay>0&&daysYr>0?iLbDay*daysYr*(hrsDay/24):null; const iGalDay=iLbDay!=null&&iDens>0?iLbDay/iDens:null; const iGalYr=iLbYr!=null&&iDens>0?iLbYr/iDens:null; const iCostYr=iGalYr!=null&&iPrice>0&&iDens>0?iGalYr*iPrice*iDens:null; const handlePDF=()=>{ const summary=[ {label:"Steam Load",value:fmt(steamLbHr,0),unit:"lbs/hr"}, {label:"Cycles of Concentration",value:fmt(cycles,1),unit:"COC"}, {label:"Make Up Flow",value:fmt(muGpm,2),unit:"gpm"}, {label:"Feed Water Flow",value:fmt(fwGpm,2),unit:"gpm"}, {label:"Blow Down Rate",value:fmt(bdGpm,2),unit:"gpm"}, {label:"% Condensate Return",value:fmt(pctCond,1),unit:"%"}, {label:"Annual Make Up",value:fmt(annMU,0),unit:"gal"}, {label:"Annual Water Cost",value:fmtMoney(annWater),unit:""}, ]; const detail=[ {title:"System Conditions",rows:[ {label:"Boiler Horsepower",unit:"hp",display:v.boilerHP||"—",type:"input"}, {label:"AVG Steam Load",unit:"#/hr",display:v.avgSteamLoad||"—",type:"input"}, {label:"Hrs / Day",unit:"hrs",display:v.hrsDay||"—",type:"input"}, {label:"Days / Year",unit:"days",display:v.daysYr||"—",type:"input"}, {label:"City Water Cost",unit:"$/1k gal",display:v.cityWaterCost||"—",type:"input"}, {label:"MU Conductivity",unit:"µmhos",display:v.muConductivity||"—",type:"input"}, {label:"FW Conductivity",unit:"µmhos",display:v.fwConductivity||"—",type:"input"}, {label:"Condensate Conductivity",unit:"µmhos",display:v.condensateConductivity||"—",type:"input"}, {label:"Boiler Conductivity",unit:"µmhos",display:v.boilerConductivity||"—",type:"input"}, ]}, {title:"Calculated System Values",rows:[ {label:"AVG Steam Load",unit:"#/hr",display:fmt(steamLbHr,0),type:"output"}, {label:"Cycles of Concentration",unit:"",display:fmt(cycles,1),type:"output"}, {label:"Make Up Water Flow",unit:"gpm",display:fmt(muGpm,2),type:"output"}, {label:"Feed Water Flow",unit:"gpm",display:fmt(fwGpm,2),type:"output"}, {label:"Blow Down Rate",unit:"gpm",display:fmt(bdGpm,2),type:"output"}, {label:"Annual Make Up",unit:"gal",display:fmt(annMU,0),type:"output"}, {label:"Annual Blow Down",unit:"gal",display:fmt(annBD,0),type:"output"}, {label:"% Condensate Return",unit:"%",display:fmt(pctCond,1),type:"output"}, {label:"MM lbs/yr Feed Water",unit:"MM lbs",display:fmt(mmLbs,3),type:"output"}, {label:"Steam Flow",unit:"gpm",display:fmt(steamGpm,2),type:"output"}, {label:"Annual Water Cost",unit:"$",display:fmtMoney(annWater),type:"output"}, ]}, {title:\`Inhibitor\${v.inhibitorName?" — "+v.inhibitorName:""}\`,rows:[ {label:"Price",unit:"$/lb",display:v.inhibitorPrice||"—",type:"input"}, {label:"Density",unit:"lb/gal",display:v.inhibitorDensity||"—",type:"input"}, {label:"Dosage",unit:"ppm",display:v.inhibitorDosage||"—",type:"input"}, {label:"Lb / Day",unit:"lbs",display:fmt(iLbDay,2),type:"output"}, {label:"Lb / Year",unit:"lbs",display:fmt(iLbYr,0),type:"output"}, {label:"Gals / Day",unit:"gal",display:fmt(iGalDay,2),type:"output"}, {label:"Gals / Year",unit:"gal",display:fmt(iGalYr,0),type:"output"}, {label:"Annual Cost",unit:"$",display:fmtMoney(iCostYr),type:"output"}, ]}, ]; generatePDF("Boiler Water",summary,detail); }; return (
setV(init)}/>
Formulas: AWT "Basic Calculations – Part III: Boiler Water" · Xelera
); } // ─── SOFTENER ───────────────────────────────────────────────────────────────── function SoftenerPage() { const init={serviceFlowRate:"5",totalHardness:"",totalIron:"",cuFtResin:"",exchangeCapacity:"30000",expPctCapacity:"90"}; const [v,setV]=useState(init); const set=(k)=>(val)=>setV(p=>({...p,[k]:val})); const sfr=n(v.serviceFlowRate),hardness=n(v.totalHardness),iron=n(v.totalIron); const resin=n(v.cuFtResin),exchCap=n(v.exchangeCapacity),expPct=n(v.expPctCapacity); const ironAsHardness=iron*4; const totalGpg=(hardness+ironAsHardness)/17.1; const softeningCapacity=resin>0&&exchCap>0&&expPct>0&&totalGpg>0?(resin*exchCap*(expPct/100))/totalGpg:null; const maxPeakFlow=sfr>0&&resin>0?sfr*resin:null; const handlePDF=()=>{ const summary=[ {label:"Resin Volume",value:v.cuFtResin||"—",unit:"ft³"}, {label:"Total Hardness",value:v.totalHardness||"—",unit:"ppm CaCO₃"}, {label:"Total Iron",value:v.totalIron||"—",unit:"ppm Fe"}, {label:"Hardness Load",value:fmt(totalGpg>0?totalGpg:null,2),unit:"gpg"}, {label:"Softening Capacity",value:fmt(softeningCapacity,0),unit:"gal"}, {label:"Max Peak Flow",value:fmt(maxPeakFlow,1),unit:"gpm"}, ]; const detail=[ {title:"Softener Inputs",rows:[ {label:"Service Flow Rate",unit:"gpm/ft³",display:v.serviceFlowRate,type:"input"}, {label:"Total Hardness",unit:"ppm CaCO₃",display:v.totalHardness||"—",type:"input"}, {label:"Total Iron",unit:"ppm Fe",display:v.totalIron||"—",type:"input"}, {label:"Cu. Ft. Resin",unit:"ft³",display:v.cuFtResin||"—",type:"input"}, {label:"Exchange Capacity",unit:"gr/ft³",display:v.exchangeCapacity,type:"input"}, {label:"Expected % Capacity",unit:"%",display:v.expPctCapacity,type:"input"}, ]}, {title:"Calculated Results",rows:[ {label:"Iron as Hardness Equiv.",unit:"ppm CaCO₃",display:fmt(iron>0?ironAsHardness:null,1),type:"output"}, {label:"Total Hardness Load",unit:"gpg",display:fmt(totalGpg>0?totalGpg:null,2),type:"output"}, {label:"Softening Capacity",unit:"gal",display:fmt(softeningCapacity,0),type:"output"}, {label:"Max Peak Flow",unit:"gpm",display:fmt(maxPeakFlow,1),type:"output"}, ]}, ]; generatePDF("Water Softener",summary,detail); }; return (
setV(init)}/>
0?totalGpg:null} decimals={2}/> 0?ironAsHardness:null} decimals={1}/>
17.1 ppm CaCO₃ = 1 grain hardness
1 ppm Fe ≈ 4 ppm CaCO₃ hardness equivalent
Exchange capacity default: 30,000 gr/ft³ @ 15 lbs salt
Peak flow default: 5 gpm/ft³ resin
Formulas: AWT "Basic Calculations – Part 2: Pretreatment" · Xelera
); } // ─── LSI ────────────────────────────────────────────────────────────────────── function LSIPage() { const init={pH:"",temp:"",tds:"",calcium:"",alkalinity:""}; const [v,setV]=useState(init); const set=(k)=>(val)=>setV(p=>({...p,[k]:val})); const pH=n(v.pH),tempF=n(v.temp),tds=n(v.tds),ca=n(v.calcium),alk=n(v.alkalinity); const pC=ca>0?-Math.log10((ca/2.5)/100000):null; const pA=alk>0?-Math.log10(alk/50000):null; let pKpKs=null; if(tempF>0){ const tbl=[[32,2.6],[40,2.5],[50,2.4],[60,2.3],[70,2.2],[80,2.1],[90,2.0],[100,1.9],[110,1.8],[120,1.7],[130,1.6],[140,1.5],[150,1.4],[160,1.3]]; if(tempF<=32)pKpKs=2.6;else if(tempF>=160)pKpKs=1.3; else for(let i=0;i=tbl[i][0]&&tempF<=tbl[i+1][0]){pKpKs=tbl[i][1]+((tempF-tbl[i][0])/(tbl[i+1][0]-tbl[i][0]))*(tbl[i+1][1]-tbl[i][1]);break;} } let fm=0; if(tds>0){const s=Math.sqrt(2.5e-5*tds);fm=-0.5*(s/(1+s)-0.3*2.5e-5*tds);} const pHs=pC!=null&&pA!=null&&pKpKs!=null?pKpKs+pC+pA+5*fm:null; const lsi=pHs!=null&&pH>0?pH-pHs:null; const lsiColor=lsi===null?C.sublabel:lsi>0.5?"#c62828":lsi<-0.5?"#1565c0":"#2e7d32"; const lsiDesc=lsi===null?"Enter all values":lsi>0.5?"Scaling tendency (↑ CaCO₃ deposition risk)":lsi<-0.5?"Corrosive tendency (↑ metal corrosion risk)":"Near neutral — balanced"; const handlePDF=()=>{ const lsiStr=lsi!==null?fmt(lsi,2):"—"; const tendency=lsi===null?"Insufficient data":lsi>0.5?"SCALING":lsi<-0.5?"CORROSIVE":"BALANCED"; const summary=[ {label:"pH (measured)",value:v.pH||"—",unit:""}, {label:"Temperature",value:v.temp||"—",unit:"°F"}, {label:"TDS",value:v.tds||"—",unit:"ppm"}, {label:"Saturation pH (pHs)",value:fmt(pHs,2),unit:""}, {label:"LSI Value",value:lsiStr,unit:""}, {label:"Tendency",value:tendency,unit:""}, ]; const detail=[ {title:"Water Analysis Inputs",rows:[ {label:"pH (measured)",unit:"",display:v.pH||"—",type:"input"}, {label:"Temperature",unit:"°F",display:v.temp||"—",type:"input"}, {label:"TDS",unit:"ppm",display:v.tds||"—",type:"input"}, {label:"Calcium Hardness",unit:"ppm CaCO₃",display:v.calcium||"—",type:"input"}, {label:"Total Alkalinity",unit:"ppm CaCO₃",display:v.alkalinity||"—",type:"input"}, ]}, {title:"LSI Calculation Results",rows:[ {label:"Saturation pH (pHs)",unit:"",display:fmt(pHs,2),type:"output"}, {label:"Langelier Saturation Index",unit:"",display:lsiStr,type:"output"}, {label:"Tendency",unit:"",display:tendency,type:"output"}, ]}, ]; generatePDF("Langelier Saturation Index",summary,detail); }; return (
setV(init)}/>
Langelier Saturation Index
{lsi!==null?fmt(lsi,2):"—"}
{lsiDesc}
{[["LSI > +0.5","Strong scaling tendency"],["LSI +0.1 to +0.5","Mild to moderate scaling"],["LSI −0.1 to +0.1","Balanced / near neutral"],["LSI −0.5 to −0.1","Mild corrosive tendency"],["LSI < −0.5","Strong corrosive tendency"]].map(([r,d])=>(
{r}
{d}
))}
); } // ─── FORMULAS ───────────────────────────────────────────────────────────────── function FormulasPage() { const sections=[ {title:"Cooling Tower Formulas",items:[ {label:"Tower Tonnage",eq:"GPM RR ÷ 3"},{label:"GPM RR",eq:"Tower Tonnage × 3"}, {label:"Volume (est.)",eq:"1.5 × sump OR 5 × RR OR RR × 1.83"}, {label:"COC",eq:"Tower TDS ÷ Make-Up TDS"}, {label:"Evaporation (E) gpm",eq:"1% × RR per 10°F ΔT (adj. for % load)"}, {label:"Make Up (MU) gpm",eq:"(E × COC) ÷ (COC − 1)"},{label:"Blow Down (BD) gpm",eq:"E ÷ (COC − 1)"}, {label:"HTI hrs",eq:"(0.7 × V gal) ÷ (BD gpm × 60) → minutes ÷ 60 = hours"},{label:"CR rule of thumb",eq:"3 gpm per ton"}, {label:"E rule of thumb",eq:"3 gpm per 100 tons"}, {label:"Inhibitor lbs/day",eq:"((ppm ÷ COC) ÷ 120) × ((MU gpm × 1440) ÷ 1000)"}, {label:"Biocide slug lbs/feed",eq:"(ppm ÷ 120) × (System Volume ÷ 1000)"}, ]}, {title:"Boiler Formulas",items:[ {label:"Steam Load from HP",eq:"Boiler HP × 34.5 = lbs steam/hr"}, {label:"COC (boiler)",eq:"Boiler Conductivity ÷ FW Conductivity"}, {label:"Steam Flow gpm",eq:"Steam lbs/hr ÷ 500"},{label:"FW Flow gpm",eq:"Steam gpm × (COC ÷ (COC − 1))"}, {label:"Blow Down gpm",eq:"FW gpm ÷ (COC − 1)"}, {label:"% Condensate Return",eq:"(FW cond − MU cond) ÷ (FW cond − Cond. cond) × 100"}, {label:"MU gpm",eq:"FW gpm − Condensate gpm"}, {label:"Annual MU gal",eq:"MU gpm × operating min/yr"}, {label:"MM lbs/yr feed water",eq:"(FW gpm × op. min × 8.33) ÷ 1,000,000"}, {label:"Inhibitor lbs/day",eq:"((ppm ÷ COC) ÷ 120) × ((MU gpm × 1440) ÷ 1000)"}, ]}, {title:"Softener Formulas",items:[ {label:"Hardness conversion",eq:"17.1 ppm CaCO₃ = 1 grain"}, {label:"Iron as hardness equiv.",eq:"1 ppm Fe = 4 ppm CaCO₃"}, {label:"Total load (gpg)",eq:"(Total hardness + Iron equiv.) ÷ 17.1"}, {label:"Softening Capacity (gal)",eq:"(Resin ft³ × Exch. cap. × Exp. %) ÷ Total gpg"}, {label:"Max Peak Flow (gpm)",eq:"Service flow rate gpm/ft³ × Resin ft³"}, {label:"Exchange capacity default",eq:"30,000 gr/ft³ @ 15 lbs salt"}, ]}, {title:"Abbreviations",items:[ {label:"BD",eq:"Blow Down"},{label:"BW",eq:"Boiler Water"}, {label:"COC",eq:"Cycles of Concentration"},{label:"FW",eq:"Feed Water"}, {label:"MU",eq:"Make Up"},{label:"µmhos / Mmhos",eq:"millimhos (conductivity)"}, {label:"ppm",eq:"parts per million"},{label:"HTI",eq:"Holding Time Index"}, {label:"gpg",eq:"grains per gallon"},{label:"LSI",eq:"Langelier Saturation Index"}, ]}, ]; return (
Reference formulas for all modules. Imperial units throughout.
{sections.map(sec=>(
{sec.items.map((f,i)=>(
{f.label}
{f.eq}
))}
))}
Source: AWT "Basic Calculations Necessary to Survive in the Field" Parts I, II & III
); } // ─── ROOT ───────────────────────────────────────────────────────────────────── const TABS=[ {id:"cooling",label:"🌡 Cooling"},{id:"boiler",label:"🔥 Boiler"}, {id:"softener",label:"💧 Softener"},{id:"lsi",label:"⚖ LSI"}, {id:"formulas",label:"📐 Formulas"}, ]; function App() { const [tab,setTab]=useState("cooling"); return (

Water Treatment Calculator

Xelera, Inc. · Field Reference Tool

{TABS.map(t=>)}
{tab==="cooling" && } {tab==="boiler" && } {tab==="softener" && } {tab==="lsi" && } {tab==="formulas" && }
); } `; var transformed = Babel.transform(appSource, { presets: [['react', {}]], filename: 'app.jsx' }).code; // Prepend React hooks destructure var finalCode = 'const { useState, useRef } = React;\n' + transformed; // Execute var fn = new Function(finalCode); fn(); // Render var root = ReactDOM.createRoot(document.getElementById('root')); root.render(React.createElement(App)); } catch(e) { document.getElementById('root').innerHTML = '
App error:
' + e.message + '
'; console.error('App load error:', e); } }; babelScript.onerror = function() { // Fallback message if CDN fails (offline) document.getElementById('root').innerHTML = '

Xelera Calculator

Please connect to the internet for the first load, then the app will work offline.

'; }; document.head.appendChild(babelScript); })();