Advanced features

This chapter explains the advanced features that ChemApp for Python has beyond the abilities of the C/Fortran ChemApp, such as using the state functions and object oriented approach to model processes.

Content Overview

  • Result objects chemapp.core.EquilibriumCalculationResult and chemapp.core.StreamCalculationResult

  • ChemApp logging

  • chemapp.core.Object

  • Input using chemical formulae using set_IA_cfs()

  • Update checks & persistent configuration

One of the core features of ChemApp for Python is taking advantage of object oriented structures to allow using calculation results of previous calculations as input for further calculations, and therefore allowing e.g. process models to be rapidly deployed without much tedious setup processes. This takes advantage of the State classes and EquilibriumCalculationResult as well as StreamCalculationResult objects mentioned in the core section.

The practical use of the logging abilities of ChemApp for Python is another feature that allows quickly generating helpful information to debug and analyze your program code.

Furthermore, a convenient way to enter incoming amounts using chemical formula instead of phase constituents or system components is introduced, using the set_IA_cfs() routine of the EquilibriumCalculation classes.

Result Objects

Most thermochemical calculations related to process manages are using multiple calculation steps to describe. With ChemApp for Python, it is possible to easily use results of previous calculations not only to store and investigate the calculation results, but also as input for following calculations. To work with calculation results as inputs for new calculations, they have to be converted into StreamState objects, which are objects that are defining input streams in ChemApp. They do carry an initial temperature, initial pressure and phase (constituent) amounts, all of which is necessary to define an input stream into ChemApp for Python.

One of the main applications of stream or initial conditions based calculations are in process modelling and in designing of material flow in multistage reaction schemes. Functions to split, separate and combine StreamState objects are available, as well as directly creating streams from equilibrium results filtered by e.g. matter of state, phase or constituents.

Creation of result objects

After executing a calculation, a EquilibriumCalculationResult and StreamCalculationResult can be created using the class routine get_result_object of EquilibriumCalculation or StreamCalculation.

The result objects are relatively rich data container classes, that expose reasonable information of the calculation as properties, such as the conditions and inputs, as well as e.g. the units in which the results are stored. All fetchable thermodynamic data is stored in the object for all phases and constituents. Most of the properties are constructed of the various data structures that ChemApp for Python provides, such as PhaseState classes.

It is recommended to always create a result object from a calculation, if any type of aggregating or deeper analysis of certain results is planned. The computational cost of collecting the data is relatively low. However, each calculation result object size can quickly become large for large datafiles.

Creation of stream objects

Note: An extended introduction to stream functionalities can be found in Stream Functionalities.

From these objects, the following routines can be used to create StreamState classes, which then can be used as inputs for new calculations:

  • create_stream

  • create_stream_by_state

  • create_gas_stream

  • create_liquid_stream

  • create_solid_stream

Of these routines, create_stream is the most versatile and allows for various types of filters and selections, namely by specifically including or excluding certain phases, as well as including or excluding certain elements. It also allows to set a certain threshold to ignore residual amounts of phase constituents.

Update checks & persistent configuration

The update mechanism and the persistent configuration (including the density preference stored via Info.set_density_config) are described in detail in the dedicated chapter below. It explains how automatic and forced update checks work, what is stored in chemapp_python.cfg in the user home directory, and how to select a VolumeEstimateSetting.

More information on this: Update checks & persistent configuration.

ChemApp Logging

A debugging functionality has been added to ChemApp for Python that allows to output the ChemApp library calls in the original FORTRAN language calls to the ChemAPP API. It allows for users to generate a complete stream of the setup that was used in calculations, which can be very helpful to guide through e.g. presumed bugs in ChemApp, in some library code or to check if the program does indeed do as intended.

If a function returns a result, this result is printed directly after the function. Therefore it can also be used to quickly find off-by-one errors or other typical programming mishaps.

It can be enabled by using

from chemapp.basic import enable_logging, disable_logging

# enable logging to 'calls.log'
enable_logging()

# and can subsequently deactivated using
disable_logging()

The output is appended to the file ‘calls.log’ in the current working directory, and together with the datafile used in the calculation should be a valuable debugging ressource, especially if you consider contacting GTT for maintenance or support.

Input of complex chemical formulae

ChemApp for Python allows you to specify incoming amounts using full chemical formula strings instead of listing system components or phase constituents individually. This is done via the class method set_IA_cfs() (and the analogous set_IA_cfs() in stream calculations).

