{
  "schemaVersion": 1,
  "slug": "dilution-calculator",
  "category": "science",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "18ea9d17baf66ff7774ba6b3c83c561d56d470c80e155fad8e02bc8a0ed324a7",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/dilution-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": "V2 = C1 × V1 ÷ C2; D = max(0, V2 − V1); F = C1 ÷ C2",
    "vars": [
      [
        "C1",
        "stock concentration"
      ],
      [
        "V1",
        "stock volume"
      ],
      [
        "C2",
        "final (target) concentration"
      ],
      [
        "V2",
        "final volume"
      ],
      [
        "D",
        "diluent to add"
      ],
      [
        "F",
        "dilution factor"
      ]
    ],
    "note": "Applies only when C2 > 0. Solute amount C1×V1 is conserved (C1V1 = C2V2); the concentration ratio is displayed as 1 to F."
  },
  "externalEvidence": {
    "reviewedAt": "2026-10-04",
    "sources": [
      {
        "name": "OpenStax Chemistry — Molarity and dilution",
        "url": "https://openstax.org/books/chemistry-2e/pages/3-3-molarity"
      }
    ],
    "basis": "C1 × V1 = C2 × V2; added diluent = V2 - V1.",
    "limitations": "Concentration units must match. Assumes conservation of solute and additive volumes; container-fit output uses the tool's 1000 mL convention, not laboratory safety advice.",
    "implementationHash": "18ea9d17baf66ff7774ba6b3c83c561d56d470c80e155fad8e02bc8a0ed324a7",
    "domain": "math"
  },
  "contract": {
    "compute": "const c1=Number(stockConcentration),v1=Number(stockVolume),c2=Number(finalConcentration);if(![c1,v1,c2].every(Number.isFinite)||c1<0||v1<0||c2<=0||c2>c1)return{finalVolume:null,diluentVolume:null,dilutionFactor:null,concentrationRatio:null,soluteAmount:null,fitsInVolume:null,__error:'inputError'};const finalV=c1*v1/c2,diluent=finalV-v1,factor=c1/c2;return{finalVolume:finalV,diluentVolume:diluent,dilutionFactor:factor,concentrationRatio:factor>0?'1 to '+Math.round(factor*100)/100:'n/a',soluteAmount:c1*v1,fitsInVolume:finalV<=1000?'Yes':'No — split across containers'};",
    "inputs": [
      {
        "name": "stockConcentration",
        "type": "number",
        "default": 2,
        "min": 0,
        "max": 1000,
        "step": 0.0001
      },
      {
        "name": "stockVolume",
        "type": "number",
        "default": 50,
        "min": 0,
        "max": 100000,
        "step": 0.1
      },
      {
        "name": "finalConcentration",
        "type": "number",
        "default": 0.5,
        "min": 0.00001,
        "max": 1000,
        "step": 0.0001
      }
    ],
    "outputs": [
      {
        "name": "finalVolume",
        "precision": 2,
        "unit": "mL"
      },
      {
        "name": "diluentVolume",
        "precision": 2,
        "unit": "mL"
      },
      {
        "name": "dilutionFactor",
        "precision": 2,
        "unit": "x"
      },
      {
        "name": "concentrationRatio",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "soluteAmount",
        "precision": 3,
        "unit": "mmol"
      },
      {
        "name": "fitsInVolume",
        "precision": 0,
        "unit": "",
        "type": "text"
      }
    ],
    "interpret": null
  }
}
