I would like to use the materials project API to search materials with some properties but to restrict my search only to two-dimensional materials.

How to do it?

Web-pages for materials contain the 'Dimensionality' field in the 'Crystal Structure' section

enter image description here

From the API page, I found that the dimensionality can be obtained from RobocrystallogapherDoc that is accessed with the robocrys object but whatever I tried to do with MPRester.robocrys.search, I got errors.

How to use it? Where to get information? I searched on the API page, the MP docs page, MP Workshop, another MP docs, Robocrystallographer github, Robocrystallographer paper - they all contain very little info on how to use the materials project API, and especially Robocrystallographer.

The only thing I got working for Robocrystallographer is querying a material given its materials project ID: robocrys.get_data_by_id.

Therefore, I first downloaded IDs for all materials into a text file (154718 materials on 23 April, 2023):

from mp_api.client import MPRester

with MPRester(api_key=api_key) as mpr:
    ids = mpr.summary.search(fields=["material_id"])

with open('mp_ids.txt', 'w') as f:
    for line in ids:

This took a few seconds on GPU.

Then, I looped through this text file, used robocrys.get_data_by_id to get only those IDs that Robocrystallographer identifies as 2D materials, and saved them in another text file:

from mp_api.client import MPRester

with open('mp_ids.txt', 'r') as f:
    mpids = [line.rstrip('\n') for line in f.readlines()]

with open('mp_2dids.txt', 'w') as f:
    with MPRester(api_key=api_key) as mpr:
        for mpid in mpids:
            mpd = mpr.robocrys.get_data_by_id(mpid)
                dim = mpd.condensed_structure.dimensionality

            if dim != None and dim == 2:

This took 14 hours on GPU (8967 2D materials on 23 April, 2023).

Is there a 'more civilized' way to do it, without downloading all IDs to text files, and redoing this every time they add new materials to the materials project database?


1 Answer 1


To avoid running through all the ids every time a new material is added you can use your text file where you have saved the ids already.

I have written helper functions that you can use to achieve this.

Helper functions:

from mp_api.client import MPRester

def get_all_material_infos_from_db(mpr):
  current_material_infos = mpr.summary.search(fields=["material_id"])
  return current_material_infos

def write_ids_to_file(id_info_filepath, ids):
  with open(id_info_filepath, 'w') as f:
      for line in ids:

def get_locally_existing_ids(id_info_filepath):
  with open(id_info_filepath, 'r') as f:
      mpids = sorted([line.rstrip('\n') for line in f.readlines()])
  return mpids

def pick_newly_added_ids(locally_existing_ids, current_db_ids):  
  newly_added_ids = list(set(current_db_ids) - set(locally_existing_ids))
  return newly_added_ids

def get_2d_materials_only(newly_added_ids,mpr):
  two_dim_materials = []
  for mpid in newly_added_ids:
      mpd = mpr.robocrys.get_data_by_id(mpid)
          dim = mpd.condensed_structure.dimensionality
  return two_dim_materials

def get_current_db_ids(current_material_infos):
  current_db_ids = []
  for info in current_material_infos:
  return current_db_ids

Main code:

id_info_filepath = 'mp_ids.txt'
mpr = MPRester(api_key=api_key)
current_material_infos = get_all_material_infos_from_db(mpr)
current_db_ids = get_current_db_ids(current_material_infos)
locally_existing_ids = get_locally_existing_ids(id_info_filepath)

newly_added_ids = pick_newly_added_ids(locally_existing_ids, current_db_ids)
newly_added_two_dim_materials = get_2d_materials_only(newly_added_ids,mpr)

You can then save only the newly added 2d materials to your: 'mp_2dids.txt'. This should save you some time as you are looping through only the newly added ids. Hope that helps.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .