Commit 78226845 authored by VIGNESHinZONE's avatar VIGNESHinZONE
Browse files

Update using the new molnet api and proper linting

parent fc74340d
Loading
Loading
Loading
Loading
+286 −296
Original line number Diff line number Diff line
import numpy as np
import os
import json
import pandas as pd
from typing import Any, Iterator, List, Optional, Tuple, Union, cast, IO
from deepchem.feat import Featurizer

from collections import defaultdict
from pymatgen import Element, Structure, Molecule, Lattice
from pymatgen.symmetry.analyzer import PointGroupAnalyzer
import networkx as nx
import networkx.algorithms.isomorphism as iso
from scipy.spatial.distance import cdist, pdist, squareform
from deepchem.utils.data_utils import download_url, get_data_dir


class LCNNFeaturizer(Featurizer):
@@ -25,7 +19,6 @@ class LCNNFeaturizer(Featurizer):
  is manner in which , First element is the node itself followed by a randomly
  selected neighboring site. The next site shares a surface Pt atom with the previous
  site. And they are picked consecutively.

  First the template of the Primitive cell needs to be defined and then Each
  structure(Data Point or diffrent condifuration of adsorbate atoms) is passed
  for featurization.
@@ -36,12 +29,11 @@ class LCNNFeaturizer(Featurizer):
  
  References
  ----------
    .. [1] Jonathan Lym and Geun Ho Gu, J. Phys. Chem. C 2019, 123, 1895118959
  [1] Jonathan Lym and Geun Ho Gu, J. Phys. Chem. C 2019, 123, 1895118959
  
  Examples
  ----------
      
    
  The input format for primitive cell Template is stored in a file named
  
  [comment]
@@ -53,18 +45,13 @@ class LCNNFeaturizer(Featurizer):
  [number sites]
  [site1a][site1b][site1c][site type]
  [site2a][site2b][site2c][site type]
    ...
    [number of data]
    [datum 1 name]
    ...
  
  - ax,ay, ... are cell basis vector
  - pbc is either T or F indication of the periodic boundary condition
  - os# is the name of the possible occupation state (interpretted as string)
  - site1a,site1b,site1c are the scaled coordinates of site 1
  - site type can be either S1, S2, ... or A1, A2,... indicating spectator 
        site and itx index and active site and its index respectively.
    
  ...
  Example:
  #Primitive Cell 
  2.81859800e+00  0.00000000e+00  0.00000000e+00 T
@@ -79,13 +66,10 @@ class LCNNFeaturizer(Featurizer):
  0.00000000e+00  0.00000000e+00  3.58978557e-01 S1
  6.66666666e-01  3.33333333e-01  4.49958662e-01 S1
  3.33333333e-01  6.66666666e-01  5.01129144e-01 A1
    653
    structure000
    structure001
    ...

    The input format for a data point Structure (Configuration of Atoms):

  The input format for a data point Structure (Configuration of Atoms):
  ...
  [ax][ay][az]
  [bx][by][bz]
  [cx][cy][cz]
@@ -93,9 +77,8 @@ class LCNNFeaturizer(Featurizer):
  [site1a][site1b][site1c][site type][occupation state if active site]
  [site2a][site2b][site2c][site type][occupation state if active site]
  ...  
    
  - property value indicates the trained value. It must start with #y=...
    
  ...
  Example:
  #y=-1.209352
  2.81859800e+00  0.00000000e+00  0.00000000e+00
@@ -108,23 +91,18 @@ class LCNNFeaturizer(Featurizer):
  0.000000000000  0.000000000000  0.361755713893 S1
  0.500000499894  0.622008360788  0.454395429618 S1
  0.000000000000  0.666667212896  0.502346789304 A1 1
     


  ...
  Python Script:

  ...
  >>> template_file_path = os.join.path(data_dir , "input.in")
  >>> Featurizer =  np.around(6.00,2)
  >>> Data_point_path = "Structure1.txt" 
  >>> Data_point_text = open(Data_point_path).read()
  >>> graph_ob = Featurizer._featurize(Data_point_text)
  >>> print(graph_ob)
    
    

  """

  def __init__(self, cutoff, input_file_path=None):
  def __init__(self, cutoff, template=None):
    """
    Parameters
    ----------
@@ -134,7 +112,7 @@ class LCNNFeaturizer(Featurizer):
    input_file_path: Template primitive stucture file path
    """
    self.cutoff = np.around(cutoff, 2)
    self.setup_env = SiteEnvironments.Load(open(input_file_path).read(), cutoff)
    self.setup_env = SiteEnvironments.Load(template, cutoff)

  def _featurize(self, structure):
    """
