Pymatgen and the Materials Project API#

Pymatgen - Python Materials Genomics#

Pymatgen is a Python package similar to ase. pymatgen is designed to support VASP and ABINIT. Like ase, we will not be able to cover much of the extensive functionality of pymatgen.

Note

Our use of pymatgen will be very limited. Nonetheless, we will install pymatgen for use as a converter: we can obtain crystal structure data from the Materials Project and convert it to an ase Atoms object.

Installation#

If you need to, please install pymatgen, please do so using a command such as pip3 install pymatgen.

MPRester - The Materials Project API#

The Materials Project API allows a user to query information from the Materials Project.

Installation#

The Materials Project API is coded in the Python package MPRester. To use ASE, you must first install the ase Python module. You may use a command such as pip3 install mp-api to do this.

Important

Note

An API key is required to use MPRester.

  • You must be logged in on materialsproject.org to obtain your API key.

  • You can obtain your personal API key from your Materials Project Dashboard, or you can get it from the documentation page.

  • Your API key is a long alphanumeric string (about 30 characters) that you must use every time you wish to query the Materials Project programmatically via the API.

Using MPRester#

To use your API key, it is helpful to store its value in a string, like this:

# Save your Materials Project API as a string
MP_API_KEY = '---your api key here ----'

Once the API key is stored as a string in a variable (here, we used the variable MP_API_KEY), that variable is used as a parameter with MPRester to obtain information from the Materials Project. The syntax is to define a code block using code like with MPRester(MP_API_KEY) as mpr:. Following this line, indented lines define a code block in which we can access the API methods using the syntax mpr.some_method(). Let’s start with some examples of MPRester usage.

Example: Get the Crystal Structure of a Specific Material#

In the Materials Project, each material has a unique identifier, known as its Materials Project ID (MPID). When you want information about a single material, it is reasonable to perform a manual search using the Materials Explorer for the material so you can find its MPID. Then, you can use the MPID along with MPRester to automate queries about the material.

As an example, YBa2Cu3O7 has mp-20674 as its MPID. We can obtain its crystal structure directly using this MPID. To do this, we do the following:

from mp_api.client import MPRester
import os
import pymatgen as pmg

from ase.io import write

MPID = 'mp-20674' # Materials Project ID number

"""
  The 'with ...' statement defines an MPRester code block. Subsequent
  indented statements belong to the code block, and the object mpr
  may be used within the code block.
"""
with MPRester(MP_API_KEY) as mpr:
    # Get only the structure for YBa2Cu3O7
    structure = mpr.get_structure_by_material_id(MPID)