The parsing, validation and convenient (pretty) printing of chemical formulae is handled by the Composition class, which provides a rich interface around a formula viewed as an ordered mapping {element: amount}.

Important

Calling set_IA_cfs() REPLACES previously defined incoming amount conditions for the involved system components. It is not additive. If you want to change or extend the incoming amounts and use set_IA_cfs(), you have to use set_IA_sc() or set_IA_pc() only after set_IA_cfs() has been called (the same semantics apply for the StreamCalculation variants).

Rationale & workflow

  1. You supply one or more chemical formula strings plus the corresponding incoming amount values.

  2. Each formula string is internally converted into a Composition object.

  3. The composition is validated: only elements that can be represented by the system components of the loaded datafile are accepted. Parentheses and fractional / decimal subscripts (e.g. Cr0.3Mn0.7C) are expanded.

  4. The element amounts are mapped onto system components; the resulting system component incoming amounts replace any prior ones.

Accepted input formats

Examples of accepted formula strings:

  • Fe2O3

  • Na(OH)2 (parentheses are expanded)

  • Cr0.3Mn0.7C (decimal amounts)

  • Al2SiO5

If a composition cannot be expressed solely with the available system components an error is raised.

Using set_IA_cfs()

Basic usage:

from chemapp.friendly import EquilibriumCalculation

# Replace (not add to) any previously defined incoming amounts
EquilibriumCalculation.set_IA_cfs(
    cfs=["CaO", "SiO2", "Al2O3"],
    values=[10.0, 5.0, 2.0]
)

As long as all compositions can be expressed using the system components of the loaded data file, you can use:

EquilibriumCalculation.set_IA_cfs(
    ["Cr0.3Mn0.7C", "Na(OH)2"],
    [1.2, 4.5]
)

Leveraging Composition explicitly

While for set_IA_cfs() you just pass formula strings, working directly with the Composition class (from chemapp.core import Composition) to inspect or transform formulae beforehand (e.g. for validation, normalization, pretty printing or logging) can be helpful.

Key features of Composition

  • Ordered storage of elements as entered

  • Validation & tolerant parsing (parentheses, decimals)

  • Multiple string representations for consistent reporting

  • Scaling reduction to smallest integer ratio

  • Dictionary export (optionally reduced)

Properties & methods

  • formula - canonical internal string representation

  • pretty_formula - elements sorted by Pauling order, amounts of 1 omitted

  • reduced_formula - smallest common denominator applied

  • pretty_reduced_formula - combination of sorting + reduction

  • elements - frozenset of element symbols

  • unordered - original input order {element: amount}

  • to_dict(reduced=False) - export mapping, optionally reduced

Examples

Creating compositions:

from chemapp.core import Composition

c1 = Composition("Fe2O3")
c2 = Composition("Cs(OH)3")
c3 = Composition({"Cr": 0.3, "Mn": 0.7, "C": 1})  # from dict
c4 = Composition(c1)  # copy from existing Composition

Inspecting representations:

c = Composition("Fe4O6")
c.formula                # 'Fe4O6'
c.pretty_formula         # e.g. 'Fe4O6'
c.reduced_formula        # 'Fe2O3'
c.pretty_reduced_formula # 'Fe2O3'
c.to_dict()              # {'Fe': 4.0, 'O': 6.0}
c.to_dict(reduced=True)  # {'Fe': 2.0, 'O': 3.0}

Dealing with parentheses & reordering:

Composition("Cs(OH)3").formula            # 'Cs1O3H3'
Composition("Cs(OH)3").pretty_formula     # 'CsO3H3'
Composition("Cs(OH)3").reduced_formula    # 'CsO3H3' (already reduced)

Logging / pretty printing in reports:

comps = [Composition(f) for f in ["Fe2O3", "Na(OH)2", "Cr0.3Mn0.7C"]]
for comp in comps:
    print(f"Input: {comp.formula}  Pretty: {comp.pretty_reduced_formula}")

Using it to e.g. validate user input:

formulas = ["Fe2O3", "Na(OH)2", "Cr0.3Mn0.7C"]
amounts = [3.0, 1.5, 0.8]

try:
   compositions = [Composition(f) for f in formulas]
except:
   # this would be a place where you could catch validation errors
   ...

# Single replacing call
EquilibriumCalculation.set_IA_cfs(formulas, amounts)