@@ -148,14 +126,13 @@ class LCNNFeaturizer(Featurizer):
    obj.X_NSs: All edges for each node in diffrent permutations. Node 1 consist of
            6 diffrent permutation , each consisting of neighbors. 
    """

    xSites, xNSs = self.setup_env.ReadDatum(structure)

    return {"X_Sites": np.array(xSites), "X_NSs": np.array(xNSs)}


def InputReader(text, template=False):
  """Read Input Files
  """
  Read Input Files

  Parameters
  ----------
@@ -215,7 +192,8 @@ def InputReader(text, template=False):
class SiteEnvironment(object):
  def __init__(self, pos, sitetypes, env2config, permutations, cutoff,\
               Grtol=0.0, Gatol=0.01, rtol=0.01, atol=0.0, tol=0.01, grtol=0.01):
    """ Initialize site environment
    """ 
    Initialize site environment

    This class contains local site enrivonment information. This is used
    to find neighborlist in the datum (see GetMapping).
@@ -278,7 +256,8 @@ class SiteEnvironment(object):
    self._em = iso.numerical_edge_match('d', 0, rtol, 0)

  def _ConstructGraph(self, pos, sitetypes):
    """Returns local environment graph using networkx and
    """
    Returns local environment graph using networkx and
    tolerance specified.

    parameters
@@ -321,21 +300,24 @@ class SiteEnvironment(object):
    return s

  def __eq__(self, o):
    """Local environment comparison is done by comparing represented site
    """
    Local environment comparison is done by comparing represented site
    """
    if not isinstance(o, SiteEnvironment):
      raise ValueError
    return self.sitetypes[0] == o.sitetypes[0]

  def __ne__(self, o):
    """Local environment comparison is done by comparing represented site
    """
    Local environment comparison is done by comparing represented site
    """
    if isinstance(o, SiteEnvironment):
      raise ValueError
    return not self.__eq__(o)

  def GetMapping(self, env, path=None):
    """Returns mapping of sites from input to this object
    """
    Returns mapping of sites from input to this object

    Pymatgen molecule_matcher does not work unfortunately as it needs to be
    a reasonably physical molecule.
@@ -400,7 +382,8 @@ class SiteEnvironment(object):
      raise ValueError(s)

  def _kabsch(self, P, Q):
    """Returns rotation matrix to align coordinates using
    """
    Returns rotation matrix to align coordinates using
    Kabsch algorithm. 
    """
    C = np.dot(np.transpose(P), Q)
@@ -416,8 +399,8 @@ class SiteEnvironment(object):
class SiteEnvironments(object):

  def __init__(self, site_envs, ns, na, aos, eigen_tol, pbc, cutoff):
    """Initialize
        
    """
    Initialize
    Use Load to intialize this class.

    Parameters
@@ -447,12 +430,14 @@ class SiteEnvironments(object):
    return s

  def __getitem__(self, el):
    """Returns a site environment
    """
    Returns a site environment
    """
    return self.site_envs[el]

  def ReadDatum(self, text, cutoff_factor=1.1):
    """Load structure data and return neighbor information
    """
    Load structure data and return neighbor information

    Parameters
    ----------
@@ -482,7 +467,7 @@ class SiteEnvironments(object):
        alltoactive[i] = n
        n += 1
    # Get Neighbors
    ## Read Data
    # Read Data
    site_envs = self._GetSiteEnvironments(
        coord,
        cell,
@@ -513,7 +498,8 @@ class SiteEnvironments(object):

  @classmethod
  def _truncate(cls, env_ref, env):
    """When cutoff_factor is used, it will pool more site than cutoff factor specifies.
    """
    When cutoff_factor is used, it will pool more site than cutoff factor specifies.
    This will rule out nonrelevant sites by distance.
    """
    # Extract the right number of sites by distance
@@ -540,7 +526,8 @@ class SiteEnvironments(object):

  @classmethod
  def Load(cls, path, cutoff, eigen_tol=1e-5):
    """Load Primitive cell and return SiteEnvironments
    """
    Load Primitive cell and return SiteEnvironments

    Parameters
    ----------
@@ -573,7 +560,8 @@ class SiteEnvironments(object):
                           pbc,
                           get_permutations=True,
                           eigen_tol=1e-5):
    """Extract local environments from primitive cell
    """
    Extract local environments from primitive cell

    Parameters
    ----------
@@ -668,7 +656,9 @@ class SiteEnvironments(object):
    return site_envs


def _chunks(l, n):
  """Yield successive n-sized chunks from l."""
  for i in range(0, len(l), n):
    yield l[i:i + n]
def _chunks(length, number):
  """
  Yield successive n-sized chunks from length.
  """
  for i in range(0, len(length), number):
    yield length[i:i + number]
