5
$\begingroup$

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:
        f.write(f"{line.material_id}\n")

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)
            try:
                dim = mpd.condensed_structure.dimensionality
            except:    
                continue

            if dim != None and dim == 2:
                f.write(f"{mpid}\n")

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?

$\endgroup$

1 Answer 1

3
$\begingroup$

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:
          f.write(f"{line.material_id}\n")

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)
      try:
          dim = mpd.condensed_structure.dimensionality
          two_dim_materials.append(mpid)
      except:    
          continue
  return two_dim_materials

def get_current_db_ids(current_material_infos):
  current_db_ids = []
  for info in current_material_infos:
    current_db_ids.append(info.material_id)
  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.

$\endgroup$

You must log in to answer this question.

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