Hide code cell output
/media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/mp_api/client/mprester.py:182: UserWarning: mpcontribs-client not installed. Install the package to query MPContribs data, or construct pourbaix diagrams: 'pip install mpcontribs-client'
  warnings.warn(

The MPRester method, get_structure_by_material_id(), accessible as mpr.get_structure_by_material(), queries the Materials Project and returns the crystal structure, storing it in an object structure. Having accessed the Materials Project, we no longer require the mpr object. We can now exit the MPRester code block by resetting the indentation.

Next, we provide code to inspect the structure we downloaded. What is its data type? How can we use it?

"""
  Reset the indentation (exith the 'with' block), and examine the
  structure we obtained.
"""
print('\nWhat is the data type of the structure we obtained?')
print(type(structure))

print('\nWhat is the structure we obtained?')
print(structure)
What is the data type of the structure we obtained?
<class 'pymatgen.core.structure.Structure'>

What is the structure we obtained?
Full Formula (Ba2 Y1 Cu3 O7)
Reduced Formula: Ba2YCu3O7
abc   :   3.844668   3.926152  11.823664
angles:  90.000000  90.000000  90.000000
pbc   :       True       True       True
Sites (13)
  #  SP      a    b         c    magmom
---  ----  ---  ---  --------  --------
  0  Ba    0.5  0.5  0.819391        -0
  1  Ba    0.5  0.5  0.180609        -0
  2  Y     0.5  0.5  0.5              0
  3  Cu    0    0    0.646678        -0
  4  Cu    0    0    0.353322        -0
  5  Cu    0    0    0                0
  6  O     0    0.5  0                0
  7  O     0.5  0    0.620653        -0
  8  O     0.5  0    0.379347        -0
  9  O     0    0.5  0.621651        -0
 10  O     0    0.5  0.378349        -0
 11  O     0    0    0.84082          0
 12  O     0    0    0.15918          0

The output of the above code cell indicates that the data in structure is in a format compatible with pymatgen. pymatgen has a tool to convert the pymatgen structure to an ase object, which we can visualize.

from pymatgen.io.ase import AseAtomsAdaptor as aaa

"""
   We use pymatgen to convert the structure to an
   ASE object. Since our work with the MaterialsProject
   API is complete, this can be done outside the WITH
   block.
"""
crystal = aaa.get_atoms(structure) # convert pymatgen to ase

# Make a static visualization
orientation='90x,75y,-9x'
write('YBa2Cu3O7_structure.png', crystal, show_unit_cell=2,
      rotation=orientation)

The following code creates an interactive visualization for the downloaded crystal structure.

from ase.visualize import view

# Interactive 3D visualization
view(crystal, viewer='x3d')
ASE atomic visualization

Having obtained the crystal structure, we can now use it in a variety of ways:

  • Use it within an atomistic simulation

  • Use ase.io.write() to save the structure in a structure file (*.cif, *.xyz, etc.)

Example: Getting the Band Structure for a Material#

We can use the MPRester class to obtain band structures for a material:

mpid = "mp-149" # this is the MPID for silicon crystal (diamond lattice)

with MPRester(MP_API_KEY) as mpr:
    bs = mpr.get_bandstructure_by_material_id("mp-149")
Hide code cell output

This returns a pymatgen band structure object, and pymatgen has a tool for plotting this structure.

from pymatgen.electronic_structure.plotter import BSPlotter

# plot & show the band structure we obtained
BSPlotter(bs).get_plot().show()
../_images/6ebaba3c9d98bc1722776b0b39353073d367e21a5e5884a24034d9f2428abe69.png

Example: Searching using MPRester#

Materials Project data can be queried in two ways:

  • through a specific (list of) MPID(s), and/or

  • through property filters (e.g. band gap less than 0.5 eV)

When querying a list of MPIDs, we use the following syntax:

with MPRester(MP_API_KEY) as mpr:
    docs = mpr.summary.search(material_ids=["mp-149", "mp-13", "mp-22526"])
Hide code cell output
/media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/mp_api/client/mprester.py:182: UserWarning: mpcontribs-client not installed. Install the package to query MPContribs data, or construct pourbaix diagrams: 'pip install mpcontribs-client'
  warnings.warn(

Here, each material entry in the Materials Project has summary data, and we are simply searching the summary data using mpr.summary.search(). Since we queried for a list of MPIDs, we store in docs a list of “documents” (formally, a list of MPDataDoc objects).

We can now reference an individual document and extract its properties. We’ll use a for loop to list the MPID and chemical formula for each search hit:

print('Our query returned {0} docs.'.format( len(docs) ))

for idx, mat_doc in enumerate(docs):
    print('Item {0}: MPID = {1} (formula: {2})'.format(idx,
                                                       mat_doc.material_id,
                                                       mat_doc.formula_pretty))
Our query returned 3 docs.
Item 0: MPID = mp-149 (formula: Si)
Item 1: MPID = mp-13 (formula: Fe)
Item 2: MPID = mp-22526 (formula: LiCoO2)

What properties ('material_id', 'formula_pretty', etc.) are available for search in the summary data? We can obtain a list of document properties using the following syntax:

print(mpr.summary.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', 'k_voigt', 'k_reuss', 'k_vrh', 'g_voigt', 'g_reuss', 'g_vrh', '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']

Next, we query using property filters. We apply the following filters:

  • Materials containing Si and O

  • Materials with a band gap no greater than 1.0 eV but no less than 0.5 eV

  • Instead of all available summary fields, we’ll only ask for a few: "material_id", "formula_pretty", "band_gap".

with MPRester(MP_API_KEY) as mpr:
    docs = mpr.summary.search(elements=["Si", "O"],
                              band_gap=(0.5, 0.75),
                              fields=["material_id", "formula_pretty",
                                      "band_gap"])

example_doc = docs[0]
# initial_structures = example_doc.initial_structures
Hide code cell output
---------------------------------------------------------------------------
ConnectionResetError                      Traceback (most recent call last)
File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/urllib3/connectionpool.py:790, in HTTPConnectionPool.urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)
    789 # Make the request on the HTTPConnection object
--> 790 response = self._make_request(
    791     conn,
    792     method,
    793     url,
    794     timeout=timeout_obj,
    795     body=body,
    796     headers=headers,
    797     chunked=chunked,
    798     retries=retries,
    799     response_conn=response_conn,
    800     preload_content=preload_content,
    801     decode_content=decode_content,
    802     **response_kw,
    803 )
    805 # Everything went great!

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/urllib3/connectionpool.py:491, in HTTPConnectionPool._make_request(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)
    490         new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)
--> 491     raise new_e
    493 # conn.request() calls http.client.*.request, not the method in
    494 # urllib3.request. It also calls makefile (recv) on the socket.

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/urllib3/connectionpool.py:467, in HTTPConnectionPool._make_request(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)
    466 try:
--> 467     self._validate_conn(conn)
    468 except (SocketTimeout, BaseSSLError) as e:

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/urllib3/connectionpool.py:1092, in HTTPSConnectionPool._validate_conn(self, conn)
   1091 if conn.is_closed:
-> 1092     conn.connect()
   1094 if not conn.is_verified:

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/urllib3/connection.py:635, in HTTPSConnection.connect(self)
    627     warnings.warn(
    628         (
    629             f"System time is way off (before {RECENT_DATE}). This will probably "
   (...)
    632         SystemTimeWarning,
    633     )
--> 635 sock_and_verified = _ssl_wrap_socket_and_match_hostname(
    636     sock=sock,
    637     cert_reqs=self.cert_reqs,
    638     ssl_version=self.ssl_version,
    639     ssl_minimum_version=self.ssl_minimum_version,
    640     ssl_maximum_version=self.ssl_maximum_version,
    641     ca_certs=self.ca_certs,
    642     ca_cert_dir=self.ca_cert_dir,
    643     ca_cert_data=self.ca_cert_data,
    644     cert_file=self.cert_file,
    645     key_file=self.key_file,
    646     key_password=self.key_password,
    647     server_hostname=server_hostname,
    648     ssl_context=self.ssl_context,
    649     tls_in_tls=tls_in_tls,
    650     assert_hostname=self.assert_hostname,
    651     assert_fingerprint=self.assert_fingerprint,
    652 )
    653 self.sock = sock_and_verified.socket

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/urllib3/connection.py:774, in _ssl_wrap_socket_and_match_hostname(sock, cert_reqs, ssl_version, ssl_minimum_version, ssl_maximum_version, cert_file, key_file, key_password, ca_certs, ca_cert_dir, ca_cert_data, assert_hostname, assert_fingerprint, server_hostname, ssl_context, tls_in_tls)
    772         server_hostname = normalized
--> 774 ssl_sock = ssl_wrap_socket(
    775     sock=sock,
    776     keyfile=key_file,
    777     certfile=cert_file,
    778     key_password=key_password,
    779     ca_certs=ca_certs,
    780     ca_cert_dir=ca_cert_dir,
    781     ca_cert_data=ca_cert_data,
    782     server_hostname=server_hostname,
    783     ssl_context=context,
    784     tls_in_tls=tls_in_tls,
    785 )
    787 try:

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/urllib3/util/ssl_.py:459, in ssl_wrap_socket(sock, keyfile, certfile, cert_reqs, ca_certs, server_hostname, ssl_version, ciphers, ssl_context, ca_cert_dir, key_password, ca_cert_data, tls_in_tls)
    457     pass
--> 459 ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)
    460 return ssl_sock

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/urllib3/util/ssl_.py:503, in _ssl_wrap_socket_impl(sock, ssl_context, tls_in_tls, server_hostname)
    501     return SSLTransport(sock, ssl_context, server_hostname)
--> 503 return ssl_context.wrap_socket(sock, server_hostname=server_hostname)

File /usr/lib/python3.10/ssl.py:513, in SSLContext.wrap_socket(self, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname, session)
    507 def wrap_socket(self, sock, server_side=False,
    508                 do_handshake_on_connect=True,
    509                 suppress_ragged_eofs=True,
    510                 server_hostname=None, session=None):
    511     # SSLSocket class handles server_hostname encoding before it calls
    512     # ctx._wrap_socket()
--> 513     return self.sslsocket_class._create(
    514         sock=sock,
    515         server_side=server_side,
    516         do_handshake_on_connect=do_handshake_on_connect,
    517         suppress_ragged_eofs=suppress_ragged_eofs,
    518         server_hostname=server_hostname,
    519         context=self,
    520         session=session
    521     )

File /usr/lib/python3.10/ssl.py:1071, in SSLSocket._create(cls, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname, context, session)
   1070             raise ValueError("do_handshake_on_connect should not be specified for non-blocking sockets")
-> 1071         self.do_handshake()
   1072 except (OSError, ValueError):

File /usr/lib/python3.10/ssl.py:1342, in SSLSocket.do_handshake(self, block)
   1341         self.settimeout(None)
-> 1342     self._sslobj.do_handshake()
   1343 finally:

ConnectionResetError: [Errno 104] Connection reset by peer

During handling of the above exception, another exception occurred:

ProtocolError                             Traceback (most recent call last)
File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/requests/adapters.py:486, in HTTPAdapter.send(self, request, stream, timeout, verify, cert, proxies)
    485 try:
--> 486     resp = conn.urlopen(
    487         method=request.method,
    488         url=url,
    489         body=request.body,
    490         headers=request.headers,
    491         redirect=False,
    492         assert_same_host=False,
    493         preload_content=False,
    494         decode_content=False,
    495         retries=self.max_retries,
    496         timeout=timeout,
    497         chunked=chunked,
    498     )
    500 except (ProtocolError, OSError) as err:

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/urllib3/connectionpool.py:844, in HTTPConnectionPool.urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)
    842     new_e = ProtocolError("Connection aborted.", new_e)
