{
  "schemaVersion": 1,
  "slug": "soil-calculator",
  "category": "construction",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "72ef86a79d78ac423cf3ab12a87c38f6ba0c49b5a629ede9eaad9c91ddb7d8a3",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/soil-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": "V_ft³ = L × W × D_in/12 × (1 + allowance/100); V_yd³ = V_ft³/27; mass = V_yd³ × density; bags = ceil(volume/bag volume) or ceil(mass/bag mass)",
    "vars": [],
    "note": "Bagged and bulk costs are separate alternatives and exclude delivery. Confirm actual product coverage and density with the supplier."
  },
  "externalEvidence": null,
  "contract": {
    "compute": "try{if(((true)&&(!Number.isFinite(length)||length<0||length>1000))||((true)&&(!Number.isFinite(width)||width<0||width>500))||((true)&&(!Number.isFinite(depthIn)||depthIn<0.5||depthIn>60))||((true)&&(!Number.isFinite(settling)||settling<0||settling>100))||(([\"volume\"].includes(String(bagMode)))&&(!Number.isFinite(bagSize)||bagSize<0.001||bagSize>100))||((true)&&(!Number.isFinite(pricePerBag)||pricePerBag<0||pricePerBag>1000000))||(([\"custom\"].includes(String(soilType)))&&(!Number.isFinite(density)||density<0.01||density>10))||(([\"weight\"].includes(String(bagMode)))&&(!Number.isFinite(bagWeightLb)||bagWeightLb<0.001||bagWeightLb>10000))||((true)&&(!Number.isFinite(pricePerCuyd)||pricePerCuyd<0||pricePerCuyd>1000000)))throw new Error('inputError');const calculate=function(){const h=(function context() {\n  const DAY=86400000;\n  const own=(o,k)=>Object.prototype.hasOwnProperty.call(o,k);\n  const fail=()=>{throw new Error('inputError');};\n  const num=(v,min=-Infinity,max=Infinity,integer=false)=>{\n    if(!Number.isFinite(v)||v<min||v>max||(integer&&!Number.isInteger(v)))fail();return v;\n  };\n  const choice=(v,values)=>{if(!values.includes(v))fail();return v;};\n  const date=s=>{if(typeof s!=='string'||!/^\\d{4}-\\d{2}-\\d{2}$/.test(s)||s.startsWith('0000'))fail();const d=new Date(s+'T00:00:00Z');if(!Number.isFinite(+d)||d.toISOString().slice(0,10)!==s)fail();return d;};\n  const iso=d=>{if(!Number.isFinite(+d)||d.getUTCFullYear()<1||d.getUTCFullYear()>9999)fail();return d.toISOString().slice(0,10);};\n  const shift=(d,n)=>{const r=new Date(+d+n*DAY);iso(r);return r;};\n  const month=(d,n)=>{const r=new Date(+d);r.setUTCDate(1);r.setUTCMonth(r.getUTCMonth()+n);const end=new Date(+r);end.setUTCMonth(end.getUTCMonth()+1,0);r.setUTCDate(Math.min(d.getUTCDate(),end.getUTCDate()));iso(r);return r;};\n  const weekdays=['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];\n  const work=(d,count)=>{let n=Math.floor(count/7)*5;for(let k=0;k<count%7;k++){const w=(d.getUTCDay()+k)%7;if(w!==0&&w!==6)n++;}return n;};\n  const wholeMonths=(a,b)=>{let n=(b.getUTCFullYear()-a.getUTCFullYear())*12+b.getUTCMonth()-a.getUTCMonth();if(n>=0&&+month(a,n)>+b)n--;if(n<0&&+month(a,n)<+b)n++;return n;};\n  return {DAY,own,fail,num,choice,date,iso,shift,month,weekdays,work,wholeMonths};\n})();const result=(function(v,h){\n    const {num,choice}=h;num(v.length,0,1000);num(v.width,0,1000);num(v.depthIn,0.001,120);num(v.settling,0,100);\n    choice(v.bagMode,['volume','weight']);choice(v.purchaseMode,['bags','bulk']);choice(v.soilType,['topsoil','compost','mix','sand','clay','custom']);\n    if(v.soilType==='custom')num(v.density,0.01,10);\n    if(v.bagMode==='volume')num(v.bagSize,0.001,100);else num(v.bagWeightLb,0.001,10000);\n    num(v.pricePerBag,0,1e6);num(v.pricePerCuyd,0,1e6);\n    const D={topsoil:1.1,compost:0.8,mix:0.55,sand:1.35,clay:1.3},density=v.soilType==='custom'?v.density:D[v.soilType],cubicFeet=v.length*v.width*v.depthIn/12*(1+v.settling/100),cubicYards=cubicFeet/27,weightTons=cubicYards*density;\n    const bags=Math.ceil(v.bagMode==='volume'?cubicFeet/v.bagSize:weightTons*2000/v.bagWeightLb),bagCost=bags*v.pricePerBag,bulkCost=cubicYards*v.pricePerCuyd;\n    return {cubicFeet,cubicYards,bags,weightTons,cost:v.purchaseMode==='bags'?bagCost:bulkCost,bagCost,bulkCost};\n  })({\"length\":(length),\"width\":(width),\"depthIn\":(depthIn),\"settling\":(settling),\"bagSize\":(bagSize),\"pricePerBag\":(pricePerBag),\"soilType\":(soilType),\"density\":(density),\"bagMode\":(bagMode),\"bagWeightLb\":(bagWeightLb),\"pricePerCuyd\":(pricePerCuyd),\"purchaseMode\":(purchaseMode)},h);return result;};const out=calculate();return Object.fromEntries([\"cubicFeet\",\"cubicYards\",\"bags\",\"weightTons\",\"cost\",\"bagCost\",\"bulkCost\"].map(k=>[k,out[k]??null]).concat(Object.entries(out).filter(([k])=>k.startsWith('__'))));}catch(error){return Object.assign(Object.fromEntries([\"cubicFeet\",\"cubicYards\",\"bags\",\"weightTons\",\"cost\",\"bagCost\",\"bulkCost\"].map(k=>[k,null])),{__error:error.message==='openingsExceedWallArea'?'openingsExceedWallArea':'inputError'});}",
    "inputs": [
      {
        "name": "length",
        "type": "number",
        "default": 8,
        "min": 0,
        "max": 1000,
        "step": 0.5,
        "slider": true,
        "strictRange": true,
        "requiredValue": true
      },
      {
        "name": "width",
        "type": "number",
        "default": 4,
        "min": 0,
        "max": 500,
        "step": 0.5,
        "slider": true,
        "strictRange": true,
        "requiredValue": true
      },
      {
        "name": "depthIn",
        "type": "number",
        "default": 12,
        "min": 0.5,
        "max": 60,
        "step": 0.5,
        "slider": true,
        "strictRange": true,
        "requiredValue": true
      },
      {
        "name": "settling",
        "type": "number",
        "default": 12,
        "min": 0,
        "max": 100,
        "step": 0.01,
        "slider": true,
        "strictRange": true,
        "requiredValue": true
      },
      {
        "name": "bagSize",
        "type": "number",
        "default": 1.5,
        "min": 0.001,
        "max": 100,
        "step": 0.01,
        "strictRange": true,
        "requiredValue": true,
        "showWhen": {
          "bagMode": [
            "volume"
          ]
        }
      },
      {
        "name": "pricePerBag",
        "type": "number",
        "default": 6,
        "min": 0,
        "max": 1000000,
        "step": 0.01,
        "slider": true,
        "strictRange": true,
        "requiredValue": true
      },
      {
        "type": "select",
        "default": "topsoil",
        "options": [
          {
            "value": "topsoil"
          },
          {
            "value": "compost"
          },
          {
            "value": "mix"
          },
          {
            "value": "sand"
          },
          {
            "value": "clay"
          },
          {
            "value": "custom"
          }
        ],
        "advanced": true,
        "name": "soilType"
      },
      {
        "type": "number",
        "default": 1.1,
        "min": 0.01,
        "max": 10,
        "step": 0.01,
        "strictRange": true,
        "requiredValue": true,
        "advanced": true,
        "name": "density",
        "showWhen": {
          "soilType": [
            "custom"
          ]
        }
      },
      {
        "type": "select",
        "default": "volume",
        "options": [
          {
            "value": "volume"
          },
          {
            "value": "weight"
          }
        ],
        "advanced": true,
        "name": "bagMode"
      },
      {
        "type": "number",
        "default": 40,
        "min": 0.001,
        "max": 10000,
        "step": 0.01,
        "strictRange": true,
        "requiredValue": true,
        "advanced": true,
        "name": "bagWeightLb",
        "showWhen": {
          "bagMode": [
            "weight"
          ]
        }
      },
      {
        "type": "number",
        "default": 40,
        "min": 0,
        "max": 1000000,
        "step": 0.01,
        "strictRange": true,
        "requiredValue": true,
        "advanced": true,
        "name": "pricePerCuyd"
      },
      {
        "type": "select",
        "default": "bags",
        "options": [
          {
            "value": "bags"
          },
          {
            "value": "bulk"
          }
        ],
        "advanced": true,
        "name": "purchaseMode"
      }
    ],
    "outputs": [
      {
        "name": "cubicFeet",
        "precision": 1,
        "unit": "cu ft",
        "notation": "auto"
      },
      {
        "name": "cubicYards",
        "precision": 2,
        "unit": "cu yd",
        "notation": "auto"
      },
      {
        "name": "bags",
        "precision": 0,
        "unit": "",
        "notation": "auto"
      },
      {
        "name": "weightTons",
        "precision": 2,
        "unit": "tons",
        "notation": "auto"
      },
      {
        "name": "cost",
        "precision": 2,
        "unit": "$",
        "notation": "auto"
      },
      {
        "precision": 2,
        "unit": "$",
        "name": "bagCost",
        "notation": "auto"
      },
      {
        "precision": 2,
        "unit": "$",
        "name": "bulkCost",
        "notation": "auto"
      }
    ],
    "interpret": null
  }
}
