Preparations

Import requests library for http request and define API endpoints

In [1]:
import requests
import pprint
import sys
import ase.io
try:# catch module change from Python2->3
    import io
except:
    import StringIO as io


API = 'http://api.catalysis-hub.org'

SEARCH_ENDPOINT = API + '/apps/prototypeSearch/facet_search/'
PROTOTYPE_ENDPOINT = API + '/apps/prototypeSearch/prototype/'
STRUCTURE_ENDPOINT = API + '/apps/prototypeSearch/get_structure/'

The prototype App uses 3 API endpoints for searching and retrieving structures. Below we go through a practical example of how to use them together. The request is a very user friendly module to make HTTP requests from python. If you don't have it installed, you can change that with pip install requests --user

Let's make use of the facet_search API to find all materials with a given composition

In [2]:
r = requests.post(SEARCH_ENDPOINT, json={
    "search_terms": "stoichiometry:AB2",
    "limit": 1000,
})
In [3]:
len(r.json()['prototypes'])
Out[3]:
462

We can learn about other possible arguments by inspecting the 'input' field of the result

In [4]:
r.json()['input']
Out[4]:
{'facet_filters': [],
 'limit': 1000,
 'offset': 0,
 'search_terms': ['stoichiometry:AB2']}

To see how many structures of this composition are in each repository, we look at the repositories facet.

In [5]:
r.json()['repositories']
Out[5]:
[['AFLOW', 50442],
 ['COD', 2888],
 ['OQMD', 533],
 ['MaterialsProject', 477],
 ['AMCSD', 66]]

The facet lists are ordered by frequency by default. There are of course all the other facets, that are also in the GUI.

In [6]:
r.json().keys()
Out[6]:
dict_keys(['input', 'n_atoms', 'n_compounds', 'n_prototypes', 'n_species', 'n_wyckoffs', 'prototypes', 'repositories', 'spacegroups', 'stoichiometries', 'time'])

Filter

To narrow down the result, we look, e.g. only at the AB2 structures in OQMD

In [7]:
r = requests.post(SEARCH_ENDPOINT, json={
    "search_terms": "stoichiometry:AB2 repository:OQMD",
    "limit": 1000,
})
In [8]:
r.json()
Out[8]:
{'input': {'facet_filters': [],
  'limit': 1000,
  'offset': 0,
  'search_terms': ['stoichiometry:AB2', 'repository:OQMD']},
 'n_atoms': [[3, 533]],
 'n_compounds': 533,
 'n_prototypes': 533,
 'n_species': [[2, 533]],
 'n_wyckoffs': [[2, 519], [3, 14]],
 'prototypes': [['AB2_a_e_139', 111],
  ['AB2_a_d_191', 105],
  ['AB2_a_c_225', 97],
  ['AB2_a_d_164', 68],
  ['AB2_a_i_12', 44],
  ['AB2_a_c_166', 32],
  ['AB2_a_i_69', 9],
  ['AB2_a_j_65', 8],
  ['AB2_a_a2_160', 8],
  ['AB2_a_i_71', 8],
  ['AB2_a_k_21', 6],
  ['AB2_a_c_42', 5],
  ['AB2_a_d_139', 5],
  ['AB2_a_e_123', 4],
  ['AB2_a_h_187', 3],
  ['AB2_a_h_123', 3],
  ['AB2_a_bc_216', 2],
  ['AB2_a_c_5', 2],
  ['AB2_a_g_115', 2],
  ['AB2_a_c_38', 1],
  ['AB2_a_a2_8', 1],
  ['AB2_a_e_191', 1],
  ['AB2_a_ab_38', 1],
  ['AB2_a_i_65', 1],
  ['AB2_a_e_38', 1],
  ['AB2_a_m_10', 1],
  ['AB2_a_bc_156', 1],
  ['AB2_a_j_71', 1],
  ['AB2_a_a2_1', 1],
  ['AB2_a_n_10', 1]],
 'repositories': [['OQMD', 533]],
 'spacegroups': [[139, 116],
  [191, 106],
  [225, 97],
  [164, 68],
  [12, 44],
  [166, 32],
  [71, 9],
  [65, 9],
  [69, 9],
  [160, 8],
  [123, 7],
  [21, 6],
  [42, 5],
  [38, 3],
  [187, 3],
  [216, 2],
  [115, 2],
  [5, 2],
  [10, 2],
  [156, 1],
  [1, 1],
  [8, 1]],
 'stoichiometries': [['AB2', 533]],
 'time': 1.216792106628418}