--> 844 retries = retries.increment(
    845     method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]
    846 )
    847 retries.sleep()

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/urllib3/util/retry.py:470, in Retry.increment(self, method, url, response, error, _pool, _stacktrace)
    469 if read is False or method is None or not self._is_method_retryable(method):
--> 470     raise reraise(type(error), error, _stacktrace)
    471 elif read is not None:

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/urllib3/util/util.py:38, in reraise(tp, value, tb)
     37 if value.__traceback__ is not tb:
---> 38     raise value.with_traceback(tb)
     39 raise value

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/urllib3/connectionpool.py:790, in HTTPConnectionPool.urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)
    789 # Make the request on the HTTPConnection object
--> 790 response = self._make_request(
    791     conn,
    792     method,
    793     url,
    794     timeout=timeout_obj,
    795     body=body,
    796     headers=headers,
    797     chunked=chunked,
    798     retries=retries,
    799     response_conn=response_conn,
    800     preload_content=preload_content,
    801     decode_content=decode_content,
    802     **response_kw,
    803 )
    805 # Everything went great!

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/urllib3/connectionpool.py:491, in HTTPConnectionPool._make_request(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)
    490         new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)
--> 491     raise new_e
    493 # conn.request() calls http.client.*.request, not the method in
    494 # urllib3.request. It also calls makefile (recv) on the socket.

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/urllib3/connectionpool.py:467, in HTTPConnectionPool._make_request(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)
    466 try:
