Tutorial: MagmaForge#

Demonstrates how to use MagmaForge to perform MELTS-style calculations.

Open this code in an executable MyBinder instance (MyBinder links may be slow to load– please be patient!):

https://mybinder.org/badge_logo.svg

Introduction#

MagmaForge is a tool for easily running MELTS-style calculations such as progressive crystallization of liquids. It is designed to be a user-friendly wrapper for the underlying phase model code and equillibration routines available in ThermoEngine. This tutorial demonstrates some of the capabilities available in MagmaForge; it is a work in progress and will be updated over the next few months to demonstrate more capabilities.

Minimum Working Example#

The following code block demonstrates the minimum amount of code necessary to run an equilibrium crystallization routine using MagmaForge. In the following sections, we will go through each part and demonstrate additional capabilities.

from thermoengine import magmaforge
import pandas as pd # a useful data analysis package

morb_oxides = pd.Series({
            'SiO2':  48.68,
            'TiO2':   1.01,
            'Al2O3': 17.64,
            'Fe2O3':  0.89,
            'Cr2O3':  0.0425,
            'FeO':    7.59,
            'MgO':    9.10,
            'CaO':   12.45,
            'Na2O':   2.65,
            'K2O':    0.03,
            'P2O5':   0.08,
            'H2O':    0.2},) # Values in grams (extensive units)

sys = magmaforge.System(comp = morb_oxides,
                        P_bar = 1000.0, # bars
                        T_K = 1600, # K
                        logfO2 = ('NNO',-1), # setting fO2 equal to 1 log unit below the NNO buffer
                        database='MELTS_v1_0', # liquid model name
                        )

sys.crystallize(
      method='equil', # equilibrium crystallization
      Tstep=5, # decrease in temperature at each step, in K
      fix_fO2=True, # hold fO2 constant at initial fO2 value, relative to NNO (more buffers to be implemented soon!)
              )

magmaforge.plot.phase_fractions(sys.history)
plot tutorial magmaforge
/workspaces/ThermoEngineLite/thermoengine/thermoengine/magmaforge/system.py:265: UserWarning: Warning! Setting an fO2 value will overwrite the FeO and Fe2O3 values given.
  warnings.warn('Warning! Setting an fO2 value will overwrite the FeO and Fe2O3 values given.')

Breaking It Down#

1. Initialization#

To use MagmaForge, you’ll first need to import the ThermoEngine package and the MagmaForge module. If you’re running the code locally, you should have already installed ThermoEngine to your computer– here you’re importing it from your computer’s package library into this notebook. If you’re running the code via MyBinder, ThermoEngine is already installed by default in the virtual environment.

from thermoengine import magmaforge