+107 −187
Original line number Diff line number Diff line
"""
Platinum Adsorbtion structure for N and NO along with their formation energies
"""
import os
import logging
import deepchem
from deepchem.feat import Featurizer
from deepchem.splits.splitters import Splitter
from deepchem.molnet.defaults import get_defaults
import numpy as np
import os
import deepchem as dc
from deepchem.molnet.load_function.molnet_loader import TransformerGenerator, _MolnetLoader
from deepchem.feat.material_featurizers.lcnn_featurizer import LCNNFeaturizer
from deepchem.data import Dataset
from typing import List, Optional, Tuple, Union

from typing import List, Tuple, Dict, Optional, Any

logger = logging.getLogger(__name__)

DEFAULT_DIR = deepchem.utils.data_utils.get_data_dir()
PLATINUM_URL = "https://deepchemdata.s3-us-west-1.amazonaws.com/datasets/platinum_adsorption.tar.gz"

# dict of accepted featurizers for this dataset
# modify the returned dicts for your dataset
DEFAULT_FEATURIZERS = get_defaults("feat")

# Names of supported featurizers
featurizers = ['LCNNFeaturizer']
DEFAULT_FEATURIZERS = {k: DEFAULT_FEATURIZERS[k] for k in featurizers}

# dict of accepted transformers
DEFAULT_TRANSFORMERS = get_defaults("trans")

# dict of accepted splitters
DEFAULT_SPLITTERS = get_defaults("splits")

# names of supported splitters
mydataset_splitters = ['RandomSplitter']
DEFAULT_SPLITTERS = {k: DEFAULT_SPLITTERS[k] for k in mydataset_splitters}
PLATINUM_TASKS = ["Formation Energy"]
PRIMITIVE_CELL_TEMPLATE = """#Primitive Cell
2.81852800e+00  0.00000000e+00  0.00000000e+00 T
-1.40926400e+00  2.44091700e+00  0.00000000e+00 T
0.00000000e+00  0.00000000e+00  2.55082550e+01 F
1 1
1 0 2
6
0.666670000000  0.333330000000  0.090220999986 S1
0.333330000000  0.666670000000  0.180439359180 S1
0.000000000000  0.000000000000  0.270657718374 S1
0.666670000000  0.333330000000  0.360876077568 S1
0.333330000000  0.666670000000  0.451094436762 S1
0.000000000000  0.000000000000  0.496569911270 A1"""


class _PtAdsorptionLoader(_MolnetLoader):

  def create_dataset(self) -> Dataset:
    dataset_file = os.path.join(self.data_dir, 'Platinum_Adsorption.json')
    if not os.path.exists(dataset_file):
      dc.utils.data_utils.download_url(url=PLATINUM_URL, dest_dir=self.data_dir)
      dc.utils.data_utils.untargz_file(
          os.path.join(self.data_dir, 'platinum_adsorption.tar.gz'),
          self.data_dir)
    loader = dc.data.JsonLoader(
        tasks=PLATINUM_TASKS,
        feature_field="Structures",
        label_field="Formation Energy",
        featurizer=self.featurizer,
        **self.args)
    return loader.create_dataset(dataset_file)