--> 467     self._validate_conn(conn)
    468 except (SocketTimeout, BaseSSLError) as e:

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/urllib3/connectionpool.py:1092, in HTTPSConnectionPool._validate_conn(self, conn)
   1091 if conn.is_closed:
-> 1092     conn.connect()
   1094 if not conn.is_verified:

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/urllib3/connection.py:635, in HTTPSConnection.connect(self)
    627     warnings.warn(
    628         (
    629             f"System time is way off (before {RECENT_DATE}). This will probably "
   (...)
    632         SystemTimeWarning,
    633     )
--> 635 sock_and_verified = _ssl_wrap_socket_and_match_hostname(
    636     sock=sock,
    637     cert_reqs=self.cert_reqs,
    638     ssl_version=self.ssl_version,
    639     ssl_minimum_version=self.ssl_minimum_version,
    640     ssl_maximum_version=self.ssl_maximum_version,
    641     ca_certs=self.ca_certs,
    642     ca_cert_dir=self.ca_cert_dir,
    643     ca_cert_data=self.ca_cert_data,
    644     cert_file=self.cert_file,
    645     key_file=self.key_file,
    646     key_password=self.key_password,
    647     server_hostname=server_hostname,
    648     ssl_context=self.ssl_context,
    649     tls_in_tls=tls_in_tls,
    650     assert_hostname=self.assert_hostname,
    651     assert_fingerprint=self.assert_fingerprint,
    652 )
    653 self.sock = sock_and_verified.socket

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/urllib3/connection.py:774, in _ssl_wrap_socket_and_match_hostname(sock, cert_reqs, ssl_version, ssl_minimum_version, ssl_maximum_version, cert_file, key_file, key_password, ca_certs, ca_cert_dir, ca_cert_data, assert_hostname, assert_fingerprint, server_hostname, ssl_context, tls_in_tls)
    772         server_hostname = normalized
--> 774 ssl_sock = ssl_wrap_socket(
    775     sock=sock,
    776     keyfile=key_file,
    777     certfile=cert_file,
    778     key_password=key_password,
    779     ca_certs=ca_certs,
    780     ca_cert_dir=ca_cert_dir,
    781     ca_cert_data=ca_cert_data,
    782     server_hostname=server_hostname,
    783     ssl_context=context,
    784     tls_in_tls=tls_in_tls,
    785 )
    787 try:

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/urllib3/util/ssl_.py:459, in ssl_wrap_socket(sock, keyfile, certfile, cert_reqs, ca_certs, server_hostname, ssl_version, ciphers, ssl_context, ca_cert_dir, key_password, ca_cert_data, tls_in_tls)
    457     pass
--> 459 ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)
    460 return ssl_sock

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/urllib3/util/ssl_.py:503, in _ssl_wrap_socket_impl(sock, ssl_context, tls_in_tls, server_hostname)
    501     return SSLTransport(sock, ssl_context, server_hostname)
