To plot and investigate the phase transitions and phase fraction calculations in the Pb-Sn system, a vertical section of the phase diagram is analysed at 30%wt Sn and 70%wt Pb.
The necessary thermodynamic data is stored in the file pbsn.dat
.
A ThermochemicalSystem
is typically instantiated by loading a .dat or .cst
file.
from chemapp.friendly import ThermochemicalSystem
ThermochemicalSystem.load("pbsn.dat")
To set the units is a good precaution. The inputs to the settings are 'guarded' by using enumerations that only allow certain limits of inputs. Therefore, we need to import the respective enums for pressure, volume, temperature, energy and amounts.
from chemapp.friendly import Units
# Make sure the units are set as expected
from chemapp.core import (
PressureUnit,
VolumeUnit,
TemperatureUnit,
EnergyUnit,
AmountUnit,
Status
)
Units.set(
T=TemperatureUnit.C,
P=PressureUnit.atm,
V=VolumeUnit.dm3,
A=AmountUnit.gram,
E=EnergyUnit.J,
)
To find the phase transitions and mixture of phase components, we want to look at the vertical section at 30wt% Sn and 70wt% of Pb, so we set these as incoming amounts (notice that we changed the units to 'gram' accordingly.)
We will use the PhaseMapCalculation
object for this.
from chemapp.friendly import EquilibriumCalculation, PhaseMapCalculation
PhaseMapCalculation.set_IA_sc('Sn', 0.3)
PhaseMapCalculation.set_IA_sc('Pb', 0.7)
Now, doing the phase mapping is a s simple as just calling the
calculate_ph_txs_T
routine, which finds all phase status changes in a given
temperature range.
Similarly, calculate_ph_txs_P
would do the same with pressure, and
calculate_ph_txs_IA
with changes in composition.
It returns a list of ResultObjects
, which have some nice properties we will
explore next.
results = PhaseMapCalculation.calculate_ph_txs_T(0., 400.)
The results object is a somewhat rich collection of results that can be accessed by properties and routines.
We are iterating over the reversed list of results, so that higher temperatures are at the top.
To get a glimpse at the data, we look at the phases that have an activity of 1 and an amount greater than 0, so all stable phases.
We use some simple print
commands to inquire about the data. There are two
transition points in the calculated range, so the results should show these, and
further include the start and end of the investigated range.
stable_phases = set()
for transitions in reversed(results):
print(f"---- T = {transitions.T:>7.2f}°C ----")
for phase, state in transitions.phs.items():
if state.AC == 1. and state.A > 0.:
print(f"{phase:>10}")
stable_phases.add(phase)
---- T = 400.00°C ---- LIQUID ---- T = 248.94°C ---- LIQUID ---- T = 181.41°C ---- BCT_A5#1 FCC_A1 ---- T = 0.00°C ---- BCT_A5#1 FCC_A1
Since we are interested to find the exact transition temperatures, we can
iterate over the T
property of the Result object. This gives us a simple
python list.
transition_temperatures = [transition.T for transition in results]
Now to do some more calculations for the cooling and phase transitions, we will generate a list of temperatures in the temperature range, and explicitly add the transition temperatures.
import numpy as np
divided_range = list(np.linspace(0., 400., num=81))
temperature_range = sorted(divided_range + transition_temperatures)
It is simply a matter of iterating over the generated temperatures to collect
all the necessary data. ChemApp for Python would typically remove old
calculation results when doing a new calculation. Therefore, we explicitly use
the get_result_object()
routine to keep a persistent copy of the result.
Notably, now we use functions from the EquilibriumCalculation
class, and not
the PhaseMapCalculation
anymore. This is possible since the underlying
thermodynamic system hasn't changed, and the underlying instance of
ChemAppBasic
maintains this state.
# we do not need to set these, because they are still maintained from above,
# from the 'transition' calculation.
# EquilibriumCalculation.set_IA_sc("Sn", 0.3)
# EquilibriumCalculation.set_IA_sc("Pb", 0.7)
results = []
for temp in temperature_range:
EquilibriumCalculation.set_eq_T(temp)
EquilibriumCalculation.calculate_eq()
res = EquilibriumCalculation.get_result_object()
results.append(res)
To plot the different stable phases and their phase amounts over the temperature
range, we resort to the pandas
module library. We simply fill a DataFrame with
the respective data.
import pandas as pd
phase_amounts = pd.DataFrame(columns=["LIQUID", "FCC_A1", "BCT_A5#1"], index=temperature_range)
for phase in stable_phases:
phase_amounts[phase] = [res.phs[phase].A for res in results]
Now, plotting the data is as easy as calling one of the plotting routines of DataFrames, namely in this case, an area plot which automatically colors the area under the plot.
plot = phase_amounts.plot.area()
This is okay, but looks much better and comprehensible when we add the
stacked=False
parameter to it. To show the significant transition points, we
will also add these as markers on the x axis, with the exact numbers as labels.
unstacked_plot = phase_amounts.plot.area(stacked=False)
# add the vertical lines
for x in transition_temperatures:
unstacked_plot.plot([x, x], [0,1.], color="black", ls=":", )
# change the x axis labels
labels_at = [ 100., 300., ]
unstacked_plot.set_xticks(labels_at + transition_temperatures)
unstacked_plot.plot()
[]