Skip to content

Python API

Process, Production and calculate_simple accept canonical trim_total_per_billet_m. Use migrate_legacy_trim(case, profiles_per_billet=2) for a verified legacy two-pull case. Non-null legacy/canonical combinations are rejected. See trim contract, migration and public counters.

Explicit legacy migration

migrate_legacy_trim(case, *, profiles_per_billet, use_multi_billet_override=None) accepts a StudyCase or PlanningCase. Supply the verified legacy p=1 or p=2 family; the helper does not infer it. If a legacy multibillet override is present, explicitly choose whether it was applied. True requires an existing override and p=1. The helper clears both legacy fields and returns a new immutable case; already canonical inputs are rejected.

Recalculate on the intended press after migration. Loading an old file or choosing a different press does not guarantee the same automatic family. A canonical value together with a non-null legacy value, even 0.0, is an ambiguity error. Omitted trim means zero.

Main objects

from pyextrusion import (
    Press,
    Profile,
    Production,
    StudyCase,
    Process,
    PlanningCase,
    PlanningRequest,
)

Press

Describes one direct extrusion press. table_length_m is mandatory.

Profile

Describes profile linear weight, exits, profile type and optional explicit section.

Production

Study/cotization input including the requested bar quantity.

Process

Alias for ProcessSpec. Describes process conditions without a production quantity.

PlanningCase

Combines Profile + ProcessSpec for quantity-independent process/planning calculations.

Standard calculation

from pyextrusion import calculate_case
result = calculate_case(press, study_case)

Important flat compatibility attributes remain available, while structured blocks are preferred for new integrations:

result.status.supported
result.status.viable
result.geometry.extrusion_ratio
result.geometry.cuts
result.geometry.cuts_per_pull
result.geometry.billets_per_pull
result.billet.recommended_length_mm
result.production.bars_per_billet
result.production.bars_per_pull
result.production.n_pulls
result.production.final_saw_events
result.production.internal_billet_transitions
result.production.puller_saw_events
result.production.billet_saw_events
result.process.trim_total_per_billet_m
result.process.trim_per_pull_m
result.scrap.fixed_pct
result.productivity.real_net_kg_h
result.productivity.productivity_index
result.timing.total_hours

Supported versus viable

if not result.supported:
    print(result.unsupported_reason)
elif not result.viable:
    print(result.warnings)

A process requiring 3+ profiles per billet is currently a controlled unsupported case, not an automatically extrapolated configuration.

Billet-first configuration fields

result.recommended_configuration
result.cuts
result.billets_per_pull
result.profiles_per_billet
result.cuts_per_pull
result.bars_per_pull

k_billets_1_profile can have any physically permitted billets_per_pull. 1_billet_2_profiles has profiles_per_billet == 2 and billets_per_pull == 1.

Speed input

Use one speed input per process. Standard usage supplies exit/profile speed:

Production(exit_speed_m_min=24, cut_length_mm=7000, bars_requested=300)

Alternatively, supply ram speed:

production = Production.from_ram_speed(
    ram_speed_mm_s=0.70,
    cut_length_mm=7000,
    bars_requested=300,
)

Process.from_ram_speed(...) is available for quantity-free planning cases. PyExtrusion derives exit speed from container area and total profile area. Supplying both ram and exit speed is rejected as ambiguous.

Strict industrial inputs

Structural counts (exits, manual cuts, bars and billets) are strict positive integers. Numeric strings, booleans, NaN and Infinity are rejected. A value such as cut_length_mm=7 is not interpreted as 7 metres; it is rejected because the supported cut range is 1000-15000 mm.

Quantity-free process evaluation

from pyextrusion import calculate_process

process = calculate_process(press, planning_case)

Useful process-level outputs:

process.viable
process.supported
process.recommended_configuration
process.cuts
process.bars_per_billet
process.billets_per_pull
process.bars_per_pull
process.billet_length_mm
process.recommended_billet_length_mm
process.table_occupancy_length_m
process.extrusion_ratio
process.exit_speed_m_min
process.ram_speed_mm_s
process.extrusion_time_per_billet_min
process.trim_total_per_billet_m
process.trim_per_pull_m
process.final_saw_events_per_pull
process.internal_billet_transitions_per_pull

ProcessResult contains no requested bars, billets, kg or time window. Its trim/event-per-pull fields refer to the full-pull configuration, not a possible last partial pull. In a planning result use plan.calculation.production for order counters when plan.calculation is not None.

Planning

from pyextrusion import calculate_planning, PlanningRequest

plan = calculate_planning(press, planning_case, PlanningRequest.bars(300))

Requests:

PlanningRequest.bars(300)
PlanningRequest.kg(2500)
PlanningRequest.metres(1800)
PlanningRequest.billets(20)
PlanningRequest.minutes(90)
PlanningRequest.hours(2)

Useful outputs:

plan.process_supported
plan.process_viable
plan.request_fulfilled
plan.planned_billets
plan.planned_bars
plan.planned_good_m
plan.planned_good_kg
plan.billets_per_pull
plan.planned_pulls
plan.time_used_min
plan.time_remaining_min
plan.planned_fixed_scrap_kg
plan.planned_total_scrap_kg
plan.planned_total_scrap_pct
plan.process.billet_length_mm

Immutable adjustments

planning_case.with_profile(exits=3)
planning_case.with_process(exit_speed_m_min=26)

study_case.with_profile(exits=3)
study_case.with_production(exit_speed_m_min=26)
study_case.replace(exits=3, exit_speed_m_min=26)

Result field discovery

from pyextrusion import list_fields, describe_field

for field in list_fields():
    print(field.path, field.unit)

print(describe_field("production.billets_per_pull"))

Dotted access is also supported:

result.value("productivity.real_net_kg_h")
result["production.billets_per_pull"]
result.select("geometry.extrusion_ratio", "productivity.real_net_kg_h")

Production sequences

from pyextrusion import ProductionOrder, calculate_production_sequence

orders = [
    ProductionOrder("OF-001", planning_case, PlanningRequest.bars(300)),
    ProductionOrder("OF-002", planning_case, PlanningRequest.billets(20)),
]

sequence = calculate_production_sequence(press, orders)

PyExtrusion preserves the supplied order exactly and inserts no setup or waiting time.

Useful outputs:

sequence.orders
sequence.all_orders_fulfilled
sequence.unresolved_order_ids
sequence.total_planned_billets
sequence.total_planned_bars
sequence.total_planned_good_kg
sequence.total_scrap_kg
sequence.total_press_time_min

sequence.orders[0].duration_min
sequence.orders[0].cumulative_start_min
sequence.orders[0].cumulative_end_min
sequence.orders[0].planning

An optional Python datetime start_at adds theoretical clock timestamps without applying a plant calendar.

Multi-press comparison

from pyextrusion import compare_processes, compare_planning, compare_production_sequences

processes = compare_processes([press_a, press_b], planning_case)
plans = compare_planning([press_a, press_b], planning_case, PlanningRequest.bars(300))
sequences = compare_production_sequences([press_a, press_b], orders)

The new comparison APIs require at least two presses, preserve press order, use identical inputs on every press and never declare an automatic winner. See Multi-press comparison.

Engineering and economics

Advanced analytical helpers live in pyextrusion.engineering. See the Engineering API for complete mechanical and thermal examples using the public 0.19.0 interface.

Deterministic production-cost and sales-margin calculations live in pyextrusion.economics. See the Economics API.