class_docstr: The Lattice Convolution layer of LCNN
  
  The following class implements the lattice convolution function which is
  based on graph convolution networks where,
  [1] Each atom is represented as a node
  [2] Adjacent atom based on distance are considered as neighbors.
  
  Operations in Lattice Convolution:
  
  [1] In graph aggregation step- node features of neighbors are concatenated and
  into a linear layer. But since diffrent permutation of order of neighbors could
  be considered because of which , diffrent permutation of the lattice
  structure are considered in diffrent symmetrical angles (0 , 60 ,120 180 , 240 , 300 )
  
  [2] After the linear layer on each permutations, they are added up for each node and
  each node is transformed into a vector.
  
  Examples
  --------
  >>> import deepchem as dc
  >>> from deepchem.models.torch_models.lcnn import LCNNBlock
  >>> from deepchem.feat.graph_data import GraphData
  >>> import numpy as np
  >>> nodes = np.array([0, 1, 2])
  >>> x = np.zeros((nodes.size, nodes.max()+1))
  >>> x[np.arange(nodes.size),nodes] = 1
  >>> v = np.array([ 0,0, 0,0, 1,1, 1,1, 2,2, 2,2 ])
  >>> u = np.array([ 1,2, 2,1, 2,0, 0,2, 1,0, 0,1 ])
  >>> graph = GraphData(node_features=x, edge_index=np.array([u, v]))
  >>> model = LCNNBlock(3*2, 3, 2)
  >>> G = graph.to_dgl_graph()
  >>> x = G.ndata.pop('x')
  >>> print(model(G, x).shape)
  torch.Size([3, 3])
docstr: Update node representations.
  
  Parameters
  ----------
  G: DGLGraph
      DGLGraph for a batch of graphs.
  node_feats: torch.Tensor
      The node features. The shape is `(N, Node_feature_size)`.
  
  Returns
  -------
  node_feats: torch.Tensor
      The updated node features. The shape is `(N, Node_feature_size)`.
docstr_tok: ["Update","node","representations",".","Parameters","--","--","--","--","--","G",":","DGLGraph","DGLGraph","for","a","batch","of","graphs",".","node_feats",":","torch.Tensor","The","node","features",".","The","shape","is","`","(","N",",","Node_feature_size",")","`",".","Returns","--","--","--","-","node_feats",":","torch.Tensor","The","updated","node","features",".","The","shape","is","`","(","N",",","Node_feature_size",")","`","."]
code: def forward(self, G, node_feats):
      """
      Update node representations.
  
      Parameters
      ----------
      G: DGLGraph
          DGLGraph for a batch of graphs.
      node_feats: torch.Tensor
          The node features. The shape is `(N, Node_feature_size)`.
  
      Returns
      -------
      node_feats: torch.Tensor
          The updated node features. The shape is `(N, Node_feature_size)`.
      """
      try:
          import dgl.function as fn
      except:
          raise ImportError("This class requires DGL to be installed.")
      G = G.local_var()
      G.ndata["x"] = node_feats
      G.update_all(fn.copy_u("x", "m"), self.reduce_func)
      X = self.conv_weights(G.ndata["X_site"])
      X = torch.stack([self.batch_norm(X_i) for X_i in X])
      node_feats = torch.stack(
          [self.dropout(X_i).sum(axis=0) for X_i in X]
      )
      return node_feats
  
imports: import torch
  import torch.nn
  from deepchem.models.torch_models.torch_model import TorchModel
  from deepchem.models.losses import L2Loss
label_desc: Use image node_id 3 for calling the LCNNBlock obj's underlying member method code with example usage: obj.forward(G, node_feats) and returns: node_feats