Skip to article frontmatterSkip to article content

Practical: Materials Project

In this practical, we will use the Materials Project API to access information about materials. The Materials Project is a database of materials properties that is maintained by the Lawrence Berkeley National Laboratory. The database contains information about the properties of a large number of materials, including their crystal structures, band structures, and thermodynamic properties.

Register for a Materials Project API Key

To access the Materials Project API, you will need to register for an API key. You can register an account of Materials Project by visiting the following website: https://profile.materialsproject.org/

Then you can find your API key in the dashboard page. You should set your MP_API_KEY in the following cell.

MP_API_KEY = "your-key" # check https://next-gen.materialsproject.org/dashboard for your API key

Install the mp_api Package

We need to install mp_api package to access the Materials Project API. You can install the package using the following command:

# you can skip this if you've already installed the mp_api package.
!pip install mp_api 

Querying Data from the Materials Project Database

We can query data from the Materials Project database using the mp_api package. The mp_api package provides a Python interface to the Materials Project API, which allows you to query the database for information about materials. The package provides a number of functions for querying the database, including functions for querying materials by chemical formula, by material ID, and by crystal structure.

To query data from the data base, we need to import the MPRester class from the mp_api package. We can then create an instance of the MPRester class, passing our API key as an argument to the constructor. We can then use the instance to query the database for information about materials.

In the example below, we are searching data using the material_ids.

Query Materials by Material ID

You can query the Materials Project database for information about a material by its material ID. The material ID is a unique identifier that is assigned to each material in the database. You can find the material ID for a material by searching for the material on the Materials Project website.

from mp_api.client import MPRester

# Pass your API key directly as an argument.
with MPRester(MP_API_KEY) as mpr:
    docs = mpr.materials.summary.search(
        material_ids=["mp-149", "mp-13", "mp-2131"]
    )
Loading...

Show the Available Fields

We can check the available properties from mpr.materials.summary.available_fields.

print(f"Available fields: {mpr.materials.summary.available_fields}")

# Print out the data (some) for each material
for example_doc in docs:
    print("\n--------------------")
    print(f"Material ID: {example_doc.material_id}")
    print(f"Theoretical? {example_doc.theoretical}") # whether this structure is a purely theoretical structure or  not (also exist in experiment)
    print(f"Formula: {example_doc.formula_pretty}")
Available fields: ['builder_meta', 'nsites', 'elements', 'nelements', 'composition', 'composition_reduced', 'formula_pretty', 'formula_anonymous', 'chemsys', 'volume', 'density', 'density_atomic', 'symmetry', 'property_name', 'material_id', 'deprecated', 'deprecation_reasons', 'last_updated', 'origins', 'warnings', 'structure', 'task_ids', 'uncorrected_energy_per_atom', 'energy_per_atom', 'formation_energy_per_atom', 'energy_above_hull', 'is_stable', 'equilibrium_reaction_energy_per_atom', 'decomposes_to', 'xas', 'grain_boundaries', 'band_gap', 'cbm', 'vbm', 'efermi', 'is_gap_direct', 'is_metal', 'es_source_calc_id', 'bandstructure', 'dos', 'dos_energy_up', 'dos_energy_down', 'is_magnetic', 'ordering', 'total_magnetization', 'total_magnetization_normalized_vol', 'total_magnetization_normalized_formula_units', 'num_magnetic_sites', 'num_unique_magnetic_sites', 'types_of_magnetic_species', 'bulk_modulus', 'shear_modulus', 'universal_anisotropy', 'homogeneous_poisson', 'e_total', 'e_ionic', 'e_electronic', 'n', 'e_ij_max', 'weighted_surface_energy_EV_PER_ANG2', 'weighted_surface_energy', 'weighted_work_function', 'surface_anisotropy', 'shape_factor', 'has_reconstructed', 'possible_species', 'has_props', 'theoretical', 'database_IDs']

--------------------
Material ID: mp-13
Theoretical? False
Formula: Fe

--------------------
Material ID: mp-2131
Theoretical? False
Formula: SrN6

--------------------
Material ID: mp-149
Theoretical? False
Formula: Si

Customize the Search Function

We can customize our search in search() function. For example, we can search for materials with a specific chemical formula, or we can search for materials with specific density. Please note that sometimes, the search may return lots of results, it’s better to save these results into a json file.

You can use chemsys to search for materials with specific elements. For example, Fe-O will search for materials with Iron and Oxygen. You can also use fields to specify the properties you want to get. You can find more information about the search in the Materials Project API documentation.

with MPRester(MP_API_KEY) as mpr:
    docs = mpr.materials.summary.search(
        chemsys="Li-Fe-P-O", is_stable=True,
        # fields=["material_id", "volume", "elements","structure"]
    )
Loading...
# dump results to a json file
import json
with open('materials_data.json', 'w') as f:
    json.dump([doc.dict() for doc in docs], f, indent=4)

You can use wildcard * to search for all elements. You can also put formula pattern in search. For example, ABO3 will search for ternary materials with formula ending with O3, structure with perovskite related composition.

with MPRester(MP_API_KEY) as mpr:
    docs = mpr.materials.summary.search(
        chemsys="O-*-*", formula="ABO3",
        fields=["material_id", "band_gap","composition", "energy_above_hull"], 
        energy_above_hull=[0,0.01], band_gap=[0.5, 1.5]
    )
    mpid_bgap_dict = {doc.material_id: [doc.band_gap, doc.composition, doc.energy_above_hull] for doc in docs}

print(f"Materials found: {len(mpid_bgap_dict)}")
for mpid, (bgap, composition, energy_above_hull) in mpid_bgap_dict.items():
    print(f"Material ID: {mpid}, Band gap: {bgap:.2f} eV, Composition: {composition}, Energy above hull: {energy_above_hull*1000:.2f} meV")
Loading...

Get Properties

Get Structure

You can get the structure of the material using get_structure_by_material_id() function. It will return a pymatgen.core.Structure object. You can save the structure to a cif file using structure.to() function.

from mp_api.client import MPRester

with MPRester(MP_API_KEY) as mpr:
    structure = mpr.materials.get_structure_by_material_id(material_id="mp-149")

structure.to(filename="mp-149.cif")
                                                      
Loading...

Thermodynamic Properties

You can construct a phase diagram using the queried data from Materials Project using get_phase_diagram_from_chemsys() function. Noted that the phase diagram is calculated using DFT and may not be the same as the experimental phase diagram as there is no temperature and pressure information.

from mp_api.client import MPRester
from emmet.core.thermo import ThermoType

with MPRester(MP_API_KEY) as mpr:
    
    # -- GGA/GGA+U mixed phase diagram
    pd = mpr.materials.thermo.get_phase_diagram_from_chemsys(chemsys="Cu-Au", 
                                                   thermo_type=ThermoType.GGA_GGA_U)
    
pd.get_plot(backend='plotly')
                                                      
Loading...

If you have encountered problem of using plotly to plot your data as backend, you can set the backend to matplotlib.

from mp_api.client import MPRester
from emmet.core.thermo import ThermoType

with MPRester(MP_API_KEY) as mpr:
    
    # -- GGA/GGA+U mixed phase diagram
    pd = mpr.materials.thermo.get_phase_diagram_from_chemsys(chemsys="Li-Fe-P-O", 
                                                   thermo_type=ThermoType.GGA_GGA_U)
                                                      
    

Since this is a pymatgen PhaseDiagram object, you can visualize the results.

pd.get_plot(backend='plotly', show_unstable=False)
Loading...