Automate Engineering Calculations at Scale Using Python and the CalcTree API

Repetitive calculations across multiple input scenarios are common in engineering workflows — but running each case manually or in isolation is inefficient.

CalcTree lets you build and verify a calculation once in a no-code interface, then reuse it programmatically via API. The key benefits of using CalcTree is that it enhances standardization and reduces errors across multiple projects. After validating logic and results on a page, you can confidently call that same calculation from other systems, leveraging the enhanced capabilities of the CalcTree API. This complete solution not only meets client needs but also enhances collaboration and efficiency in engineering tasks through standardized templates.

Automate engineering workflows via CalcTree's API

This guide shows how to use Python and the CalcTree Bulk Calculation API to run hundreds of calculations in a single request. It reduces network overhead, ensures consistency, and makes your workflows more scalable.

Bulk Calculations With Confidence

Engineering workflows often require running the same logic across many input cases — for design checks, parametric studies, or scenario analysis. Doing this manually or in Excel introduces risks: formulas must be reimplemented in Excel syntax, logic is scattered and hard to audit, and errors propagate easily across large files.

CalcTree solves this by letting you define and verify your engineering logic once, in a structured and transparent format. The calculation is built in a no-code or Python editor that enforces units, dependencies, and clear formulas. Once verified, the same CalcTree page can be reused in multiple environments — directly in the UI, via plugins like Excel and Grasshopper, or programmatically through the API, utilizing engineering calculation templates across various disciplines. These templates are created to enhance standardization and collaboration among engineers, allowing for customization according to specific project needs while ensuring a consistent approach.

CalcTree's no-code or Python editor

When comparing CalcTree with traditional methods like Excel, CalcTree offers a more reliable and efficient solution by centralizing and verifying calculations, reducing the risk of errors and inconsistencies.

This guide focuses on the API method: using Python to run bulk calculations in a single request. It allows you to apply a trusted, centralized calculation to hundreds of input sets efficiently, without rewriting or duplicating logic.

Scaling Engineering Calculations with the CalcTree API

A common bottleneck in automated engineering workflows is API performance. Most systems process calculations sequentially — and when running hundreds of requests in a loop, latency adds up quickly. This slows down parametric studies, optimizations, and any high-volume scenario where performance matters.

CalcTree solves this by allowing bulk execution of calculations using a single, optimized GraphQL request. Unlike traditional tools that evaluate inputs one-by-one, CalcTree pages execute in parallel, catering to diverse engineering needs. This enables significantly faster runtimes when working at scale.

The approach outlined in this guide uses Python to structure and submit batch input data to a verified CalcTree page. The API handles all execution, returning results efficiently in one response. This model is scalable, consistent, and works across disciplines — from structural checks to simulation post-processing — wherever large sets of engineering data need to be processed reliably, showcasing the power of the CalcTree API.

CalcTree API Overview

The CalcTree API features high-performance workflows, including bulk execution where many input sets are processed in parallel, allowing engineers to programmatically run verified calculation pages from any environment. Built on GraphQL, it supports efficient and scalable operations.

CalcTree API is built on GraphQL

Each CalcTree page acts as a reusable, version-controlled template. Logic is defined once, then accessed via the API, plugins (like Excel or Grasshopper), or the UI.

Various elements make the CalcTree API effective for engineering workflows, such as its ability to centralize engineering logic, reduce manual effort, and enable fast, consistent, and concurrent calculations at scale.

What You’ll Learn in This Guide

We’ll walk through how to take a verified CalcTree page and use it as a template to process a dataset — checking each row of inputs and returning a structured set of results, all through a single Python function in this course.

In this post, you’ll learn how to:

  • Extract the necessary IDs from your CalcTree calculation page
  • Retrieve input structure with a GraphQL query
  • Format your input data and send a single bulk calculation request
  • Parse and format the API results (including units)
  • Run everything in one fast, automated Python function
  • Create calculation templates to streamline workflows
  • Access various resources to enhance your understanding and efficiency

Let’s walk through the process step-by-step.

Setting Up the Environment

To get started with automation, it’s essential to set up the right environment. This includes choosing the right tools and technologies, such as GraphQL APIs, Python code, and automation frameworks. It’s also important to consider security and authentication, to ensure that automated tasks are secure and authorized. By setting up the right environment, engineers and developers can ensure that automation is effective and efficient. For example, setting up a GraphQL server can provide a unified graph of data, making it easier to automate queries and retrieval. This setup not only simplifies the process but also ensures that the data is consistent and easily accessible, which is crucial for efficient automation.

1. Set Up Your API Endpoint

We’ll use the CalcTree GraphQL API to submit and retrieve data:

GRAPHQL_ENDPOINT = "https://graph.calctree.com/graphql"
REVISION_ID = "fffffffffff"  # Use the latest revision ID

The CalcTree API can be utilized in various environments, from complex software systems requiring high customization to user-friendly platforms that prioritize scalability.

2. Extract IDs from Your CalcTree URL