--> 503 return ssl_context.wrap_socket(sock, server_hostname=server_hostname)

File /usr/lib/python3.10/ssl.py:513, in SSLContext.wrap_socket(self, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname, session)
    507 def wrap_socket(self, sock, server_side=False,
    508                 do_handshake_on_connect=True,
    509                 suppress_ragged_eofs=True,
    510                 server_hostname=None, session=None):
    511     # SSLSocket class handles server_hostname encoding before it calls
    512     # ctx._wrap_socket()
--> 513     return self.sslsocket_class._create(
    514         sock=sock,
    515         server_side=server_side,
    516         do_handshake_on_connect=do_handshake_on_connect,
    517         suppress_ragged_eofs=suppress_ragged_eofs,
    518         server_hostname=server_hostname,
    519         context=self,
    520         session=session
    521     )

File /usr/lib/python3.10/ssl.py:1071, in SSLSocket._create(cls, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname, context, session)
   1070             raise ValueError("do_handshake_on_connect should not be specified for non-blocking sockets")
-> 1071         self.do_handshake()
   1072 except (OSError, ValueError):

File /usr/lib/python3.10/ssl.py:1342, in SSLSocket.do_handshake(self, block)
   1341         self.settimeout(None)
-> 1342     self._sslobj.do_handshake()
   1343 finally:

ProtocolError: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))

During handling of the above exception, another exception occurred:

ConnectionError                           Traceback (most recent call last)
Cell In[12], line 1
----> 1 with MPRester(MP_API_KEY) as mpr:
      2     docs = mpr.summary.search(elements=["Si", "O"],
      3                               band_gap=(0.5, 0.75),
      4                               fields=["material_id", "formula_pretty",
      5                                       "band_gap"])
      7 example_doc = docs[0]

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/mp_api/client/mprester.py:192, in MPRester.__init__(self, api_key, endpoint, notify_db_version, include_user_agent, monty_decode, use_document_model, session, headers)
    189     warnings.warn(f"Problem loading MPContribs client: {error}")
    191 # Check if emmet version of server os compatible
--> 192 emmet_version = version.parse(self.get_emmet_version())
    194 if version.parse(emmet_version.base_version) < version.parse(
    195     _MAPI_SETTINGS.MIN_EMMET_VERSION
    196 ):
    197     warnings.warn(
    198         "The installed version of the mp-api client may not be compatible with the API server. "
    199         "Please install a previous version if any problems occur."
    200     )

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/mp_api/client/mprester.py:340, in MPRester.get_emmet_version(self)
    333 def get_emmet_version(self):
    334     """
    335     Get the latest version emmet-core and emmet-api used in the
    336     current API service.
    337 
    338     Returns: version as a string
    339     """
