class_docstr: This featurizer represents each sample as an AtomicConformation object,
  representing a 3D arrangement of atoms.
  
  It expects each datapoint to be a string, which may be either a filename or a
  SMILES string.  It is processed as follows.
  
  If the string ends in .pdb, .sdf, or .mol2, it is assumed to be a file in the
  corresponding format.  The positions and elements of all atoms contained in
  the file are loaded.  RDKit is used to compute formal and partial charges.
  
  Otherwise, it is assumed to be a SMILES string.  RDKit is used to generate a
  3D conformation and to compute formal and partial charges.
  
  Examples
  --------
  >>> import deepchem as dc
  >>> smiles = ['CCC']
  >>> featurizer = dc.feat.AtomicConformationFeaturizer()
  >>> features = featurizer.featurize(smiles)
  >>> features[0].num_atoms
  11
  >>> sum(features[0].atomic_number == 6)
  3
  >>> sum(features[0].atomic_number == 1)
  8
  >>> type(features[0].formal_charge)
  <class 'numpy.ndarray'>
  >>> features[0].formal_charge.shape
  (11,)
  >>> type(features[0].partial_charge)
  <class 'numpy.ndarray'>
  >>> features[0].partial_charge.shape
  (11,)
docstr: Calculate features for a single datapoint.
  
  Parameters
  ----------
  datapoint: str
      This is expected to be either a filename or a SMILES string.
docstr_tok: ["Calculate","features","for","a","single","datapoint",".","Parameters","--","--","--","--","--","datapoint",":","str","This","is","expected","to","be","either","a","filename","or","a","SMILES","string","."]
code: def _featurize(self, datapoint: str, **kwargs) -> AtomicConformation:
      """Calculate features for a single datapoint.
  
      Parameters
      ----------
      datapoint: str
          This is expected to be either a filename or a SMILES string.
      """
      from rdkit import Chem
      from rdkit.Chem import AllChem
  
      if datapoint.endswith(".pdb"):
          mols = [Chem.MolFromPDBFile(datapoint, removeHs=False)]
      elif datapoint.endswith(".sdf"):
          supplier = Chem.SDMolSupplier(datapoint, removeHs=False)
          mols = [mol for mol in supplier]
      elif datapoint.endswith(".mol2"):
          mols = [Chem.MolFromMol2File(datapoint, removeHs=False)]
      else:
          mol = Chem.MolFromSmiles(datapoint)
          # SMILES is unique, so set a canonical order of atoms
          new_order = Chem.rdmolfiles.CanonicalRankAtoms(mol)
          mol = Chem.rdmolops.RenumberAtoms(mol, new_order)
          # Add hydrogens and generate a conformation.
          mol = Chem.AddHs(mol)
          AllChem.EmbedMolecule(mol, AllChem.ETKDGv3())
          mols = [mol]
  
      # Record properties of the molecules.
  
      positions = []
      properties = []
      for mol in mols:
          positions.append(mol.GetConformer(0).GetPositions())
          AllChem.ComputeGasteigerCharges(mol)
          for atom in mol.GetAtoms():
              atomic_num = atom.GetAtomicNum()
              formal_charge = atom.GetFormalCharge()
              partial_charge = get_partial_charge(atom)
              properties.append(
                  [atomic_num, formal_charge, partial_charge]
              )
  
      # Create the output object.
  
      names = ["atomic number", "formal charge", "partial charge"]
      return AtomicConformation(
          np.concatenate(positions).astype(np.float32),
          np.array(properties, dtype=np.float32),
          names,
      )
  
file_path: deepchem/deepchem/feat/atomic_conformation.py
imports: import numpy
  from deepchem.feat.base_classes import Featurizer
  from deepchem.utils import get_partial_charge
  from typing import Sequence
label_desc: Use image node_id 1 for calling the AtomicConformationFeaturizer obj's underlying member method code with example usage: obj._featurize(datapoint) and returns: AtomicConformation