Prototypes

Some prototypes are apparently more frequent than others. So let's have a look at the structures in the AB2_a_d_191 prototype. To this end we use the prototype API.

In [9]:
r = requests.post(PROTOTYPE_ENDPOINT, json={
    "prototype": "AB2_a_d_191",
    "search_terms": "repository:OQMD"
})
In [10]:
len(r.json()['prototypes'])
Out[10]:
105

Structures

So, let's say we want to do some specific manipulation on structures. To this end it will be handy to turn it into ASE atoms objects.

In [11]:
structures = []
for prototype in r.json()['prototypes'][:10]:
    sys.stdout.write('.')
    r_structure = requests.post(STRUCTURE_ENDPOINT, json=prototype)
    cif = r_structure.json()['structure']
    with io.StringIO() as cif_file:
        cif_file.write(cif)
        cif_file.seek(0)
        structures.append(
            ase.io.read(cif_file, format='cif')
        )
    
..........
In [12]:
structures
Out[12]:
[Atoms(symbols='B2Mg', pbc=True, cell=[[3.8347, 0.0, 0.0], [-1.9173499999999992, 3.320947615892188, 0.0], [0.0, 0.0, 3.50909]]),
 Atoms(symbols='Bi2Tl', pbc=True, cell=[[7.10897, 0.0, 0.0], [-3.5544849999999983, 6.156548614741462, 0.0], [0.0, 0.0, 3.38233]]),
 Atoms(symbols='B2W', pbc=True, cell=[[3.78488, 0.0, 0.0], [-1.892439999999999, 3.2778022302756464, 0.0], [0.0, 0.0, 3.35748]]),
 Atoms(symbols='EuHg2', pbc=True, cell=[[6.26501, 0.0, 0.0], [-3.1325049999999988, 5.4256578149635475, 0.0], [0.0, 0.0, 3.58463]]),
 Atoms(symbols='CaHg2', pbc=True, cell=[[6.19862, 0.0, 0.0], [-3.0993149999999985, 5.368171048660336, 0.0], [0.0, 0.0, 3.54152]]),
 Atoms(symbols='B2V', pbc=True, cell=[[3.73867, 0.0, 0.0], [-1.869329999999999, 3.23777453611273, 0.0], [0.0, 0.0, 3.03155]]),
 Atoms(symbols='B2V', pbc=True, cell=[[3.74283, 0.0, 0.0], [-1.8714099999999991, 3.2413772017924734, 0.0], [0.0, 0.0, 3.01813]]),
 Atoms(symbols='TiU2', pbc=True, cell=[[5.95252, 0.0, 0.0], [-2.9762599999999986, 5.155033536534948, 0.0], [0.0, 0.0, 2.80189]]),
 Atoms(symbols='Au2Ba', pbc=True, cell=[[6.05807, 0.0, 0.0], [-3.0290349999999986, 5.246442517904395, 0.0], [0.0, 0.0, 4.18078]]),
 Atoms(symbols='Hg2Y', pbc=True, cell=[[6.10075, 0.0, 0.0], [-3.0503799999999988, 5.283413142391953, 0.0], [0.0, 0.0, 3.47105]])]

Voila!

Ok, should be admitted, that doing n HTTP round trips for n structures is not ideal. We are working on that.