def load_Platinum_Adsorption(featurizer=DEFAULT_FEATURIZERS['LCNNFeaturizer'],
                             transformers: List = [],
                             splitter=DEFAULT_SPLITTERS['RandomSplitter'],
def load_Platinum_Adsorption(
    featurizer: Union[dc.feat.Featurizer, str] = LCNNFeaturizer(
        np.around(6.00), PRIMITIVE_CELL_TEMPLATE),
    splitter: Union[dc.splits.Splitter, str, None] = 'random',
    transformers: List[Union[TransformerGenerator, str]] = [],
    reload: bool = True,
    data_dir: Optional[str] = None,
    save_dir: Optional[str] = None,
                             featurizer_kwargs: Dict[str, object] = {},
                             splitter_kwargs: Dict[str, Any] = {
                                 'frac_train': 0.8,
                                 'frac_valid': 0.1,
                                 'frac_test': 0.1
                             },
                             transformer_kwargs: Dict[str, Any] = {},
                             **kwargs) -> Tuple[List, Optional[Tuple], List]:
  """Load mydataset.
    **kwargs
) -> Tuple[List[str], Tuple[Dataset, ...], List[dc.trans.Transformer]]:
  """
    Load mydataset.
    Contains 
    Parameters
    ----------
@@ -102,94 +108,8 @@ def load_Platinum_Adsorption(featurizer=DEFAULT_FEATURIZERS['LCNNFeaturizer'],
        save_dir=data_path,
        featurizer_kwargs=feat_args)
    >> train_dataset, val_dataset, test_dataset = datasets

    """

  # Featurize mydataset
  logger.info("About to featurize Platinum Adsorption dataset.")
  my_tasks = ["Formation Energy"]  # machine learning targets

  # Get DeepChem data directory if needed
  if data_dir is None:
    data_dir = DEFAULT_DIR
  if save_dir is None:
    save_dir = DEFAULT_DIR

  if 'cutoff' not in featurizer_kwargs:
    raise TypeError("cutoff argument needs to be given")
  if 'input_file_path' not in featurizer_kwargs:
    raise TypeError("input_file_path argument needs to be given")

  #Download the data if does'nt exist
  dataset_file = os.path.join(data_dir, 'Platinum_Adsorption.json')
  if not os.path.exists(dataset_file):

    deepchem.utils.data_utils.download_url(url=PLATINUM_URL, dest_dir=data_dir)
    deepchem.utils.data_utils.untargz_file(
        os.path.join(data_dir, 'platinum_adsorption.tar.gz'), data_dir)

  # Check for str args to featurizer and splitter
  if issubclass(featurizer, Featurizer):
    featurizer = featurizer(**featurizer_kwargs)
  else:
    raise TypeError("featurizer must be a subclass of Featurizer.")

  if issubclass(splitter, Splitter):
    splitter = splitter()
  else:
    raise TypeError("splitter must be a subclass of Splitter.")

  # Reload from disk
  if reload:
    featurizer_name = str(featurizer.__class__.__name__)
    splitter_name = str(splitter.__class__.__name__)
    save_folder = os.path.join(save_dir, "Platinum_dataset", featurizer_name,
                               splitter_name)

    loaded, all_dataset, transformers = deepchem.utils.data_utils.load_dataset_from_disk(
        save_folder)
    if loaded:
      return my_tasks, all_dataset, transformers

  # First type of supported featurizers
  supported_featurizers: List[str] = ['LCNNFeaturizer'
                                     ]  # type: List[Featurizer]

  # If featurizer requires a non-CSV file format, load .tar.gz file
  if featurizer.__class__.__name__ in supported_featurizers:
    dataset_file = os.path.join(data_dir, 'Platinum_Adsorption.json')

    # Changer loader to match featurizer and data file type
    loader = deepchem.data.JsonLoader(
        tasks=my_tasks,
        feature_field="Structures",
        label_field="Formation Energy",
        featurizer=featurizer)

  else:
    raise TypeError("Wrong format of featurizers")

  # Featurize dataset
  dataset = loader.create_dataset(dataset_file)

  train_dataset, valid_dataset, test_dataset = splitter.train_valid_test_split(
      dataset, **splitter_kwargs)

  # Initialize transformers
  transformers = [
      DEFAULT_TRANSFORMERS[t](dataset=dataset, **transformer_kwargs[t])
      if isinstance(t, str) else t(
          dataset=dataset, **transformer_kwargs[str(t.__class__.__name__)])
      for t in transformers
  ]

  for transformer in transformers:
    train_dataset = transformer.transform(train_dataset)
    valid_dataset = transformer.transform(valid_dataset)
    test_dataset = transformer.transform(test_dataset)

  if reload:  # save to disk
    deepchem.utils.data_utils.save_dataset_to_disk(
        save_folder, train_dataset, valid_dataset, test_dataset, transformers)

  return my_tasks, (train_dataset, valid_dataset, test_dataset), transformers
  loader = _PtAdsorptionLoader(featurizer, splitter, transformers,
                               PLATINUM_TASKS, data_dir, save_dir, **kwargs)
  return loader.load_dataset('LCNN_feat', reload)
+4 −16
Original line number Diff line number Diff line
import os
import numpy as np
from deepchem.molnet import load_Platinum_Adsorption


def test_Platinum_Adsorption_loader():

  current_dir = os.path.dirname(os.path.abspath(__file__))
  feat_args = {
      "cutoff": np.around(6.00, 2),
      "input_file_path": os.path.join(current_dir, 'input.in')
  }

  kwargs = {"log_every_n": 100}
  tasks, datasets, transformers = load_Platinum_Adsorption(
      reload=False,
      data_dir=current_dir,
      featurizer_kwargs=feat_args,
      splitter_kwargs={
          'seed': 42,
          'frac_train': 0.5,
          'frac_valid': 0.3,
          'frac_test': 0.2
      })

      reload=False, data_dir=current_dir, save_dir=current_dir, **kwargs)
  assert tasks[0] == "Formation Energy"
  assert datasets[0].X[0]['X_Sites'].shape[1] == 3
  assert datasets[0].X[0]['X_NSs'].shape[3] == 19
@@ -37,3 +23,5 @@ def test_Platinum_Adsorption_loader():

  if os.path.exists(os.path.join(current_dir, 'platinum_adsorption.tar.gz')):
    os.remove(os.path.join(current_dir, 'platinum_adsorption.tar.gz'))