Introduction
Process modeling is a critical component in the optimization of industrial operations, delivering significant benefits in cost reduction, efficiency enhancement, and environmental sustainability. Through its stream functionality, ChemApp for Python delivers advanced thermochemically sound calculation capabilities that provide engineers with a robust framework for modeling complex thermochemical processes. Several functions related to streams have been added to ChemApp for Python in Version 8.3.4 (Release September 2025). This post explains step-by-step how engineers can leverage ChemApp’s stream-oriented architecture to efficiently develop comprehensive thermochemical models, using steelmaking as an industrial example case. The full script can be downloaded from our repository of ChemApp for Python examples.
Streams in Process Modeling
As the fundamental constituent of a process model, a stream defines a material in one of two primary states:
- A mechanical mixture: Phases coexist without achieving thermodynamic equilibrium
- A chemically stable mixture: Phases exist in a state of thermodynamic equilibrium
Yet, different streams, all in chemical equilibrium and with the same base component amounts, may exhibit distinct phase distributions and compositions, depending on the thermodynamic conditions through which they have been processed. Therefore, streams appear as the interconnection between process units, allowing for the comprehensive modeling of material flows throughout complex industrial systems.

Setting Up the Python Script
The initial step requires loading the appropriate resources and relevant thermochemical database, as shown below:
from chemapp.friendly import StreamCalculation, Units, ThermochemicalSystem
from chemapp.core import AmountUnit, TemperatureUnit, PressureUnit, EnergyUnit
# Set global units for consistency
Units.set(A=AmountUnit.tonne, T=TemperatureUnit.C, P=PressureUnit.bar, E=EnergyUnit.J)
# Load specialized thermochemical database for ferrous metallurgy
ThermochemicalSystem.load("steelmaking.cst")
Code language: PHP (php)
The CST format of the thermochemical database is encrypted and proprietary. It can be exported from the FactSage (R) software package or purchased directly from GTT-Technologies. For users requiring more flexibility, ChemApp supports an open text-based format (DAT) for custom databases.
Input Stream Definition
In ChemApp for Python in Version 8.3.4, several new stream handling functionalities have been added. We start with a very convenient function to set up streams: the StreamCalculation.create_stream_from_complex_formulas()
method (or the create_st_cfs
shorthand version of it) allows stream initialization based on chemical composition, temperature and pressure, which is on-the-fly equilibrated:
# Define hot metal input (values in tonnes)
hot_metal = StreamCalculation.create_st_cfs(
"HotMetal",
["Fe", "C", "Si", "S", "P", "Mn" ],
[94.6225, 4.35, 0.505, 0.0225, 0.1, 0.4 ],
T=1300.0
)
# Define oxygen for decarburization and oxidation reactions
oxygen = StreamCalculation.create_st_cfs("Oxygen", ["O2"], [5.0], T=25.0)
# Define steel scrap for temperature moderation and yield enhancement
scrap = StreamCalculation.create_st_cfs("Scrap", ["Fe"], [18.0], T=25.0)
# Define lime addition for slag formation and impurity sequestration
lime = StreamCalculation.create_st_cfs("Lime", ["CaO"], [2.5], T=25.0)
Code language: PHP (php)
Explanation: The complex formulas are internally decomposed into their elemental components and then equilibrated at the specified temperature (T) and pressure (P, which defaults to 1.0 if unspecified).
Primary Steelmaking: LD Converter Simulation
The streams defined above react in an LD converter. In first-order approximation, we assume that this reaction is adiabatic here. Using the new reaction_adiabatic
method, we can equilibrate the inputs under adiabatic conditions:
# Execute adiabatic reaction simulation for converter process
converter_result = StreamCalculation.reaction_adiabatic(
[hot_metal, oxygen, scrap, lime]
)
# Extract final temperature for process validation
print(f"Converter temperature: {converter_result.T:.1f} °C")
Code language: PHP (php)
which outputs the final temperature of the converter operation:
Converter temperature: 1603.1 °C
Code language: CSS (css)
This simulation predicts the final temperature, which serves as a critical validation parameter for the model, as industrial steelmaking requires temperatures above 1600°C for proper fluidity and separation. For a higher fidelity model, the single-zone adiabatic approach can be extended to a multi-zone configuration, allowing for a more accurate representation of temperature gradients and reaction kinetics within the converter.
Additionally, for scenarios requiring heat transfer modeling, ChemApp for Python now provides the reaction_diathermal
function which extends the basic adiabatic model, allowing users to specify the amount of heat exchanged with energy sources or the environment:
# Diathermal reaction assuming 200 MJ heat input in the converter
converter_result = StreamCalculation.reaction_diathermal(
[hot_metal, oxygen, scrap, lime],
dH=200000.0, # in J
)
# Extract final temperature for process validation
print(f"Converter temperature: {converter_result.T:.1f} °C")
Code language: PHP (php)
which outputs a higher final temperature:
Converter temperature with added heat: 1649.3 °C
Code language: JavaScript (javascript)
Heat loss can of course also be modeled by specifying a negative value for dH
.
Product Separation
After the primary steelmaking operation, the heterogeneous product mixture requires separation into its constituent phases. The newly developed create_streams_by_density
method is a significant addition, employing a physics-based separation algorithm that automatically classifies phases according to density thresholds. This makes it possible to conveniently partition the products of an equilibrium calculation into a variable number of streams – such as metal, slag, and gas – without having to refer to specific phase names:
# Execute phase separation based on density thresholds
off_gas, slag, steel = converter_result.create_streams_by_density([1.0, 5.0])
print(f"Off-gas amount: {off_gas.A:.2f} tonnes")
print(f"Slag amount: {slag.A:.2f} tonnes")
print(f"Steel amount: {steel.A:.2f} tonnes")
Code language: PHP (php)
which produces the following output:
Off-gas amount: 4.35 tonnes
Slag amount: 3.92 tonnes
Steel amount: 107.54 tonnes
Code language: CSS (css)
Given the boundary conditions, steel and slag can be readily separated at densities around 5.0 g/cm³, while gaseous phases exhibit densities below 1.0 g/cm³. The method automatically generates the number of streams based on the density boundaries defined by the user; if finer resolution is required, additional thresholds can be specified.
The density-based separation method relies on volumetric data present in the thermodynamic database. When such volumetric data is unavailable, ChemApp for Python 8.3.4 automatically employs its internal density estimation model, which covers most common phases independent of the database.
Note
Users can control how ChemApp’s density separation method should rely on its internal density model, by selecting one of three options: ifmissing
(the default behavior, which uses the model only when volumetric data is unavailable), never
(to completely avoid using the estimation model), or always
(to exclusively use the model, even when volumetric data exists in the database). This configuration can be managed with the Info.read_density_config
and Info.set_density_config
functions or through the .chemapp_python.cfg
file, which is automatically created in the user’s home directory upon first execution of ChemApp for Python, under the use_estimate_volume
flag.
Alternative separation methods based on matter state or phase names were already available in previous versions and can provide more precise control when phase densities overlap:
# Separation strategy utilizing matter state
from chemapp.core import PhaseMatterState
off_gas_alt = converter_result.create_stream_by_state(
name="OffGas",
state=PhaseMatterState.GAS
)
solids_only = converter_result.create_stream_by_state(
name="Precipitates",
state=PhaseMatterState.SOLID
)
# Separation strategy utilizing phase names
slag_liquid_and_solid = converter_result.create_stream(
name="Slag",
phs_exclude=["gas_ideal", "LIQUID#1"]
)
steel_alt = converter_result.create_stream(
name="Steel",
phs_include=["LIQUID#1"]
)
Code language: PHP (php)
These different product separation routines demonstrate the flexibility of ChemApp’s stream manipulation capabilities, allowing for customized separation strategies based on specific process requirements.
Secondary Metallurgy: Alloying
Compositional adjustments via alloying additions represent a critical step in achieving the desired steel properties. The new reaction_isothermal
method provides a straightforward approach to simulate these isothermal reactions:
# Define alloying materials
Al = StreamCalculation.create_st_cfs("Al", ["Al"], [0.15], T=25.0)
Fe_Si = StreamCalculation.create_st_cfs("Fe_Si", ["Si", "Fe"], [0.0238, 0.0102], T=25.0)
Fe_Mn = StreamCalculation.create_st_cfs("Fe_Mn", ["Mn", "Fe"], [0.0272, 0.0068], T=25.0)
Fe_Ti = StreamCalculation.create_st_cfs("Fe_Ti", ["Ti", "Fe"], [0.0221, 0.0119], T=25.0)
# Execute isothermal reaction simulation at steel temperature
alloying_result = StreamCalculation.reaction_isothermal(
[steel, Al, Fe_Si, Fe_Mn, Fe_Ti],
T=steel.T
)
# Extract alloyed steel stream for subsequent processing
alloyed_steel = alloying_result.create_stream("AlloyedSteel")
Code language: PHP (php)
Secondary Metallurgy: Vacuum Degassing
Dissolved gases in steel, particularly hydrogen and nitrogen, can significantly impact mechanical properties. The simulation of vacuum degassing with inert gas purging demonstrates the application of reduced-pressure equilibrium calculations, which is also performed using the reaction_isothermal
method but at a lower pressure:
# Define argon stream for inert gas purging
Ar = StreamCalculation.create_st_cfs("Argon", ["Ar"], [0.05], T=25.0)
# Execute low-pressure equilibrium calculation
degasser_result = StreamCalculation.reaction_isothermal(
[alloyed_steel, Ar],
T=alloyed_steel.T,
P=0.01 # Vacuum condition (10 mbar)
)
# Separate gaseous phase from degassed steel
degassing_gas, degassed_steel = degasser_result.create_streams_by_density([1.0])
Code language: PHP (php)
Vacuum levels around 0.01 bar shift the equilibrium so gases leave the steel, with argon bubbles helping by stirring the melt and providing surfaces for gas escape. In simplified models, only the total pressure matters as it defines the driving force for degassing, assuming constant system pressure. In reality, achieving and maintaining constant low pressures can be technically challenging.
This completes the modeling of steelmaking operations in a few straightforward steps. While ChemApp for Python always enabled such modeling, the advancements of the latest version truly make these steps easier to implement.
Conclusion
This guide has demonstrated the application of the new stream functionalities availible in ChemApp for Python from Version 8.3.4 (Release September 2025). The key aspects addressed include:
- Stream creation and manipulation methodologies
- Thermodynamic reaction simulations (adiabatic and isothermal)
- Phase separation techniques based on physical properties
The stream-based modeling approach provides significant advantages in terms of flexibility, accuracy, and computational efficiency. The modular nature of the presented model facilitates extension to incorporate additional process steps or adaptation to alternative metallurgical processes. Through systematic parameter variation, process engineers can optimize operations to meet specific objectives related to product quality, operational efficiency, and environmental performance.
The methodology presented herein can be applied to a wide range of industrial processes beyond steelmaking, including non-ferrous metallurgy, cement production, glass manufacturing, chemical processing, and more – wherever complex thermochemical transformations govern product quality and process efficiency.
A second part of this series will be published soon. Stay tuned for an example of how modular design can be used in integrated process modeling, enabling parametric studies and process optimization.