Import Pandas (https://pandas.pydata.org/), a package which provides convenient capabilities for entering, storing, and anaylzing data. If you used Anaconda to create a virtual environment on your machine, Pandas should exist on your machine and the import statement below should work. If you get an error message, you can install Pandas by typing “pip install pandas” into your command line.

import pandas as pd

2. Defining a System#

The first step for most MELTS-style calculations is to define a chemical system– i.e., a bulk chemical composition equilibrated at a set of conditions (usually pressure and temperature, but sometimes other variables like entropy or volume). Here, let’s imagine that we’re interested in a mid-ocean ridge basalt. We can define the bulk chemical composition using a series, which is a data type specific to the Pandas package– the ‘pd’ indicates that we are invoking this package.

morb_oxides = pd.Series({
            'SiO2':  48.68,
            'TiO2':   1.01,
            'Al2O3': 17.64,
            'Fe2O3':  0.89,
            'Cr2O3':  0.0425,
            'FeO':    7.59,
            'MgO':    9.10,
            'CaO':   12.45,
            'Na2O':   2.65,
            'K2O':    0.03,
            'P2O5':   0.08,
            'H2O':    0.2},) # values in grams (extensive units)

Now that we have a bulk chemical composition, we can use MagmaForge to equilibrate the MORB composition at the conditions of interest. We use the magmaforge.System() call to create a system object at the indicated composition, pressure, temperature, and fO2. Here, the initial temperature is chosen to be above the liquidus of the system so that later calculations can crystallize the system.

sys = magmaforge.System(comp = morb_oxides,
                        P_bar = 1000.0, # bars
                        T_K = 1600, # K
                        logfO2 = ('NNO', -1), # setting fO2 equal to 1 log unit below the NNO buffer
                        database='MELTS_v1_0', # liquid model name
                        )
/workspaces/ThermoEngineLite/thermoengine/thermoengine/magmaforge/system.py:265: UserWarning: Warning! Setting an fO2 value will overwrite the FeO and Fe2O3 values given.
  warnings.warn('Warning! Setting an fO2 value will overwrite the FeO and Fe2O3 values given.')

The sys object that we created in the last cell represents our equilibrated chemical system. We can probe this system to ensure our calculation had the expected behavior. For instance, in the cell below, we are querying the temperature (in K), pressure (in bars), and melt fraction of the system.

print(sys.T_C)
print(sys.P_GPa)
print(sys.melt_fraction)
1326.85
0.1
1.0

3. Performing a Calculation Along a Path#

Now that we have our chemical system, we can perform calculations such as crystallization during cooling. To do this, we will apply the crystallize method to our system. We tell it that we want to use the ‘equil’ (equilibrium/batch crystallization) method of crystallizing, that we want to decrease in temperature steps of 15°, and that we want to hold fO2 steady at the value we set for the system– here NNO -1.

This calculation may return a message reading “No check made for phase separation.” This is fine!

sys.crystallize(
      method='equil', # equilibrium crystallization
      Tstep=15, # decrease in temperature at each step, in K
      fix_fO2=True, # hold fO2 constant at initial fO2 value, relative to NNO (more buffers to be implemented soon!)
              )
Bad phase composition for Liquid: [ 9.51536524e-08  3.16490592e-06 -7.97877731e-07  4.12861483e-07
  3.08050640e-09 -4.63763903e-04  0.00000000e+00  6.90490869e-05
  0.00000000e+00  0.00000000e+00  5.63087312e-07  0.00000000e+00
  1.59575585e-06  5.61144607e-04  3.83830588e-05]
/workspaces/ThermoEngineLite/thermoengine/thermoengine/magmaforge/system.py:618: UserWarning: Warning: Unsuccessful cooling step ended equilibrium calculation.
  warnings.warn("Warning: Unsuccessful cooling step ended equilibrium calculation.")

<thermoengine.magmaforge.system.System object at 0xffff936f36a0>

Accessing/Plotting Output#

1. Accessing Output as a Plot#

Once you have performed your calculations, you probably want to see the results. MagmaForge has a few built-in plotting functions for creating basic plots. MagmaForge has a few simple built-in plots that can be called using the magmaforge.plot submodule. Here we’re using the .phase_fractions() method to create an automatic plot of phase fractions with respect to temperature as the system cools. The sys.history object contains the history of the system’s state after each calculation and will be very useful for accessing output.

magmaforge.plot.phase_fractions(sys.history)
plot tutorial magmaforge

For a somewhat more in-depth look at our results, we can use magmaforge.plot.magma_evolution() to plot the phase fractions and magma composition during crystallization.

magmaforge.plot.magma_evolution(sys.history)
plot tutorial magmaforge

You can, of course, also create custom plots using the output of the run. We’ll show some examples in a later section.

2. Accessing Output as a Table#

You may also want to access numerical output for your run. Recall that the sys.history object stores the information of the state of the system after each calculation. We can access a table showing the fractions of each phase after each calculation step using the .get_phase_frac_table() method. Here we’re using the ‘present’ argument to only display columns for phases that are present at some point during the run.

sys.history.get_phase_frac_table(phases='present')
Olivine Feldspar Clinopyroxene Orthopyroxene Spinel Water Liquid
1600.0 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000000
1585.0 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000005
1570.0 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000010
1555.0 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000016
1540.0 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000022
1525.0 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000029
1510.0 0.000000 0.000000 0.000000 0.000000 0.000034 0.000000 1.000002
1495.0 0.000000 0.012359 0.000000 0.000000 0.000427 0.000000 0.987260
1480.0 0.032009 0.117035 0.000000 0.000000 0.000295 0.000000 0.850664
1465.0 0.059590 0.214136 0.054031 0.000000 0.000479 0.000000 0.671733
1450.0 0.076850 0.285288 0.115116 0.000000 0.000764 0.000000 0.521909
1435.0 0.090468 0.336387 0.157529 0.000000 0.001049 0.000000 0.414443
1420.0 0.102319 0.374142 0.188995 0.000000 0.001455 0.000000 0.332916
1405.0 0.113145 0.402511 0.214124 0.000000 0.002367 0.000000 0.267639
1390.0 0.122456 0.424581 0.235866 0.000000 0.004799 0.000000 0.212077
1375.0 0.128488 0.442708 0.254014 0.000000 0.009337 0.000000 0.165278
1360.0 0.130846 0.457474 0.266713 0.000000 0.014480 0.000000 0.130404
1345.0 0.131270 0.468970 0.274722 0.000000 0.018759 0.000000 0.106296
1330.0 0.130962 0.477964 0.279780 0.000000 0.022095 0.000000 0.089308
1315.0 0.130445 0.485194 0.283016 0.000000 0.024713 0.000000 0.076822
1300.0 0.128643 0.490717 0.283571 0.003737 0.026671 0.000000 0.066922
1285.0 0.125375 0.494711 0.281715 0.011789 0.028097 0.000000 0.058643
1270.0 0.122468 0.498034 0.279836 0.018895 0.029259 0.000000 0.051899
1255.0 0.119143 0.510544 0.279054 0.026573 0.030943 0.000593 0.033609
1240.0 0.118019 0.525932 0.278498 0.031750 0.031940 0.001459 0.012890


The composition of the liquid can be accessed using the .get_liquid_comp_table() method:

sys.history.get_liquid_comp_table()
SiO2 TiO2 Al2O3 Fe2O3 Cr2O3 FeO MnO MgO NiO CoO CaO Na2O K2O P2O5 H2O CO2
1600.0 48.491314 1.006085 17.571626 1.151156 0.042335 7.322485 0.0 9.064728 0.0 0.0 12.401743 2.639728 0.029884 0.079690 0.199225 0.0
1585.0 48.491076 1.006080 17.571540 1.156032 0.042335 7.318057 0.0 9.064684 0.0 0.0 12.401682 2.639716 0.029884 0.079690 0.199224 0.0
1570.0 48.490820 1.006075 17.571447 1.161306 0.042335 7.313267 0.0 9.064636 0.0 0.0 12.401617 2.639702 0.029883 0.079689 0.199223 0.0
1555.0 48.490543 1.006069 17.571347 1.166998 0.042335 7.308098 0.0 9.064584 0.0 0.0 12.401546 2.639687 0.029883 0.079689 0.199222 0.0
1540.0 48.490245 1.006063 17.571239 1.173127 0.042334 7.302532 0.0 9.064528 0.0 0.0 12.401470 2.639670 0.029883 0.079688 0.199220 0.0
1525.0 48.489925 1.006056 17.571123 1.179713 0.042334 7.296551 0.0 9.064468 0.0 0.0 12.401388 2.639653 0.029883 0.079688 0.199219 0.0
1510.0 48.491237 1.006059 17.570306 1.186756 0.041583 7.289742 0.0 9.064071 0.0 0.0 12.401724 2.639724 0.029884 0.079690 0.199224 0.0
1495.0 48.520545 1.018748 17.360075 1.208397 0.034349 7.370188 0.0 9.173484 0.0 0.0 12.353455 2.648007 0.030237 0.080718 0.201796 0.0
1480.0 48.863868 1.182325 16.066667 1.351609 0.041581 8.090838 0.0 8.926090 0.0 0.0 12.329648 2.784825 0.034671 0.093680 0.234199 0.0
1465.0 48.966253 1.458056 15.291877 1.531175 0.044818 9.193526 0.0 8.212275 0.0 0.0 11.767912 3.075854 0.043038 0.118633 0.296583 0.0
1450.0 48.795794 1.781984 14.883767 1.704369 0.044051 10.399859 0.0 7.458986 0.0 0.0 10.943984 3.398882 0.053913 0.152689 0.381723 0.0
1435.0 48.562393 2.095327 14.540735 1.852472 0.041536 11.439968 0.0 6.797415 0.0 0.0 10.266644 3.664822 0.065701 0.192282 0.480704 0.0
1420.0 48.386096 2.368341 14.292029 1.969881 0.036365 12.251508 0.0 6.190106 0.0 0.0 9.686065 3.903072 0.078745 0.239370 0.598424 0.0
1405.0 48.467096 2.535421 14.181991 2.043982 0.026987 12.711331 0.0 5.593854 0.0 0.0 9.144572 4.158707 0.093928 0.297752 0.744379 0.0
1390.0 49.116167 2.477598 14.272424 2.050470 0.014061 12.595118 0.0 4.964277 0.0 0.0 8.577740 4.503684 0.113301 0.375760 0.939400 0.0
1375.0 50.430869 2.161218 14.556256 1.971526 0.005338 11.766810 0.0 4.326898 0.0 0.0 7.991814 4.963188 0.138539 0.482156 1.205389 0.0
1360.0 51.935958 1.778036 14.886680 1.837296 0.002312 10.556057 0.0 3.784938 0.0 0.0 7.493470 5.419247 0.167159 0.611099 1.527748 0.0
1345.0 53.232930 1.470691 15.160291 1.691195 0.001330 9.360491 0.0 3.367486 0.0 0.0 7.124872 5.771166 0.195617 0.749695 1.874237 0.0
1330.0 54.275158 1.242626 15.369390 1.550682 0.000935 8.300656 0.0 3.042488 0.0 0.0 6.857893 6.014352 0.222753 0.892305 2.230761 0.0
1315.0 55.106658 1.070556 15.527520 1.420509 0.000748 7.383105 0.0 2.779927 0.0 0.0 6.662147 6.169684 0.248463 1.037338 2.593344 0.0
1300.0 55.618002 0.920012 15.664218 1.315918 0.000645 6.641169 0.0 2.549827 0.0 0.0 6.508365 6.340630 0.273459 1.190787 2.976967 0.0
1285.0 55.767039 0.777934 15.800501 1.238832 0.000581 6.053506 0.0 2.337050 0.0 0.0 6.385435 6.584843 0.298152 1.358893 3.397234 0.0
1270.0 55.774687 0.660431 15.920164 1.167920 0.000545 5.530195 0.0 2.149041 0.0 0.0 6.300705 6.800282 0.321843 1.535482 3.838705 0.0
1255.0 54.948123 0.571982 15.625075 1.111378 0.000500 4.962533 0.0 2.006464 0.0 0.0 6.967633 6.877411 0.393680 2.371086 4.164135 0.0
1240.0 50.116832 0.551674 13.906673 1.089800 0.000557 4.142626 0.0 2.088064 0.0 0.0 11.185564 6.080630 0.520442 6.182326 4.134813 0.0


The composition of phases can be accessed using the .get_mineral_comp_table() method:

sys.history.get_mineral_comp_table('Feldspar')
SiO2 TiO2 Al2O3 Fe2O3 Cr2O3 FeO MnO MgO NiO CoO CaO Na2O K2O P2O5 H2O CO2
1600.0 0.000000 0.0 0.000000 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 0.0 0.0 0.0
1585.0 0.000000 0.0 0.000000 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 0.0 0.0 0.0
1570.0 0.000000 0.0 0.000000 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 0.0 0.0 0.0
1555.0 0.000000 0.0 0.000000 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 0.0 0.0 0.0
1540.0 0.000000 0.0 0.000000 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 0.0 0.0 0.0
1525.0 0.000000 0.0 0.000000 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 0.0 0.0 0.0
1510.0 0.000000 0.0 0.000000 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.000000 0.000000 0.0 0.0 0.0
1495.0 47.649538 0.0 33.647186 0.0 0.0 0.0 0.0 0.0 0.0 0.0 16.640997 2.059715 0.002564 0.0 0.0 0.0
1480.0 48.199463 0.0 33.276602 0.0 0.0 0.0 0.0 0.0 0.0 0.0 16.206945 2.313656 0.003334 0.0 0.0 0.0
1465.0 48.886017 0.0 32.813889 0.0 0.0 0.0 0.0 0.0 0.0 0.0 15.665006 2.630541 0.004548 0.0 0.0 0.0
1450.0 49.581489 0.0 32.345088 0.0 0.0 0.0 0.0 0.0 0.0 0.0 15.115963 2.951340 0.006120 0.0 0.0 0.0
1435.0 50.180395 0.0 31.941287 0.0 0.0 0.0 0.0 0.0 0.0 0.0 14.643077 3.227351 0.007890 0.0 0.0 0.0
1420.0 50.687794 0.0 31.599090 0.0 0.0 0.0 0.0 0.0 0.0 0.0 14.242367 3.460945 0.009804 0.0 0.0 0.0
1405.0 51.111811 0.0 31.313039 0.0 0.0 0.0 0.0 0.0 0.0 0.0 13.907435 3.655926 0.011788 0.0 0.0 0.0
1390.0 51.460308 0.0 31.077854 0.0 0.0 0.0 0.0 0.0 0.0 0.0 13.632088 3.815960 0.013790 0.0 0.0 0.0
1375.0 51.745013 0.0 30.885638 0.0 0.0 0.0 0.0 0.0 0.0 0.0 13.407077 3.946491 0.015781 0.0 0.0 0.0
1360.0 51.982584 0.0 30.725192 0.0 0.0 0.0 0.0 0.0 0.0 0.0 13.219274 4.055276 0.017674 0.0 0.0 0.0
1345.0 52.182210 0.0 30.590346 0.0 0.0 0.0 0.0 0.0 0.0 0.0 13.061445 4.146615 0.019384 0.0 0.0 0.0
1330.0 52.348759 0.0 30.477823 0.0 0.0 0.0 0.0 0.0 0.0 0.0 12.929751 4.222766 0.020901 0.0 0.0 0.0
1315.0 52.487572 0.0 30.384020 0.0 0.0 0.0 0.0 0.0 0.0 0.0 12.819972 4.286184 0.022252 0.0 0.0 0.0
1300.0 52.595890 0.0 30.310756 0.0 0.0 0.0 0.0 0.0 0.0 0.0 12.734254 4.335495 0.023605 0.0 0.0 0.0
1285.0 52.679772 0.0 30.253928 0.0 0.0 0.0 0.0 0.0 0.0 0.0 12.667798 4.373438 0.025063 0.0 0.0 0.0
1270.0 52.754431 0.0 30.203325 0.0 0.0 0.0 0.0 0.0 0.0 0.0 12.608630 4.407149 0.026465 0.0 0.0 0.0
1255.0 53.030093 0.0 30.016265 0.0 0.0 0.0 0.0 0.0 0.0 0.0 12.389982 4.531043 0.032617 0.0 0.0 0.0
1240.0 53.370965 0.0 29.784091 0.0 0.0 0.0 0.0 0.0 0.0 0.0 12.118899 4.681980 0.044065 0.0 0.0 0.0


Any of these tables can be easily downloaded as a csv file using built-in Pandas commands:

If you are running in a MyBinder, be sure to download your output file to your machine before closing your session!

table_to_export = sys.history.get_phase_frac_table(phases='present')
table_to_export.to_csv('output.csv', index=True)

3. Accessing outputs as variables/data structures#

You can also access each property of the system as an array or other data structure, which can be helpful if you want to do further math with the outputs.

T = sys.history.get_temperatures('K')
P = sys.history.get_pressures('bar')
S = sys.history.get_total_entropies()

F = sys.history.get_instantaneous_melt_fractions()
phase_frac = sys.history.get_phase_fractions()

comp_liq = sys.history.get_liquid_comps()
comp_phs = sys.history.get_mineral_comps('Feldspar')

print(T) # replace with whichever variable you'd like to view
[1600. 1585. 1570. 1555. 1540. 1525. 1510. 1495. 1480. 1465. 1450. 1435.
 1420. 1405. 1390. 1375. 1360. 1345. 1330. 1315. 1300. 1285. 1270. 1255.
 1240.]

More methods are documented in the MagmaForge API reference: https://thermoenginelite.readthedocs.io/en/latest/api/index.html

Total running time of the script: (0 minutes 23.765 seconds)

Gallery generated by Sphinx-Gallery