class_docstr: Localize Pi stacking interactions between atoms in macromolecular complexes.
  
  Given a macromolecular complex made up of multiple
  constitutent molecules, compute pi-stacking interactions
  between atoms in the macromolecular complex. For each atom,
  localize this salt bridge in the voxel in which it originated
  to create a local pi-stacking array.
  
  Let `voxels_per_edge = int(box_width/voxel_width)`.  Creates a
  tensor output of shape `(voxels_per_edge, voxels_per_edge,
  voxels_per_edge, 2)` for each macromolecular complex. Each voxel has
  2 fields, with the first tracking the number of pi-pi parallel
  interactions, and the second tracking the number of pi-T
  interactions.
class_docstr_tok: ["Localize","Pi","stacking","interactions","between","atoms","in","macromolecular","complexes",".","Given","a","macromolecular","complex","made","up","of","multiple","constitutent","molecules",",","compute","pi-stacking","interactions","between","atoms","in","the","macromolecular","complex",".","For","each","atom",",","localize","this","salt","bridge","in","the","voxel","in","which","it","originated","to","create","a","local","pi-stacking","array",".","Let","`","voxels_per_edge","=","int","(","box_width\/voxel_width",")","`",".","Creates","a","tensor","output","of","shape","`","(","voxels_per_edge",",","voxels_per_edge",",","voxels_per_edge",",","2",")","`","for","each","macromolecular","complex",".","Each","voxel","has","2","fields",",","with","the","first","tracking","the","number","of","pi-pi","parallel","interactions",",","and","the","second","tracking","the","number","of","pi-T","interactions","."]
docstr: Compute featurization for a single mol/protein complex
  
  Parameters
  ----------
  datapoint: Tuple[str, str]
      Filenames for molecule and protein.
code: def _featurize(self, datapoint, **kwargs):  # -> Optional[np.ndarray]:
      """
      Compute featurization for a single mol/protein complex
  
      Parameters
      ----------
      datapoint: Tuple[str, str]
          Filenames for molecule and protein.
      """
      if "complex" in kwargs:
          datapoint = kwargs.get("complex")
          raise DeprecationWarning(
              'Complex is being phased out as a parameter, please pass "datapoint" instead.'
          )
  
      try:
          fragments = rdkit_utils.load_complex(
              datapoint, add_hydrogens=False
          )
  
      except MoleculeLoadException:
          logger.warning(
              "This molecule cannot be loaded by Rdkit. Returning None"
          )
          return None
      pairwise_features = []
      # We compute pairwise contact fingerprints
      centroid = compute_contact_centroid(fragments, cutoff=self.cutoff)
      for frag1_ind, frag2_ind in itertools.combinations(
          range(len(fragments)), 2
      ):
          frag1, frag2 = fragments[frag1_ind], fragments[frag2_ind]
          distances = compute_pairwise_distances(frag1[0], frag2[0])
          frag1_xyz = subtract_centroid(frag1[0], centroid)
          frag2_xyz = subtract_centroid(frag2[0], centroid)
          xyzs = [frag1_xyz, frag2_xyz]
          # rdks = [frag1[1], frag2[1]]
          (
              protein_pi_t,
              protein_pi_parallel,
              ligand_pi_t,
              ligand_pi_parallel,
          ) = compute_pi_stack(
              frag1[1],
              frag2[1],
              distances,
              dist_cutoff=self.cutoff,
              angle_cutoff=self.angle_cutoff,
          )
          pi_parallel_tensor = sum(
              [
                  voxelize(
                      convert_atom_to_voxel,
                      hash_function=None,
                      box_width=self.box_width,
                      voxel_width=self.voxel_width,
                      coordinates=xyz,
                      feature_dict=feature_dict,
                      nb_channel=1,
                  )
                  for (xyz, feature_dict) in zip(
                      xyzs, [ligand_pi_parallel, protein_pi_parallel]
                  )
              ]
          )
  
          pi_t_tensor = sum(
              [
                  voxelize(
                      convert_atom_to_voxel,
                      hash_function=None,
                      box_width=self.box_width,
                      voxel_width=self.voxel_width,
                      coordinates=frag1_xyz,
                      feature_dict=protein_pi_t,
                      nb_channel=1,
                  )
                  for (xyz, feature_dict) in zip(
                      xyzs, [ligand_pi_t, protein_pi_t]
                  )
              ]
          )
  
          pairwise_features.append(
              np.concatenate([pi_parallel_tensor, pi_t_tensor], axis=-1)
          )
      # Features are of shape (voxels_per_edge, voxels_per_edge, voxels_per_edge, 2) so we should concatenate on the last axis.
      return np.concatenate(pairwise_features, axis=-1)
  
imports: import itertools
  import logging
  import numpy
  from deepchem.utils import rdkit_utils
  from deepchem.feat import ComplexFeaturizer
  from deepchem.utils.voxel_utils import voxelize
  from deepchem.utils.voxel_utils import convert_atom_to_voxel
  from deepchem.utils.voxel_utils import convert_atom_pair_to_voxel
  from deepchem.utils.noncovalent_utils import compute_salt_bridges
  from deepchem.utils.noncovalent_utils import compute_binding_pocket_cation_pi
  from deepchem.utils.noncovalent_utils import compute_pi_stack
  from deepchem.utils.noncovalent_utils import compute_hydrogen_bonds
  from deepchem.utils.rdkit_utils import MoleculeLoadException
  from deepchem.utils.rdkit_utils import compute_contact_centroid
  from deepchem.utils.geometry_utils import compute_pairwise_distances
  from deepchem.utils.geometry_utils import subtract_centroid
  from deepchem.utils.fragment_utils import get_partial_charge
  from deepchem.utils.fragment_utils import reduce_molecular_complex_to_contacts
  from typing import List, Tuple, Optional
label_desc: Use image node_id 2 for calling the PiStackVoxelizer obj's underlying member method code with example usage: obj._featurize(datapoint) and returns: np, None