Each CalcTree page has a unique workspaceId and calculationId. We can extract them automatically from the URL:

from typing import List, Dict, Tuple

def extract_ids_from_url(url: str) -> Tuple[str, str]:
    """Extract workspaceId and calculationId from a CalcTree URL."""
    parts = url.strip().split("/")
    if len(parts) >= 6 and parts[3] == "edit":
        workspace_id = parts[4]
        calculation_id = parts[5]
        return workspace_id, calculation_id
    else:
        raise ValueError("Invalid URL format. Expected format: https://.../edit/{workspaceId}/{calculationId}")

Additionally, the properties of the data being extracted, such as the workspaceId and calculationId, are crucial for ensuring accurate data retrieval and efficient application performance. The CalcTree API provides robust support for extracting these IDs, which helps streamline the workflow and enhances overall efficiency.

Each CalcTree page also has a unique page ID you can call from your API

3. Get the Calculation Structure via GraphQL

Before submitting data, we need to know how the calculation is structured — specifically which statementId maps to which input variable. This involves using a query language to retrieve the calculation structure.

import requests
import json

def fetch_calculation_structure(api_key: str, workspace_id: str, calculation_id: str) -> List[Dict]:
    """Fetches calculation structure to retrieve parameter names and statement IDs."""
    query = """
    query GetCalculation($workspaceId: ID!, $calculationId: ID!, $revisionId: ID!) {
      calculation(workspaceId: $workspaceId, calculationId: $calculationId, revisionId: $revisionId) {
        calculationId
        statements {
          statementId
          title
          engine
          formula
          namedValues {
            name
            value
          }
        }
      }
    }
    """
    payload = {
        "query": query,
        "variables": {
            "workspaceId": workspace_id,
            "calculationId": calculation_id,
            "revisionId": REVISION_ID,
        }
    }
    headers = {
        "Content-Type": "application/json",
        "x-api-key": api_key,
    }
    response = requests.post(GRAPHQL_ENDPOINT, headers=headers, json=payload)
    if not response.ok:
        raise Exception(f"Failed to fetch calculation structure: {response.status_code} {response.text}")
    data = response.json()
    if "errors" in data:
        raise Exception(f"GraphQL errors: {data['errors']}")
    return data.get("data", {}).get("calculation", {}).get("statements", [])

4. Format Output for Units and Readability

CalcTree returns detailed metadata with each result. We clean these into correct, human-readable strings, and spreadsheets can be used to format output data efficiently:

def format_output_value(raw_value) -> str:
    """Formats output values to handle units and simple numbers."""
    if isinstance(raw_value, str):
        try:
            parsed = json.loads(raw_value)
            if isinstance(parsed, dict):
                if parsed.get("mathjs") == "Unit":
                    value = parsed.get("value", "")
                    unit = parsed.get("unit", "")
                    try:
                        value = round(float(value), 6)
                    except (TypeError, ValueError):
                        pass
                    return f"{value} {unit}".strip()
                if parsed.get("type") == "image":
                    return "[Image]"
        except json.JSONDecodeError:
            pass
    return str(raw_value)

5. Send a Batch GraphQL Mutation

Instead of sending one request per input set, we send one well-structured GraphQL mutation with multiple embedded calculations to address specific project needs.

The API leverages existing data and code to perform these batch mutations efficiently.

def calculate_mutations_batch(api_key: str, batch_requests: List[Dict]) -> List[Dict]:
    """Send a batch of GraphQL mutations to perform multiple calculations."""
    variables = {}
    mutations = []

    for idx, req in enumerate(batch_requests):
        base_name = f"EXL_BTCH_calc{idx}"
        variables[f"{base_name}_workspaceId"] = req["workspaceId"]
        variables[f"{base_name}_calculationId"] = req["calculationId"]
        variables[f"{base_name}_revisionId"] = REVISION_ID
        variables[f"{base_name}_statements"] = json.loads(req["statements"])

        mutation = f"""
        {base_name}: calculate(
          workspaceId: ${base_name}_workspaceId,
          calculationId: ${base_name}_calculationId,
          revisionId: ${base_name}_revisionId,
          statements: ${base_name}_statements
        ) {{
          statements {{
            statementId
            errors
            namedValues {{
              name
              value
            }}
          }}
        }}
        """
        mutations.append(mutation)

    query = f"""
    mutation ({', '.join([f"${key}: {'[StatementInput!]!' if key.endswith('_statements') else 'ID!'}" for key in variables])}) {{
      {''.join(mutations)}
    }}
    """
    headers = {
        "Content-Type": "application/json",
        "x-api-key": api_key,
    }
    payload = {
        "query": query,
        "variables": variables,
    }
    response = requests.post(GRAPHQL_ENDPOINT, headers=headers, json=payload)
    if not response.ok:
        raise Exception(f"Batch calculation API call failed: {response.status_code} {response.text}")
    
    data = response.json()

    results = []
    for idx in range(len(batch_requests)):
        base_name = f"EXL_BTCH_calc{idx}"
        result = data.get("data", {}).get(base_name)
        if not result:
            results.append({"error": f"Missing result for {base_name}"})
            continue
        output = {}
        for stmt in result.get("statements", []):
            for nv in stmt.get("namedValues", []):
                output[nv["name"]] = nv["value"]
        results.append(output)

    return results

