MatCalc python integration
MatCalc comes with monaco-editor shipped and ready to create python scripts with code-completion in the Matcalc GUI.
The currently used python version is 3.10, so make sure to match this version should you decide to not use the shipped python version to run your scripts.
Running python scripts with MatCalc
Using python shipped with MatCalc
Easiest way to get started outside of the MatCalc GUI is by using the shipped python installation.
Windows PowerShell
$env:MATCALCPATH = "C:\Program Files\MatCalc 6.11.0.054"
& "$env:MATCALCPATH\python\python.exe" "$env:MATCALCPATH\scripts\script_menu\Python\Precipitation\al-base\example.py"
Windows command prompt
set MATCALCPATH=C:\Program Files\MatCalc 6.11.0.054
"%MATCALCPATH%\python\python.exe" "%MATCALCPATH%\scripts\script_menu\Python\Precipitation\al-base\example.py"
Unix
export MATCALCPATH="$HOME/MatCalc 6.11.0.054"
"$MATCALCPATH/python/bin/python3" "$MATCALCPATH/scripts/script_menu/Python/Precipitation/al-base/example.py"
Using external python (must be version 3.10)
Windows PowerShell
$env:MATCALCPATH = "C:\Program Files\MatCalc 6.11.0.054"
$env:PYTHONHOME = "$env:MATCALCPATH\python"
& python3.10.exe "$env:MATCALCPATH\scripts\script_menu\Python\Precipitation\al-base\example.py"
Windows command prompt
set MATCALCPATH=C:\Program Files\MatCalc 6.11.0.054
set PYTHONHOME=%MATCALCPATH%\python
python3.10.exe "%MATCALCPATH%\scripts\script_menu\Python\Precipitation\al-base\example.py"
Unix
export MATCALCPATH="$HOME/MatCalc 6.11.0.054"
export PYTHONHOME="$MATCALCPATH/python/lib"
python3.10 "$MATCALCPATH/scripts/script_menu/Python/Precipitation/al-base/example.py"
Developing with matcalc module
Initializing MatCalc core
import matcalc
mc = matcalc.get()
mc.init()
Using MatCalc script language
At the moment only some functions are exposed in the matcalc package but you can execute any MatCalc script language command.
mc.console("show expression T$c")
Working with databases
# thermodynamic database
mc.open_database("mc_al.tdb", matcalc.DatabaseType.EQUILIBRIUM)
mc.select_elements(["Al", "Mg", "Si", "Va"])
mc.select_phases(["FCC_A1", "CL_MGX", "mg5si6_b_dp"])
mc.read_database(matcalc.DatabaseType.EQUILIBRIUM)
# diffusion database
mc.open_database("mc_al.ddb", matcalc.DatabaseType.DIFFUSION)
mc.read_database(matcalc.DatabaseType.DIFFUSION)
print("databases: ")
print(f" thermodynamic: {mc.database_name(matcalc.DatabaseType.EQUILIBRIUM)}")
print(f" diffusion: {mc.database_name(matcalc.DatabaseType.DIFFUSION)}")
print(f" physical: {mc.database_name(matcalc.DatabaseType.PHYSICAL)}")
print("")
print("selected elements:")
print(mc.elements())
print("")
print("selected phases:")
print(mc.phases())
print("")
Element Composition
# weight-percent
mc.setup_composition(
matcalc.CompositionType.CT_WEIGHT_PERCENT,
[
matcalc.Composition("Mg", 0.7),
matcalc.Composition("Si", 0.4)
])
# mole-fraction
mc.setup_composition(
matcalc.CompositionType.CT_MOLE_FRACTION,
[
matcalc.Composition("Mg", 0.7),
matcalc.Composition("Si", 0.4)
])
# u-fraction
mc.setup_composition(
matcalc.CompositionType.CT_U_FRACTION,
[
matcalc.Composition("Mg", 0.7),
matcalc.Composition("Si", 0.4)
])
Calculating equilibrium
mc.set_start_values()
mc.set_temperature_celsius(180.0)
mc.calculate_equilibrium(matcalc.OutputFlags.EO_NORMAL)
Precipitation domains
mc.console("create-precipitation-domain new-domain-name=almatrix")
for parameter, value in {
"thermodynamic-matrix-phase": "fcc_a1",
"initial-grain-diameter": 5.e-05,
"vacancy-evolution-model": "FSAK-dynamics",
# add more parameters here
}.items():
mc.set_precipitation_parameter("almatrix", parameter, value)
print(mc.precipitation_domains())
Precipitate phases
mc.console("create-new-phase parent-phase=cl_mgx precipitate")
for parameter, value in {
"diffuse-interface-energy-effect": True,
"precipitate properties regular-solution-critical-temperature": 800,
"special coalescence-type": "binder-stauffer-dynamics",
"special coalescence-factor": 30,
# add more parameters here
}.items():
mc.set_precipitation_parameter("CL_MGX_P0", parameter, value)
Heat treatments
mc.console("create-tm-treatment tm-treatment-name=aging")
# Quenching from 540°C to 25°C with cooling rate of 100 K/s
mc.console("""
append-tmt-segment tm-treatment-name=aging
edit-tmt-segment tm-treatment-name=aging tm-treatment-segment=. segment-start-temperature=540
edit-tmt-segment tm-treatment-name=aging tm-treatment-segment=. precipitation-domain=almatrix
edit-tmt-segment tm-treatment-name=aging tm-treatment-segment=. T_end+T_dot segment-end-temperature=25 temperature-gradient=-100
edit-tmt-segment tm-treatment-name=aging tm-treatment-segment=. segment-comment=Quenching of solution annealed material
""")
Plotting (when run in MatCalc GUI)
if mc.is_mcg():
mc.console("""
new-gui-window type-id=p1
set-gui-window-property window-id=. default-x-axis-title=Time [h]
set-gui-window-property window-id=. default-x-axis-factor=1/60/60
""")
# Temperature plot
mc.console("""
set-plot-option plot-id=. series new buffer variable-name=t$c
set-plot-option plot-id=. y-axis-title=Temperature [°C]
set-plot-option plot-id=. grid major enable-x-axis=yes
set-plot-option plot-id=. grid major enable-y-axis=yes
""")
Plotting with matplotlib
from ctypes import CFUNCTYPE, c_int
import matcalc
import matplotlib.pyplot as plt
mc = matcalc.get()
mc.init()
y = [[], []]
x = [[], []]
ax = None
fig = None
@CFUNCTYPE(None, c_int)
def buffer_append(index: int):
""" called when a line gets added to the buffer """
y[0].append(mc.get_calc_variable("F_PREC$CL_MGX_P0"))
y[1].append(mc.get_calc_variable("F_PREC$mg5si6_b_dp_P0"))
x[0].append(mc.get_calc_variable("STEPVALUE"))
x[1].append(mc.get_calc_variable("STEPVALUE"))
ax.plot(x[0], y[0])
ax.plot(x[1], y[1])
fig.canvas.draw()
fig.canvas.flush_events()
@CFUNCTYPE(None, c_int)
def buffer_changed(index: int):
""" called when the buffer changes """
pass
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x, y)
mc.register_buffer_append_callback(buffer_append)
mc.register_buffer_changed_callback(buffer_changed)
plt.show(block=False)
# your stuff
plt.show(block=True)
Kinetic step simulation
mc.calculate_kinetic_step()
Buffer variables
mc.get_calc_variable("T$c")
mc.get_buffer_variables(["F_PREC$CL_MGX_P0", "F_PREC$mg5si6_b_dp_P0"])
User variables
You can add buffer variables to MatCalc to be evaluated and or plotted.
import matcalc
from ctypes import CFUNCTYPE, c_char_p, c_double, c_int, c_void_p
mc: matcalc.MatCalc = None
user_variable_cache = {}
@CFUNCTYPE(c_double, c_int, c_int, c_char_p)
def user_variable(buffer: int, line: int, variable: bytes):
""" Called when a user variable is to be resolved.
Args:
buffer (int): The index of the current buffer.
line (int): The index of the current line in the buffer.
variable (bytes): The name of the user variable.
Returns:
float: The value of the user variable.
"""
if variable == b"user1":
# calculate current value of "user1" variable
# depending on the passed parameters
value: float = mc.get_calc_variable("T$c") * buffer * line * 2
return value
raise ValueError(f"unknown variable {variable}")
def setup_mc_callbacks():
# mc is not set when loading a workspace
global mc
if not mc:
mc = matcalc.get()
mc.set_user_variable_callback(user_variable)
def main():
global mc
mc = matcalc.get()
mc.init()
# your stuff
# This block is strictly necessary for callbacks.
#
if __name__ == "__main__":
setup_mc_callbacks()
main()
elif __name__ == "__mc__":
# setup callbacks when loading this script from a workspace
setup_mc_callbacks()
Callbacks
You can set up callback functions which are called on specific events.
import matcalc
from ctypes import CFUNCTYPE, c_char_p, c_double, c_int, c_void_p
mc: matcalc.MatCalc = None
@CFUNCTYPE(None, c_void_p)
def calc_step(user_data):
""" called before a calc step """
pass
@CFUNCTYPE(c_double, c_double, c_double)
def next_delta_time_step(delta_t: float, new_delta_t: float):
""" return a new delta_t if you dare """
return new_delta_t
@CFUNCTYPE(None, c_int)
def buffer_append(index: int):
""" called when a line gets added to the buffer """
pass
@CFUNCTYPE(None, c_int)
def buffer_changed(index: int):
""" called when the buffer changes """
pass
def setup_mc_callbacks():
""" sets up all the callbacks """
# mc is not set when loading a workspace
global mc
if not mc:
mc = matcalc.get()
mc.register_calc_callback(calc_step, None)
mc.set_next_delta_time_step_callback(next_delta_time_step)
mc.register_buffer_append_callback(buffer_append)
mc.register_buffer_changed_callback(buffer_changed)
def main():
global mc
mc = matcalc.get()
mc.init()
# your stuff
# This block is strictly necessary for callbacks.
#
if __name__ == "__main__":
setup_mc_callbacks()
main()
elif __name__ == "__mc__":
# setup callbacks when loading this script from a workspace
setup_mc_callbacks()