Skip to main content
Docs

Search guides and API endpoints, for example “Idempotency-Key” or “submit job”.

    Tools · Fluids & Thermodynamics

    Reaction Calorimetry & Thermal-Safety Model

    Simulate the temperature and heat flow of a batch or semi-batch reactor, and screen its thermal-runaway risk if cooling fails.

    Updated October 1, 2026

    On this page

    Prices, workflows, and method papersOpen in the app

    This tool models one liquid batch or semi-batch vessel from your reaction kinetics and heats of reaction: how temperature, concentrations, and heat flow evolve, and what would happen if cooling failed at any moment. It reports the standard thermal-safety screening numbers, with sensitivities and an optional Monte Carlo spread.

    It is a screening model, not a certified safety assessment. It runs on CPU.

    How it works

    • Modes: batch or semi_batch (one reactant fed at a constant rate), each adiabatic or jacketed (heat removed through the jacket: UA × (T − T_jacket)).
    • Model: a lumped energy balance on the reaction mass, with Arrhenius mass-action kinetics, per-reaction enthalpies, and a heat capacity (constant or a table against temperature). Volume and composition follow the feed exactly.
    • Cooling-failure scan: at many instants through the process, cooling and dosing are switched off and the mixture is followed adiabatically. From this come:
      • MTSR, the maximum temperature of the synthesis reaction after a failure, and when the worst failure happens;
      • ΔT_ad, the adiabatic temperature rise if the whole charge reacts;
      • TMR_ad, the adiabatic time to maximum rate at the failure state (a conservative zero-order estimate);
      • the heat still to be released (accumulation) at each instant.
    • Sensitivities of these results to every rate, activation energy, enthalpy, and the vessel parameters, and an optional Monte Carlo (up to 200 samples) from the uncertainties you give, reported as 5th, 50th, and 95th percentiles.

    Inputs

    • kinetics: one row per irreversible reaction with its rate (k at a reference temperature with ea_j_mol, or a with ea_j_mol). The parameters table from Kinetic Parameter Fitter can be used as is, uncertainties included.
    • thermochemistry: each reaction's enthalpy (negative is exothermic).
    • vessel: volume, starting temperature, density, heat capacity, and for jacketed operation UA and the jacket temperature (fixed or ramped).
    • dosing (semi-batch): the feed, its volume, and dose time.
    • time_end and time_unit, and optional uncertainty.

    Limits: 20 reactions, 30 species, and 200 Monte Carlo samples.

    Outputs

    FileContents
    trajectory.csvTemperature, volume, conversion, and concentrations over time
    heat_flow.csvHeat released, removed, and accumulated over time
    cooling_failure.csvFor each failure instant: the temperature reached, TMR_ad, and heat accumulation
    safety_summary.csvMTSR, ΔT_ad, TMR_ad, and peak temperature, with Monte Carlo percentiles
    sensitivity.csvHow each result responds to each parameter

    Not covered

    Decomposition kinetics, gas evolution and pressure, multiphase systems, relief sizing, and regulatory criticality classes.

    Run it from the API

    Submit with Submit a job and the job_type below. Price it first with Estimate job reservation cost: submitting reserves that amount from your wallet, and the charge settles at the actual runtime.

    Reaction Calorimetry & Thermal-Safety Model reaction-calorimetry

    Job type
    reaction-calorimetry
    Hardware
    cpu (default)
    Typical runtime
    1 min on CPU

    Payload

    Payload fields
    FieldTypeDescription
    modestring

    One of: "batch", "semi_batch"

    coolingstring

    One of: "adiabatic", "jacketed"

    kineticsrequiredtableValue
    thermochemistryrequiredtableValue
    heat_capacitytableValue
    initial_concentrationsrequiredconcentrations
    vesselrequiredobject
    vessel.volume_lrequirednumber

    Limits: ≥ 0.001, ≤ 100000

    vessel.density_kg_lnumber

    Limits: ≥ 0.3, ≤ 3

    vessel.cp_j_kg_knumber

    Limits: ≥ 500, ≤ 10000

    vessel.t0_krequiredtemperatureK

    Limits: ≥ 200, ≤ 800

    vessel.ua_w_knumber

    Limits: ≥ 0.001, ≤ 10000000

    vessel.ua_scalingstring

    One of: "constant", "wetted_area"

    vessel.jacket_t_ktemperatureK

    Limits: ≥ 200, ≤ 800

    vessel.jacket_ramp_k_per_minnumber

    Limits: ≥ -20, ≤ 20

    vessel.jacket_t_final_ktemperatureK

    Limits: ≥ 200, ≤ 800

    dosingobject
    dosing.feedrequiredconcentrations
    dosing.feed_volume_lrequirednumber

    Limits: ≥ 0.001, ≤ 100000

    dosing.dose_timerequirednumber

    Limits: > 0

    dosing.start_timenumber

    Limits: ≥ 0

    dosing.feed_t_ktemperatureK

    Limits: ≥ 200, ≤ 800

    time_endrequirednumber

    Limits: > 0

    time_unitstring

    One of: "s", "min", "h"

    n_pointsinteger

    Limits: ≥ 11, ≤ 2001

    uncertaintyobject
    uncertainty.monte_carlo_samplesinteger

    Limits: ≥ 0, ≤ 200

    uncertainty.seedinteger

    Limits: ≥ 0, ≤ 2147483647

    uncertainty.ua_rel_sdnumber

    Limits: ≥ 0, ≤ 1

    uncertainty.cp_rel_sdnumber

    Limits: ≥ 0, ≤ 1

    Example

    from cognichem_client import CogniChem
    
    client = CogniChem.from_env()  # reads COGNICHEM_API_KEY
    payload = {
        "mode": "semi_batch",
        "cooling": "jacketed",
        "kinetics": "reaction_id,equation,status,order,k,k_stderr,k_units,t_ref_k… (181 characters)",
        "thermochemistry": [
            {
                "reaction_id": "R1",
                "dh_rxn_kj_mol": -150,
                "dh_rxn_stderr_kj_mol": 7.5,
            },
        ],
        "initial_concentrations": {"A": 2},
        "vessel": {
            "volume_l": 2,
            "density_kg_l": 1,
            "cp_j_kg_k": 2000,
            "t0_k": 313.15,
            "ua_w_k": 10,
            "ua_scaling": "wetted_area",
            "jacket_t_k": 313.15,
        },
        "dosing": {
            "feed": {"B": 4},
            "feed_volume_l": 1,
            "dose_time": 60,
            "start_time": 0,
            "feed_t_k": 298.15,
        },
        "time_end": 180,
        "time_unit": "min",
        "n_points": 361,
        "uncertainty": {
            "monte_carlo_samples": 3,
            "seed": 7,
            "ua_rel_sd": 0.1,
            "cp_rel_sd": 0.05,
        },
    }
    
    estimate = client.jobs.estimate(job_type="reaction-calorimetry", payload=payload, resource="cpu")
    print(f"Reserves ${estimate.cost:.2f}")
    
    job = client.jobs.submit(
        job_name="my-reaction-calorimetry-run",
        job_type="reaction-calorimetry",
        payload=payload,
        resource="cpu",
    )
    status = client.jobs.wait(job.process_id)
    if status.status == "completed":
        client.jobs.result(job.process_id, save_path=".")

    Sample data from the job catalog; long values are shortened here. Each job_name must be unique among your jobs.

    Workflow inputs

    • Table (list) · optionalCSV, JSON
    • Table (list)CSV, JSON
    • Table (list)CSV, JSON

    Workflow outputs

    • ArchiveZIP
    • TableCSV
    • TableCSV
    • TableCSV
    • TableCSV
    • TableCSV