# HVAC Duct Calculator: Duct Sizing, Pressure Loss, CFM (`jumblemog/duct-calculator`) Actor

HVAC duct sizing from plain text: round and rectangular ducts by friction rate or velocity, duct run pressure loss with fittings, filters and diffusers, and the airflow (cfm or L/s) for a load or air changes, with a friction chart.

- **URL**: https://apify.com/jumblemog/duct-calculator.md
- **Developed by:** [Jumble Mog](https://apify.com/jumblemog) (community)
- **Categories:** AI, Automation, Developer tools
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## HVAC Duct Calculator: Duct Sizing, Pressure Loss, CFM

**HVAC duct sizing from one line of text.** Type `size a round duct for 1000 cfm`, `500 L/s, 1 Pa/m, max height 300 mm`, `1200 cfm, 14 in round, 80 ft, 4 elbows, 1 tee, filter 0.3 in wc` or `cooling load 24000 Btu/h, supply 55 F, room 75 F`. You get back:

- **Duct sizes**: the standard round size and the exact diameter for a friction rate (equal friction), a maximum velocity, or both; the sizes around it with their velocity and friction; and up to five rectangular options (least sheet metal first, aspect ratio up to 4, or a height you set).
- **Duct checks**: velocity, velocity pressure, friction rate, Reynolds number, hydraulic and equivalent diameters for any round or rectangular duct.
- **Duct run pressure loss**: friction over the length, fittings (elbows, tees, wyes, takeoffs, dampers, transitions, exits) from typical ASHRAE loss coefficients, and components like filters, coils and diffusers at their pressure drops; several sections in series for the path to the farthest outlet.
- **Airflow**: cfm or L/s for a sensible heating or cooling load at a temperature difference, or for air changes per hour in a room, and the duct that carries it.
- **A chart**: the duct friction chart (round ducts and velocity lines) with your duct on it, or the pressure drop of each section split into friction, fittings and components.

US (cfm, in, ft, fpm, in. w.c.) or metric (L/s, m³/h, mm, m, m/s, Pa): results come back in the units you wrote. Air at other temperatures and altitudes, and galvanized, aluminum, PVC, duct board, lined or flex duct.

It's made for:

- HVAC designers, mechanical engineers and contractors sizing ductwork.
- Estimators and installers checking existing ducts and fan static pressure.
- HVAC students learning the equal friction method.
- AI agents that need real duct numbers instead of a rule of thumb.

![The duct friction chart drawn by this Actor for 500 L/s at 1 Pa/m: round duct lines from 160 to 560 mm and velocity lines from 2 to 12 m/s on log scales, with the chosen 355 mm duct marked at 0.81 Pa/m and 5.05 m/s](https://api.apify.com/v2/key-value-stores/Km5b4PG3kYHdZSb1E/records/duct-calculator-example.png?signature=rGQvnRWY1nNFJhX1DuIM)

### How to use it

1. Write **Ducts, runs and airflows**, one per entry. The form has examples.
2. Optionally set the **Units** for numbers written without one.
3. Click **Start**. Each request is a row in the results, with its summary, chart and report.

#### What you can write

| You write | It means |
|---|---|
| `1000 cfm`, `500 L/s`, `1800 m3/h` | The airflow |
| `0.08 in wc/100 ft`, `1 Pa/m` | Friction rate to size for (0.1 in/100 ft or 0.8 Pa/m by default) |
| `max velocity 900 fpm`, `5 m/s` | Velocity limit to size for |
| `max height 12 in`, `depth 300 mm` | A fixed side for rectangular options |
| `12 in round`, `250 mm duct`, `400 x 250 mm`, `24 x 12 in` | A duct to check (or to use in a run) |
| `80 ft`, `25 m long` | Length of the run |
| `4 elbows`, `1 tee`, `2 vaned elbows`, `mitered elbow`, `45 elbow`, `wye`, `takeoff`, `damper`, `exit` | Fittings |
| `filter 0.3 in wc`, `coil 120 Pa`, `diffuser 25 Pa` | Components and their pressure drops |
| `flex`, `duct board`, `lined`, `aluminum`, `pvc` | Duct material (galvanized by default) |
| `air at 120 F`, `altitude 5000 ft` | Air conditions (20 °C at sea level by default) |
| `24000 Btu/h`, `2 tons`, `5 kW` with `supply 55 F, room 75 F` or `delta T 20 F` | Airflow for a sensible load |
| `room 20 x 15 x 9 ft, 6 ACH` | Airflow for air changes |

Several sections go as an object: `{"type": "system", "sections": [{"name": "Main", "q": "2000 cfm", "w": "24 in", "h": "12 in", "length": "60 ft", "fittings": {"vaned elbow": 2}}, {"name": "Branch", "q": "400 cfm", "d": "10 in", "length": "30 ft", "fittings": {"takeoff": 1, "elbow": 2}, "components": {"diffuser": "0.08 in wc"}}]}`.

### Examples

- `size a round duct for 1000 cfm` → 14 in round (13.7 in exact) at 935 fpm and 0.088 in. w.c./100 ft; rectangular 14 x 12 in.
- `500 L/s, 1 Pa/m, max height 300 mm` → 355 mm round at 5.05 m/s; rectangular 350 x 300 mm.
- `rectangular duct for 2000 cfm, max velocity 1000 fpm, max height 12 in` → 24 x 12 in.
- `1200 cfm, 14 in round, 80 ft, 4 elbows, 1 tee, filter 0.3 in wc, diffuser 0.05 in wc` → 0.56 in. w.c. (friction 0.10, fittings 0.11, components 0.35).
- `cooling load 24000 Btu/h, supply 55 F, room 75 F` → 1107 cfm; a 15 in round duct.

### How-to examples

Each example is a complete input; the results are from runs of the Actor (also listed under **Examples**).

#### How to size a round or rectangular duct for a cfm

```json
{"requests": ["size a round duct for 1000 cfm"]}
```

Result: 14 in round (13.7 in exact) at 935 fpm and 0.088 in. w.c. per 100 ft, or a 14 x 12 in rectangular duct. In metric, `500 L/s, 1 Pa/m, max height 300 mm` gives 355 mm round or 350 x 300 mm.

#### How to calculate the pressure loss of a duct run

```json
{"requests": ["1200 cfm, 14 in round, 80 ft, 4 elbows, 1 tee, filter 0.3 in wc, diffuser 0.05 in wc"]}
```

Result: 0.56 in. w.c. in total: 0.10 friction, 0.11 fittings and 0.35 components.

#### How to find the airflow for a cooling load

```json
{"requests": ["cooling load 24000 Btu/h, supply 55 F, room 75 F"]}
```

Result: 1107 cfm, carried by a 15 in round duct.

#### How to let an AI agent size ducts

Add this Actor to the [Apify MCP server](https://mcp.apify.com) with `https://mcp.apify.com/?tools=jumblemog/duct-calculator`. The agent passes the airflow or load in one line and answers with the duct size, velocity and friction rate, instead of reading a duct calculator wheel from memory.

### FAQ

**Which sizing method does it use?** Equal friction, a maximum velocity, or both, with the standard round size, the exact diameter and rectangular equivalents.

**Where do the fitting losses come from?** Typical ASHRAE loss coefficients for elbows, tees, wyes, takeoffs, dampers, transitions and exits.

**Does it work in metric?** Yes. Results come back in the units you wrote: cfm, in and in. w.c., or L/s, mm and Pa.

**Can I change the duct material or air temperature?** Yes: galvanized steel, aluminum, PVC, duct board and other linings, and air at other temperatures and altitudes.

### Input

| Field | What it is |
|---|---|
| `requests` | The ducts, runs and airflows, as lines of text or objects (up to 200 per run) |
| `units` | For numbers without a unit: `m` (metric) or `ft` (US) |
| `charts` | Draw a chart for each request (default on) |

### Output

One dataset item per request, also saved together in the run's `OUTPUT` record:

```json
{
  "request": 1, "status": "ok", "type": "duct", "mode": "size", "title": "Duct size for 1000 cfm",
  "summary": "14 in round (exact 13.7 in): 935.4 fpm, 0.08846 in. w.c./100 ft; rectangular 14 x 12 in.",
  "design": {"flow": 1000.0, "frictionLimit": 0.1, "exactDiameter": 13.65, "governedBy": "friction",
             "material": "galvanized", "roughnessMm": 0.09},
  "round": [{"size": "13 in round", "diameter": 13.0, "velocity": 1085.0, "frictionRate": 0.1273, "fits": false},
            {"size": "14 in round", "diameter": 14.0, "velocity": 935.4, "frictionRate": 0.08846, "fits": true}],
  "rectangular": [{"size": "14 x 12 in", "width": 14.0, "height": 12.0, "velocity": 857.1, "frictionRate": 0.08304,
                   "equivalentDiameter": 14.16, "aspectRatio": 1.17}],
  "units": {"size": "in", "flow": "cfm", "velocity": "fpm", "gradient": "in. w.c./100 ft", "...": "..."},
  "imageUrl": "https://api.apify.com/v2/key-value-stores/.../records/001-Duct-size-for-1000-cfm.png"
}
```

Checks have `duct` and `flow`; runs have `sections`, `fittings`, `components` and `total`; airflows have `airflow` and the `duct` for it. Every item has `air`, `units`, `summary`, `warnings`, `notes` (the method and assumptions), a Markdown `report` and links to the chart and report. A request that can't be computed has `"status": "failed"` and the reason in `error`, and isn't billed.

### How it works

1. **Air**: density from the temperature and the barometric pressure at the altitude; viscosity by Sutherland's law.
2. **Friction**: Darcy-Weisbach, Δp/L = f/D · ρV²/2, with the Colebrook friction factor and ASHRAE's roughness for the material (galvanized 0.09 mm); rectangular ducts use the hydraulic diameter, and Huebscher's equivalent diameter (1.30·(ab)^0.625/(a+b)^0.25) is given for comparison. This reproduces the ASHRAE friction chart.
3. **Sizing**: the diameter where the friction rate meets the limit (and the velocity stays under its limit), rounded up to the standard sizes (US 4 to 60 in, EN 1506 63 to 1600 mm); rectangular sides from standard sizes.
4. **Fittings**: Δp = C × velocity pressure, with typical coefficients from the ASHRAE Duct Fitting Database (smooth elbow r/D 1.5: 0.15, mitered elbow: 1.2, tee branch: 0.8...).
5. **Airflow**: Q = load / (ρ·cp·ΔT), the 1.08 rule at standard air.

Fitting coefficients depend on the exact geometry and flow split; look up the exact fitting for final design and fan selection.

### Pricing

You pay one low price per request, at the prices shown on this page; airflows cost less than duct sizes and runs. The chart and report are included. Requests that can't be computed are never charged. If you set a maximum cost per run, the Actor stops before a request that wouldn't fit.

### Speed

Each request takes a few milliseconds. A run through the API answers in about 10 seconds, including the cloud container starting.

### Tips and limits

- **Velocity**: it warns above 2500 fpm (12.7 m/s), where low-pressure duct gets noisy, and when a duct is far larger than needed.
- **Flex duct** is taken fully stretched; sagging or compressed flex loses several times more.
- **Systems** add sections in series. For the fan's external static pressure, give the path to the farthest (or most resistive) outlet.
- **Flat oval ducts** and duct leakage aren't modelled.
- **Limits**: 200 requests per run.

### For AI agents and developers

This Actor works with the [Apify MCP server](https://mcp.apify.com), so AI agents can call it as a tool. Pass `requests` as plain text and read `summary`, `flow`, `round`, `rectangular`, `total`, `airflow` and `warnings`. A direct API call that waits for the answer:

```bash
curl -X POST "https://api.apify.com/v2/acts/jumblemog~duct-calculator/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"requests": ["size a round duct for 1000 cfm"]}'
```

`run-sync` instead returns the run's `OUTPUT`: the status, the counts and every result as JSON.

In Python, with the `apify-client` package:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")
run = client.actor("jumblemog/duct-calculator").call(run_input={
    "requests": [{"type": "duct", "q": "800 L/s", "velocity": "6 m/s", "fixed": "350 mm"}],
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["summary"])
```

### Credits

- Charts: [Vega-Lite](https://vega.github.io/vega-lite/) and [vl-convert](https://github.com/vega/vl-convert) (BSD-3-Clause), with the [Inter](https://rsms.me/inter/) font (SIL Open Font License).
- Methods: ASHRAE Handbook, *Fundamentals*, chapter 21 (Duct Design) and the ASHRAE Duct Fitting Database; Colebrook (1939); Huebscher (1948); EN 1506 round duct sizes.

# Actor input Schema

## `requests` (type: `array`):

One request per entry, as a line of text or an object. Duct sizing: the airflow ('1000 cfm', '500 L/s', '1800 m3/h') with a friction rate ('0.08 in wc/100 ft', '1 Pa/m'; 0.1 in/100 ft or 0.8 Pa/m by default), a maximum velocity ('900 fpm', '5 m/s') or both, and optionally a height limit for rectangular ducts: the standard round size, the exact diameter, and rectangular options. Duct check: a size ('12 in round', '400 x 250 mm') and an airflow: velocity, friction rate, velocity pressure. Duct runs: add a length, fittings ('4 elbows', '1 tee', 'mitered elbow', 'vaned elbow', '45 elbow', 'wye', 'takeoff', 'damper', 'fire damper', 'exit') and components with their pressure drop ('filter 0.3 in wc', 'coil 120 Pa', 'diffuser 25 Pa'): the total pressure drop; several sections as an object. Airflow: a sensible load ('24000 Btu/h', '2 tons', '5 kW') with ΔT or supply and room temperatures, or air changes ('room 20 x 15 x 9 ft, 6 ACH'); the duct for it. Materials: galvanized (default), aluminum, pvc, duct board, lined, flex. Air at another temperature ('air at 120 F') or altitude ('altitude 5000 ft'). Object fields: type (duct, system or airflow), q, d, w, h, fixed, friction, velocity, material, roughness (mm), design, length, fittings, components, sections (name, q, d or w and h, length, fittings, components, material), load, dt, supply, room, ach, volume, altitude, temperature, units, title, text.

## `units` (type: `string`):

For numbers written without a unit. cfm, fpm, inches or Btu/h in the text switch to US units on their own.

## `charts` (type: `boolean`):

The duct friction chart with the chosen size, or the pressure drop by section.

## Actor input object example

```json
{
  "requests": [
    "size a round duct for 1000 cfm",
    "500 L/s, 1 Pa/m, max height 300 mm",
    "rectangular duct for 2000 cfm, max velocity 1000 fpm, max height 12 in",
    "400 x 250 mm duct, 300 L/s",
    "1200 cfm, 14 in round, 80 ft, 4 elbows, 1 tee, filter 0.3 in wc, diffuser 0.05 in wc",
    "cooling load 24000 Btu/h, supply 55 F, room 75 F",
    {
      "type": "system",
      "sections": [
        {
          "name": "Main",
          "q": "2000 cfm",
          "w": "24 in",
          "h": "12 in",
          "length": "60 ft",
          "fittings": {
            "vaned elbow": 2,
            "tee straight": 1
          }
        },
        {
          "name": "Branch",
          "q": "400 cfm",
          "d": "10 in",
          "length": "30 ft",
          "fittings": {
            "takeoff": 1,
            "elbow": 2
          },
          "components": {
            "diffuser": "0.08 in wc"
          }
        }
      ]
    }
  ],
  "units": "m",
  "charts": true
}
```

# Actor output Schema

## `results` (type: `string`):

One row per request: the summary and chart.

## `output` (type: `string`):

The OUTPUT record: every result in one JSON object.

## `files` (type: `string`):

Charts (PNG and SVG) and Markdown reports in the run's key-value store.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "requests": [
        "size a round duct for 1000 cfm",
        "500 L/s, 1 Pa/m, max height 300 mm",
        "rectangular duct for 2000 cfm, max velocity 1000 fpm, max height 12 in",
        "400 x 250 mm duct, 300 L/s",
        "1200 cfm, 14 in round, 80 ft, 4 elbows, 1 tee, filter 0.3 in wc, diffuser 0.05 in wc",
        "cooling load 24000 Btu/h, supply 55 F, room 75 F",
        {
            "type": "system",
            "sections": [
                {
                    "name": "Main",
                    "q": "2000 cfm",
                    "w": "24 in",
                    "h": "12 in",
                    "length": "60 ft",
                    "fittings": {
                        "vaned elbow": 2,
                        "tee straight": 1
                    }
                },
                {
                    "name": "Branch",
                    "q": "400 cfm",
                    "d": "10 in",
                    "length": "30 ft",
                    "fittings": {
                        "takeoff": 1,
                        "elbow": 2
                    },
                    "components": {
                        "diffuser": "0.08 in wc"
                    }
                }
            ]
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("jumblemog/duct-calculator").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "requests": [
        "size a round duct for 1000 cfm",
        "500 L/s, 1 Pa/m, max height 300 mm",
        "rectangular duct for 2000 cfm, max velocity 1000 fpm, max height 12 in",
        "400 x 250 mm duct, 300 L/s",
        "1200 cfm, 14 in round, 80 ft, 4 elbows, 1 tee, filter 0.3 in wc, diffuser 0.05 in wc",
        "cooling load 24000 Btu/h, supply 55 F, room 75 F",
        {
            "type": "system",
            "sections": [
                {
                    "name": "Main",
                    "q": "2000 cfm",
                    "w": "24 in",
                    "h": "12 in",
                    "length": "60 ft",
                    "fittings": {
                        "vaned elbow": 2,
                        "tee straight": 1,
                    },
                },
                {
                    "name": "Branch",
                    "q": "400 cfm",
                    "d": "10 in",
                    "length": "30 ft",
                    "fittings": {
                        "takeoff": 1,
                        "elbow": 2,
                    },
                    "components": { "diffuser": "0.08 in wc" },
                },
            ],
        },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("jumblemog/duct-calculator").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "requests": [
    "size a round duct for 1000 cfm",
    "500 L/s, 1 Pa/m, max height 300 mm",
    "rectangular duct for 2000 cfm, max velocity 1000 fpm, max height 12 in",
    "400 x 250 mm duct, 300 L/s",
    "1200 cfm, 14 in round, 80 ft, 4 elbows, 1 tee, filter 0.3 in wc, diffuser 0.05 in wc",
    "cooling load 24000 Btu/h, supply 55 F, room 75 F",
    {
      "type": "system",
      "sections": [
        {
          "name": "Main",
          "q": "2000 cfm",
          "w": "24 in",
          "h": "12 in",
          "length": "60 ft",
          "fittings": {
            "vaned elbow": 2,
            "tee straight": 1
          }
        },
        {
          "name": "Branch",
          "q": "400 cfm",
          "d": "10 in",
          "length": "30 ft",
          "fittings": {
            "takeoff": 1,
            "elbow": 2
          },
          "components": {
            "diffuser": "0.08 in wc"
          }
        }
      ]
    }
  ]
}' |
apify call jumblemog/duct-calculator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jumblemog/duct-calculator"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/tn9iQTCp2G483qFyY/builds/Gw3ffR3ErquWaG5BK/openapi.json