The functions involved in this process handle the data efficiently, ensuring that each mutation is correctly calculated and integrated within the batch request.

6. Automate the Entire Workflow in Python

The bulk_calculate function is the driver of the entire bulk calculation process, supporting different versions of the API used in the workflow.

It calls the prior functions to perform the following steps:

  • Extracts the workspace ID and calculation ID from the page URL.
  • Fetches the structure of the calculation to match input parameter names to their correct statementId.
  • Organizes each input row into a set of calculation statements.
  • Builds a list of batch requests to submit together.
  • Calls calculate_mutations_batch to execute all calculations in one API call.
  • Formats the output by cleaning up unit values and organizing results into a structured table.

This function allows you to run many calculations at once on a CalcTree page using only one API request, making the process both scalable and fast. You can write code to automate this workflow efficiently.

def bulk_calculate(api_key: str, url: str, input_data: List[List], output_names: List = None) -> List[List]:
    """Perform bulk calculations on a CalcTree template page."""
    workspace_id, calculation_id = extract_ids_from_url(url)

    if not input_data or len(input_data) <  2:
        raise ValueError("Input data must include at least a header and one data row.")

    input_names = input_data[0]
    input_values = input_data[1:]

    # Fetch page structure
    statements = fetch_calculation_structure(api_key, workspace_id, calculation_id)

    batch_requests = []
    for row in input_values:
        if len(row) != len(input_names):
            raise ValueError("Input row length must match header length.")

        statements_list = []
        for name, value in zip(input_names, row):
            matching_statement = next(
                (stmt for stmt in statements if any(nv.get("name") == name for nv in stmt.get("namedValues", []))),
                None
            )
            if not matching_statement:
                raise ValueError(f"No matching statement found for input: {name}")

            statement_id = matching_statement["statementId"]
            statements_list.append({
                "statementId": statement_id,
                "formula": f"{name}={value}"
            })

        batch_requests.append({
            "workspaceId": workspace_id,
            "calculationId": calculation_id,
            "statements": json.dumps(statements_list),
            "apiKey": api_key
        })

    batch_results = calculate_mutations_batch(api_key, batch_requests)

    # Format results
    formatted_results = []
    all_keys = []
    for res in batch_results:
        if isinstance(res, dict) and "error" not in res:
            all_keys = list(res.keys())
            break

    if not all_keys:
        return [["Error: No valid results returned."]]

    formatted_results.append(all_keys)

    for res in batch_results:
        row = []
        for key in all_keys:
            raw_value = res.get(key, "")
            row.append(format_output_value(raw_value))
        formatted_results.append(row)

    return formatted_results

Just provide your API key, the URL of your CalcTree template page, and a matrix of inputs.

To implement the entire workflow in Python, follow best practices for developing and executing complex workflows to ensure fast and successful computation.

7. Example: Calculate Areas for Multiple Width/Length Pairs

if __name__ == "__main__":
    API_KEY = "YOUR_API_KEY"
    URL = "https://app.calctree.com/edit/your-workspace-id/your-calculation-id"

    input_data = [
        ["w", "l"],
        [1, 4],
        [2, 5],
        [3, 4.5],
        [4, 6],
        [5, 3],
        [5, 4]
    ]

    result_table = bulk_calculate(API_KEY, URL, input_data)

    for row in result_table:
        print(row)

Output:

['w', 'l', 'area']
['1', '4', '10.0 m^2']
['2', '5', '10.0 m^2']
['3', '4.5', '10.0 m^2']
['4', '6', '10.0 m^2']
['5', '3', '10.0 m^2']
['5', '4', '10.0 m^2']

This example demonstrates how the calculations can benefit an app by providing quick and efficient data processing, which is particularly useful for improving speed and performance on slower mobile networks.

Automate Bulk Calculations with Python and CalcTree

This approach lets you scale up a verified CalcTree page to handle large datasets efficiently — without rewriting the logic or running each case manually. By structuring a single API request, you can evaluate hundreds of scenarios in parallel, with consistent logic and clean outputs.

Whether you’re working on structural design checks, load combinations, or parameter sweeps, this workflow gives you a reliable and repeatable way to integrate engineering calculations into your Python-based tools or automation pipelines. Additionally, the flexibility of using various programming languages ensures seamless integration with your existing data and code.

Want to try it yourself? Sign up for CalcTree or read the full API documentation to dive deeper.

Related resources
Ready to try?

Streamline your engineering workflows today!

Join engineers from top firms who've signed up

Try CalcTree free
AECOM
ARCADIS
aurecon
Jacobs
MOTT MACDONALD
wsp