{
  "schemaVersion": 1,
  "slug": "pool-chemical-calculator",
  "category": "household",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "c997d4f31159732781f25b66e4979f6aab628de3aadd21fd63aecfe363ef9b58",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/pool-chemical-calculator.json",
    "src/engine.js"
  ],
  "runtimeSource": "/sources/engine.txt",
  "runtimeHash": "5c888d8898afbdee36267bb9977829e1e2ac568f6677c8ee87469c139864645c",
  "scope": "The compute function records implemented equations, constants, lookup tables and custom rules. Inputs record defaults and allowed values; outputs record precision and units. Defaults are examples, not recommendations. General background references are not evidence for this specific algorithm.",
  "publishedFormula": {
    "formula": "Cl_g = max(0, Cl_t − Cl) × G × 3.785411784 ÷ 1000; A_lb = max(0, A_t − A) × 0.15 × G ÷ 10000",
    "vars": [
      [
        "Cl_g",
        "Additional available chlorine (g)"
      ],
      [
        "Cl_t",
        "Target chlorine (ppm)"
      ],
      [
        "Cl",
        "Current chlorine (ppm)"
      ],
      [
        "G",
        "Pool volume (US gal)"
      ],
      [
        "A_lb",
        "Sodium bicarbonate estimate (lb)"
      ],
      [
        "A_t",
        "Target alkalinity (ppm)"
      ],
      [
        "A",
        "Current alkalinity (ppm)"
      ]
    ],
    "note": "Chlorine is theoretical available-chlorine mass, not a product dose. Bicarbonate is an approximate alkalinity adjustment. pH direction is shown without an acid/base dose; follow labels and retest."
  },
  "externalEvidence": null,
  "contract": {
    "compute": "const units = gallons/10000; const chlorineActiveGrams = Math.max(0,targetChlorine-currentChlorine)*gallons*3.785411784/1000; const dPh = targetPh-currentPh; return { chlorineActiveGrams, phDirection: dPh < -0.05 ? 'pH needs lowering; use a product label and retest' : dPh > 0.05 ? 'pH needs raising; use a product label and retest' : 'pH is at the entered target', alkalinityLb: Math.max(0,targetAlkalinity-currentAlkalinity)*0.15*units, note: 'These are planning estimates, not product doses. Follow labels, never mix chemicals, circulate and retest.' };",
    "inputs": [
      {
        "name": "gallons",
        "type": "number",
        "default": 15000,
        "min": 100,
        "max": 200000,
        "step": 100,
        "slider": true
      },
      {
        "name": "currentChlorine",
        "type": "number",
        "default": 0.5,
        "min": 0,
        "max": 20,
        "step": 0.1,
        "slider": true
      },
      {
        "name": "targetChlorine",
        "type": "number",
        "default": 3,
        "min": 0,
        "max": 20,
        "step": 0.1,
        "slider": true
      },
      {
        "name": "currentPh",
        "type": "number",
        "default": 7.8,
        "min": 6,
        "max": 9,
        "step": 0.1,
        "slider": true
      },
      {
        "name": "targetPh",
        "type": "number",
        "default": 7.4,
        "min": 6,
        "max": 9,
        "step": 0.1,
        "slider": true
      },
      {
        "name": "currentAlkalinity",
        "type": "number",
        "default": 60,
        "min": 0,
        "max": 300,
        "step": 5,
        "slider": true
      },
      {
        "name": "targetAlkalinity",
        "type": "number",
        "default": 100,
        "min": 0,
        "max": 300,
        "step": 5,
        "slider": true
      }
    ],
    "outputs": [
      {
        "name": "chlorineActiveGrams",
        "precision": 1,
        "unit": "g"
      },
      {
        "name": "phDirection",
        "type": "text",
        "unit": ""
      },
      {
        "name": "alkalinityLb",
        "precision": 2,
        "unit": "lb"
      },
      {
        "name": "note",
        "type": "text",
        "unit": ""
      }
    ],
    "interpret": null
  }
}