--> 340     return get(url=self.endpoint + "heartbeat").json()["version"]

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/requests/api.py:73, in get(url, params, **kwargs)
     62 def get(url, params=None, **kwargs):
     63     r"""Sends a GET request.
     64 
     65     :param url: URL for the new :class:`Request` object.
   (...)
     70     :rtype: requests.Response
     71     """
---> 73     return request("get", url, params=params, **kwargs)

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/requests/api.py:59, in request(method, url, **kwargs)
     55 # By using the 'with' statement we are sure the session is closed, thus we
     56 # avoid leaving sockets open which can trigger a ResourceWarning in some
     57 # cases, and look like a memory leak in others.
     58 with sessions.Session() as session:
---> 59     return session.request(method=method, url=url, **kwargs)

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/requests/sessions.py:587, in Session.request(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)
    582 send_kwargs = {
    583     "timeout": timeout,
    584     "allow_redirects": allow_redirects,
    585 }
    586 send_kwargs.update(settings)
--> 587 resp = self.send(prep, **send_kwargs)
    589 return resp

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/requests/sessions.py:701, in Session.send(self, request, **kwargs)
    698 start = preferred_clock()
    700 # Send the request
--> 701 r = adapter.send(request, **kwargs)
    703 # Total elapsed time of the request (approximately)
    704 elapsed = preferred_clock() - start

File /media/colin/Shared/colin/git/materials-ml-workshop/env/lib/python3.10/site-packages/requests/adapters.py:501, in HTTPAdapter.send(self, request, stream, timeout, verify, cert, proxies)
    486     resp = conn.urlopen(
    487         method=request.method,
    488         url=url,
   (...)
    497         chunked=chunked,
    498     )
    500 except (ProtocolError, OSError) as err:
--> 501     raise ConnectionError(err, request=request)
    503 except MaxRetryError as e:
    504     if isinstance(e.reason, ConnectTimeoutError):
    505         # TODO: Remove this in 3.0.0: see #2811

ConnectionError: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))

To see what our search turned up, we can use some simple code, like this. We first find out how many hits our query returned using len(docs), and then we print only the first N hits, where we set N = 10.

N = 10
print('Our query returned {0} docs.'.format( len(docs) ))
print(f'Printing only the first {N} results:')

for idx in range(0,N):
    mat_doc = docs[idx]
    print('Item {0}: MPID = {1} ({2}), band gap = {3:6.4f} eV'.format(idx,
                                             mat_doc.material_id,
                                             mat_doc.formula_pretty,
                                             mat_doc.band_gap))

Exercises#

Exercise 1: Obtain the electronic density of states (DOS) for YBa2Cu3O7. Plot it using pymatgen.

Hints:

  1. To find the code to obtain the DOS, a Google search such as “MPRester DOS example” may help, or perhaps you can try asking a chatbot.

  2. Once you have obtained a DOS and saved it as, say, some_DOS, you can plot it using code such as this:

from pymatgen.electronic_structure.plotter import DosPlotter
import matplotlib.pyplot as plt

with MPRester(MP_API_KEY) as mpr:
    some_DOS = <your code to get the DOS>

# obtain a DosPlotter object
Plotter =  DosPlotter()

# add the DOS to the plotter
Plotter.add_dos('DOS', some_DOS)

"""
   Choose appropriate numbers for:

       E_lo and E_hi, the upper and lower limits
           of the domain for your DOS plot.

       MaxDensity, the upper limit for the range of
           your DOS plot.

   This may require some trial and error!
"""
Plotter.get_plot(xlim=(E_lo, E_hi), ylim=(0, MaxDensity))
plt.show()

Solutions#

Exercise 1: YBCO DOS#

Hide code cell content
from mp_api.client import MPRester # client for Materials Project
from pymatgen.electronic_structure.plotter import DosPlotter
import matplotlib.pyplot as plt

YBCO = 'mp-20674' # Materials Project ID number

with MPRester(MP_API_KEY) as mpr:
    YBCO_DOS = mpr.get_dos_by_material_id(YBCO)

print(YBCO_DOS)

# plot & show DOS we obtained
Plotter =  DosPlotter()

Plotter.add_dos('DOS', YBCO_DOS)

Plotter.get_plot(xlim=(-10, 10), ylim=(0, 30))
plt.show()