Subsamples the point cloud using a grid (cubic) clustering scheme. The function returns one average sample per cell, as described in Fig. 3.e) of the paper. Args: x (Tensor): (N,3) point cloud. batch (integer Tensor, optional): (N,) batch vector, as in PyTorch_geometric
(x, batch=None, scale=1.0)
| 105 | # On-the-fly generation of the surfaces ======================================== |
| 106 | # Code taken from https://github.com/FreyrS/dMaSIF/blob/master/geometry_processing.py |
| 107 | def subsample(x, batch=None, scale=1.0): |
| 108 | """Subsamples the point cloud using a grid (cubic) clustering scheme. |
| 109 | |
| 110 | The function returns one average sample per cell, as described in Fig. 3.e) |
| 111 | of the paper. |
| 112 | |
| 113 | Args: |
| 114 | x (Tensor): (N,3) point cloud. |
| 115 | batch (integer Tensor, optional): (N,) batch vector, as in PyTorch_geometric. |
| 116 | Defaults to None. |
| 117 | scale (float, optional): side length of the cubic grid cells. Defaults to 1 (Angstrom). |
| 118 | |
| 119 | Returns: |
| 120 | (M,3): sub-sampled point cloud, with M <= N. |
| 121 | """ |
| 122 | |
| 123 | if batch is None: # Single protein case: |
| 124 | if True: # Use a fast scatter_add_ implementation |
| 125 | labels = grid_cluster(x, scale).long() |
| 126 | C = labels.max() + 1 |
| 127 | |
| 128 | # We append a "1" to the input vectors, in order to |
| 129 | # compute both the numerator and denominator of the "average" |
| 130 | # fraction in one pass through the data. |
| 131 | x_1 = torch.cat((x, torch.ones_like(x[:, :1])), dim=1) |
| 132 | D = x_1.shape[1] |
| 133 | points = torch.zeros_like(x_1[:C]) |
| 134 | points.scatter_add_(0, labels[:, None].repeat(1, D), x_1) |
| 135 | return (points[:, :-1] / points[:, -1:]).contiguous() |
| 136 | |
| 137 | else: # Older implementation; |
| 138 | points = scatter(points * weights[:, None], labels, dim=0) |
| 139 | weights = scatter(weights, labels, dim=0) |
| 140 | points = points / weights[:, None] |
| 141 | |
| 142 | else: # We process proteins using a for loop. |
| 143 | # This is probably sub-optimal, but I don't really know |
| 144 | # how to do more elegantly (this type of computation is |
| 145 | # not super well supported by PyTorch). |
| 146 | batch_size = torch.max(batch).item() + 1 # Typically, =32 |
| 147 | points, batches = [], [] |
| 148 | for b in range(batch_size): |
| 149 | p = subsample(x[batch == b], scale=scale) |
| 150 | points.append(p) |
| 151 | batches.append(b * torch.ones_like(batch[: len(p)])) |
| 152 | |
| 153 | return torch.cat(points, dim=0), torch.cat(batches, dim=0) |
| 154 | |
| 155 | |
| 156 | def soft_distances(x, y, batch_x, batch_y, smoothness=0.01, atomtypes=None): |
no outgoing calls
no test coverage detected