CALPHAD tools for designing thermodynamic models, calculating phase diagrams and investigating phase equilibria.
github-actions[bot] on website
DOC: Deploy latest docs to webs… (compare)
richardotis on develop
ENH: `CompositionSet`-based sol… (compare)
Sir, Database("mc_fe_v2.059.pycalphad.tdb")
the traceback goes like :
File "pyCalphad_test/Bi.py",
line 6, in <module>
db_alzn = Database('FE.TDB')
File "D:\ANACONDA\envs\pycalphad-env\lib\site-packages\pycalphad\io\database.py",
line 119, in new
return cls.from_file(fname, fmt=fmt)
File "D:\ANACONDA\envs\pycalphad-env\lib\site-packages\pycalphad\io\database.py",
line 213, in from_file
format_registry[fmt.lower()].read(dbf, fd)
File "D:\ANACONDA\envs\pycalphad-env\lib\site-packages\pycalphad\io\tdb.py",
line 932, in read_tdb
lines = fd.read().upper()
UnicodeDecodeError: 'gbk' codec can't decode byte 0xbd in position 201209: illegal multibyte sequence
Greetings! Has anybody tried a Scheil calculation with a system that models the liquid phase as an ordered “ionic liquid”? I’m trying calcs with a Nb-O-Zr TDB (attached). The error I get, below, is the one i see where liquid is not being found (i.e. initial temp is too low), even after I named the liquid phase according to the ionic liquid phase in the TDB (e.g. liquid_phase_name = ‘IONIC_LIQ’). Complete code example is below. Also the binary looks funky at O > 0.6 mol fraction, and wondering if there are any thoughts there? I won’t run calcs in that region but are there any red flags with the database, etc. Thanks for any ideas.
UnboundLocalError: local variable 'current_fraction_solid' referenced before assignment
Pycalphad v.0.9.2
Scheil v.0.1.6
solvent = 'Niobium'
solute = 'Oxygen'
a = 'NB'
b = 'O'
db = Database('ONBZRDATFILE.tdb')
phases = sorted(db.phases.keys())
comps = [a, b, 'VA']
fig = plt.figure(figsize=(9,6))
axes = fig.gca()
binplot(db, comps, phases, {v.X(b):(0.,1.0,0.05), v.T: (500, 3000, 25.), v.P:101325, v.N: 1}, plot_kwargs={'ax': axes})
plt.xlim(0., 1.0)
plt.ylim(500, 3000)
plt.show()
liquid_phase_name = 'IONIC_LIQ'
initial_composition = {v.X(b): 1.0e-3}
start_temperature = 3000.0
sol_res = simulate_scheil_solidification(db, comps, phases, initial_composition, start_temperature, step_temperature=0.25, verbose=True)
for phase_name, amounts in sol_res.cum_phase_amounts.items():
plt.plot(sol_res.temperatures, amounts, label=phase_name)
plt.plot(sol_res.temperatures, sol_res.fraction_liquid, label='LIQUID')
plt.ylabel('Phase Fraction')
plt.xlabel('Temperature (K)')
plt.title(str(solvent)+'-'+str(solute)+' Scheil Simulation')
plt.legend(loc='best')
plt.ylim(0.000, 1.1)
plt.show()
from pycalphad import Database, binplot, variables as v, equilibrium, calculate
from scheil import simulate_scheil_solidification
import matplotlib.pyplot as plt
solvent = 'Niobium'
solute = 'Oxygen'
a = 'NB'
b = 'O'
db = Database('ONBZRDATFILE.tdb')
phases = sorted(db.phases.keys())
comps = [a, b, 'VA']
# Energy surface
cr = calculate(db, comps, phases, T=2000, N=1, P=101325)
fig, ax = plt.subplots()
for phase_name in sorted(set(cr.Phase.values.flatten().tolist())):
msk_cr = cr.where(cr.Phase == phase_name)
ax.scatter(msk_cr.X.sel(component='O').squeeze(), msk_cr.GM.squeeze(), s=2, label=phase_name)
ax.legend(loc='center left', bbox_to_anchor=(1.01, 0.5))
ax.set_ylim(cr.GM.min() - 10000, 0)
ax.set_xlabel("X(O)")
ax.set_ylabel("GM (J/mol-atom)")
ax.set_title("T = 2000 K")
fig.savefig('GM.png', bbox_inches='tight')
Hi guys! Just a quick question regarding the concentration outputs from an equilibrium solve. Why are there so many NaNs when using eq.X.sel(component='AL').values.squeeze()
? Has this got something to do with site fractions? Furthermore, why are these not only the input concentrations prescribed in
my_vars = {v.X('AL'):(np.linspace(concentrations_min[0], concentrations_max[0], num_points)),
v.X('CO'):(np.linspace(concentrations_min[1], concentrations_max[1], num_points)),
v.X('CR'):(np.linspace(concentrations_min[2], concentrations_max[2], num_points)),
v.X('MO'):(np.linspace(concentrations_min[3], concentrations_max[3], num_points)),
v.X('TI'):(np.linspace(concentrations_min[4], concentrations_max[4], num_points)),
v.T: (Temperature),
v.P:Pressure}
when num_points=2
and concentrations_min
/_max
are arrays of the lower and upper bounds of the concentration space of interest? np.shape(eq.X.sel(component='AL').values.squeeze())
yields (8, 2, 2, 2, 2, 2, 7)
, where there are 8 temperatures, and each of the five elements can take two values of the min and max concentrations.
The context for this question is that I want to extract the free energy at various temperatures, across a multicomponent concentration space for a single phase. I want to be able to correlate a specific concentration for each component to one of the outputs from pycalphad. If it's quicker to perform an equilibrium calculation in a for loop for each concentration set, I can do that instead.
Thanks in advance for the help!
@Noxical Here is a sketch of an idea of how to approach it. Ideally we'd be able to compute liquid temperatures directly using equilibrium, but that isn't fully supported yet.
from pycalphad import Database, equilibrium, variables as v
dbf = Database('C:/Users/rotis/git/pycalphad-binder/multicomponent-databases/steel1.TDB')
eq = equilibrium(dbf, ['FE', 'C', 'VA'], ['FCC_A1', 'BCC_A2', 'LIQUID'],
{v.X('C'): (1e-4, 0.3, 0.01), v.T: 650, v.P: 1e5, v.N: 1})
import matplotlib.pyplot as plt
from pycalphad.plot.utils import phase_legend
stable_phases = sorted(set(eq.Phase.values.flatten()) - {''})
phase_handles, phasemap = phase_legend(stable_phases)
plt.gca().set_title('Phase fractions vs X(C)')
plt.gca().set_xlabel('X(C)')
plt.gca().set_ylabel('Phase Fraction')
plt.gca().set_ylim((0,1.1))
for phase in stable_phases:
plt.scatter(eq.X_C.broadcast_like(eq.NP), eq.NP.where(eq.Phase == phase), color=phasemap[phase])
plt.gca().legend(phase_handles, stable_phases, loc='center left')
import numpy as np
min_liquid_fraction_idx = eq.NP.where(eq.Phase == 'LIQUID').squeeze().fillna(np.inf).argmin(axis=0).sel(vertex=0)
min_carbon_content = eq.X_C[min_liquid_fraction_idx]
print('Carbon content where liquid first appears: ', float(min_carbon_content))
Note that this will give you a solidus temperature (where liquid first appears), not the liquidus (where all the solid is consumed and only the liquid is left).
NP
array corresponding to the liquid phase that is equal to 1.0
, meaning the phase is the only one that is stable at that composition. The indexing looks slightly different but it's similar to what I've shown here.
Hi,Brandon and Richard.I'm trying to load my own-made TDB file,but there's something wrong with the program.
``` (shift+enter for line break)
import matplotlib.pyplot as plt
from pycalphad import Database, binplot
import pycalphad.variables as v
dbf = Database(open('Fe-Ti.tdb', encoding='utf-8').read())
comps = ['FE', 'TI', 'VA']
phases = dbf.phases.keys()
binplot(dbf,
comps,
phases,
{v.N: 1,
v.P:101325,
v.T: (300, 1000, 10),
v.X('FE'):(0, 1, 0.02)
}
)
plt.show()
```
And the error is "pyparsing.exceptions.ParseException: Expected {{'ELEMENT' W:(-/A-Za-z){1,2} W:((-)-/-:A-Z_a-z) Re:('[-+]?([0-9]+.(?!([0-9]|[eE])))|([0-9].?[0-9]+([eE][-+]?[0-9]+)?)') Re:('[-+]?([0-9]+.(?!([0-9]|[eE])))|([0-9].?[0-9]+([eE][-+]?[0-9]+)?)') Re:('[-+]?([0-9]+.(?!([0-9]|[eE])))|([0-9].?[0-9]+([eE][-+]?[0-9]+)?)') LineEnd} | {'SPECIES' W:(-+--9A-Z_a-z) [Suppress:('%')] Group:({{W:(A-Za-z){1,2} [Re:('[-+]?([0-9]+.(?!([0-9]|[eE])))|([0-9].?[0-9]+([eE][-+]?[0-9]+)?)')]}}...) [Suppress:('/') W:(+-0-9)] LineEnd} | {'TYPE_DEFINITION' Suppress:(<SP><TAB><CR><LF>) !W:( !) SkipTo:(LineEnd)} | {'FUNCTION' W:((-)-/-:A-Z_a-z) {{Re:('[-+]?([0-9]+.(?!([0-9]|[eE])))|([0-9].?[0-9]+([eE][-+]?[0-9]+)?)') | [',']...} {{SkipTo:(';') Suppress:(';') [Suppress:(',')]... [Re:('[-+]?([0-9]+.(?!([0-9]|[eE])))|([0-9].?[0-9]+([eE][-+]?[0-9]+)?)')] Suppress:([(Yy)])}}... Suppress:([(Nn)])} [Suppress:(W:(-0-:A-Z_a-z))] LineEnd} | {'ASSESSED_SYSTEMS' SkipTo:(LineEnd)} | {'DEFINE_SYSTEM_DEFAULT' SkipTo:(LineEnd)} | {'DEFAULT_COMMAND' SkipTo:(LineEnd)} | {'DATABASE_INFO' SkipTo:(LineEnd)} | {'VERSION_DATE' SkipTo:(LineEnd)} | {'REFERENCE_FILE' SkipTo:(LineEnd)} | {'ADD_REFERENCES' SkipTo:(LineEnd)} | {'LIST_OF_REFERENCES' SkipTo:(LineEnd)} | {'TEMPERATURE_LIMITS' SkipTo:(LineEnd)} | {'PHASE' W:((-)-/-:A-Z_a-z) Suppress:(<SP><TAB><CR><LF>) !W:( !) Suppress:(<SP><TAB><CR><LF>) Suppress:(W:(0-9)) Group:({Re:('[-+]?([0-9]+.(?!([0-9]|[eE])))|([0-9].?[0-9]+([eE][-+]?[0-9]+)?)')}...) Suppress:(SkipTo:(LineEnd))} | {'CONSTITUENT' W:((-)-/-:A-Z_a-z) Suppress:(<SP><TAB><CR><LF>) Suppress:(':') Group:(Group:({{[Suppress:(',')] W:(-+--9A-Z_a-z) [Suppress:('%')]}}...) [: Group:({{[Suppress:(',')] W:(-+--9A-Z_a-z) [Suppress:('%')]}}...)]...) Suppress:(':') LineEnd} | {'PARAMETER' {'BMAGN' | 'DF' | 'DQ' | 'ELRS' | 'G' | 'GD' | 'L' | 'MF' | 'MQ' | 'NT' | 'SIGM' | 'TC' | 'THCD' | 'THETA' | 'V0' | 'VA' | 'VC' | 'VISC' | 'VK' | 'VS' | 'XI'} Suppress:('(') W:((-)-/-:A-Z_a-z) [Suppress:('&') W:(-/A-Za-z){1,2}] Suppress:(',') Group:(Group:({{[Suppress:(',')] W:(-+--9A-Z_a-z) [Suppress:('%')]}}...) [: Group:({{[Suppress:(',')] W:(-+--9A-Z_a-z) [Suppress:('%')]}}...)]...) [Suppress:(';') W:(0-9)] Suppress:(')') {{Re:('[-+]?([0-9]+.(?!([0-9]|[eE])))|([0-9].?[0-9]+([eE][-+]?[0-9]+)?)') | [',']...} {{SkipTo:(';') Suppress:(';') [Suppress:(',')]... [Re:('[-+]?([0-9]+.(?!([0-9]|[eE])))|([0-9].?[0-9]+([eE][-+]?[0-9]+)?)')] Suppress:([(Yy)])}}... Suppress:([(Nn)])} [Suppress:(W:(-0-:A-Z_a-z))] LineEnd}}, found 'UN' (at char 49), (line:1, col:50)"
import matplotlib.pyplot as plt
from pycalphad import Database, binplot
import pycalphad.variables as v
dbf = Database(open('Fe-Ti.tdb', encoding='utf-8').read())
comps = ['FE', 'TI', 'VA']
phases = dbf.phases.keys()
binplot(dbf,
comps,
phases,
{v.N: 1,
v.P:101325,
v.T: (300, 1000, 10),
v.X('FE'):(0, 1, 0.02)
}
)
plt.show()
At the top of the traceback for the error, it reads:
Failed while parsing: FUNCTION ZERO 298.15 0.0; 6000.00 N FUNCTION UN_ASS 298.15 0.0; 3.00000E+02 N FUNCTION GHSERFE 298.15 1225.7+124.134*T-23.5143*T*LN(T)-4.39752E-3*T**2-0.058927E-6*T**3 +77359*T**(-1); 1811 Y -25383.581+299.31255*T-46*T*LN(T)+2296.03E28*T**(-9); 6000.00 N
the FUNCTION ZERO
and FUNCTION UN_ASS
lines are missing the line terminators (!
)
There's no one officially accepted way that I'm aware of to compute degree of ordering. The way it's calculated in pycalphad is shown here: https://github.com/pycalphad/pycalphad/blob/56201bfb10372fb7ef90efde4f3fa431781c36bc/pycalphad/model.py#L347
The key piece of it is Abs(v.SiteFraction(self.phase_name, idx, comp) - self.moles(comp)) / self.moles(comp)
. We're basically looking at the percent deviation of the sublattice content compared to the overall composition, for each component. Then we sum up all the deviations and divide by a normalization factor.
I don't have a reference for the function. I developed it during my dissertation study so I had a degree of ordering function that varied from 0 to 1 and also worked for multi-component systems. It hasn't been extensively investigated by me (or anyone, to my knowledge)