From f7ef8dc9cced702ed137b98700980fbb997be4b0 Mon Sep 17 00:00:00 2001 From: Mani <55563282+saimani5@users.noreply.github.com> Date: Tue, 25 Oct 2022 13:31:53 -0400 Subject: [PATCH 01/13] Update graphx.py Added max_neighbors argument to find_neighbors method --- atomai/utils/graphx.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/atomai/utils/graphx.py b/atomai/utils/graphx.py index d7930f15..09486a49 100644 --- a/atomai/utils/graphx.py +++ b/atomai/utils/graphx.py @@ -87,6 +87,10 @@ def find_neighbors(self, **kwargs: float): Identifies neighbors of each graph node Args: + **max_neighbors(int): + This is the maximum number of neighbors each node can have, + ususally used to form the graph with only nearest neighbors + Default is -1 which means it will find all the neighbors **expand (float): coefficient determining the maximum allowable expansion of atomic bonds when constructing a graph. For example, the two @@ -97,6 +101,7 @@ def find_neighbors(self, **kwargs: float): del v.neighbors[:] Rij = get_interatomic_r e = kwargs.get("expand", 1.2) + max_neighbors = kwargs.get("max_neighbors", -1) tree = spatial.cKDTree(self.coordinates[:, :3]) uval = np.unique(self.coordinates[:, -1]) if len(uval) == 1: @@ -105,8 +110,9 @@ def find_neighbors(self, **kwargs: float): for v, nn in zip(self.vertices, neighbors): for n in nn: if self.vertices[n] != v: - v.neighbors.append(self.vertices[n]) - v.neighborscopy.append(self.vertices[n]) + if max_neighbors==-1 or len(v.neighbors) Date: Tue, 25 Oct 2022 13:39:27 -0400 Subject: [PATCH 02/13] Update graphx.py Turned on return_sorted to cKDTree --- atomai/utils/graphx.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atomai/utils/graphx.py b/atomai/utils/graphx.py index 09486a49..fdb4b5e6 100644 --- a/atomai/utils/graphx.py +++ b/atomai/utils/graphx.py @@ -106,7 +106,7 @@ def find_neighbors(self, **kwargs: float): uval = np.unique(self.coordinates[:, -1]) if len(uval) == 1: rmax = Rij([self.map_dict[uval[0]], self.map_dict[uval[0]]], e) - neighbors = tree.query_ball_point(self.coordinates[:, :3], r=rmax) + neighbors = tree.query_ball_point(self.coordinates[:, :3], r=rmax, return_sorted = True) for v, nn in zip(self.vertices, neighbors): for n in nn: if self.vertices[n] != v: @@ -121,7 +121,7 @@ def find_neighbors(self, **kwargs: float): rij = dict(zip(apairs, rij)) for v, coords in zip(self.vertices, self.coordinates): atom1 = self.map_dict[coords[-1]] - nn = tree.query_ball_point(coords[:3], r=rmax) + nn = tree.query_ball_point(coords[:3], r=rmax, return_sorted = True) for n, coords2 in zip(nn, self.coordinates[nn]): if self.vertices[n] != v: atom2 = self.map_dict[coords2[-1]] From 842f92fca7363fc7bf4e2caada23afc93b0cd36f Mon Sep 17 00:00:00 2001 From: Mani <55563282+saimani5@users.noreply.github.com> Date: Tue, 25 Oct 2022 14:47:03 -0400 Subject: [PATCH 03/13] Update graphx.py Added max_neighbors as an argument to get_neighbors --- atomai/utils/graphx.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/atomai/utils/graphx.py b/atomai/utils/graphx.py index fdb4b5e6..e871eb5f 100644 --- a/atomai/utils/graphx.py +++ b/atomai/utils/graphx.py @@ -106,13 +106,16 @@ def find_neighbors(self, **kwargs: float): uval = np.unique(self.coordinates[:, -1]) if len(uval) == 1: rmax = Rij([self.map_dict[uval[0]], self.map_dict[uval[0]]], e) - neighbors = tree.query_ball_point(self.coordinates[:, :3], r=rmax, return_sorted = True) + if max_neighbors == -1: + neighbors = tree.query_ball_point(self.coordinates[:, :3], r=rmax) + else: + _, neighbors = tree.query(self.coordinates[:, :3], k=max_neighbors+1, distance_upper_bound = rmax) for v, nn in zip(self.vertices, neighbors): for n in nn: if self.vertices[n] != v: - if max_neighbors==-1 or len(v.neighbors) Date: Tue, 25 Oct 2022 14:51:38 -0400 Subject: [PATCH 04/13] Update graphx.py --- atomai/utils/graphx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomai/utils/graphx.py b/atomai/utils/graphx.py index e871eb5f..05dcfb15 100644 --- a/atomai/utils/graphx.py +++ b/atomai/utils/graphx.py @@ -127,7 +127,7 @@ def find_neighbors(self, **kwargs: float): if max_neighbors == -1: nn = tree.query_ball_point(coords[:3], r=rmax) else: - _, nn = tree.query(self.coordinates[:, :3], k=max_neighbors+1, distance_upper_bound = rmax) + _, nn = tree.query(coords[:3], k=max_neighbors+1, distance_upper_bound = rmax) for n, coords2 in zip(nn, self.coordinates[nn]): if self.vertices[n] != v: atom2 = self.map_dict[coords2[-1]] From 4a719b1dd6f68096ab7717636d56c170a3f59a09 Mon Sep 17 00:00:00 2001 From: Mani <55563282+saimani5@users.noreply.github.com> Date: Tue, 25 Oct 2022 14:59:33 -0400 Subject: [PATCH 05/13] Update graphx.py --- atomai/utils/graphx.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/atomai/utils/graphx.py b/atomai/utils/graphx.py index 05dcfb15..7e15ce2e 100644 --- a/atomai/utils/graphx.py +++ b/atomai/utils/graphx.py @@ -112,9 +112,10 @@ def find_neighbors(self, **kwargs: float): _, neighbors = tree.query(self.coordinates[:, :3], k=max_neighbors+1, distance_upper_bound = rmax) for v, nn in zip(self.vertices, neighbors): for n in nn: - if self.vertices[n] != v: - v.neighbors.append(self.vertices[n]) - v.neighborscopy.append(self.vertices[n]) + if not n >= len(self.vertices): + if self.vertices[n] != v: + v.neighbors.append(self.vertices[n]) + v.neighborscopy.append(self.vertices[n]) else: uval = [self.map_dict[u] for u in uval] @@ -129,12 +130,12 @@ def find_neighbors(self, **kwargs: float): else: _, nn = tree.query(coords[:3], k=max_neighbors+1, distance_upper_bound = rmax) for n, coords2 in zip(nn, self.coordinates[nn]): - if self.vertices[n] != v: - atom2 = self.map_dict[coords2[-1]] - eucldist = np.linalg.norm( - coords[:3] - coords2[:3]) - if eucldist <= rij[(atom1, atom2)]: - if max_neighbors==-1 or len(v.neighbors)= len(self.vertices): + if self.vertices[n] != v: + atom2 = self.map_dict[coords2[-1]] + eucldist = np.linalg.norm( + coords[:3] - coords2[:3]) + if eucldist <= rij[(atom1, atom2)]: v.neighbors.append(self.vertices[n]) v.neighborscopy.append(self.vertices[n]) From 31e81f9359051ff36a48e3afdc42a7f0233764fe Mon Sep 17 00:00:00 2001 From: Mani <55563282+saimani5@users.noreply.github.com> Date: Tue, 25 Oct 2022 15:07:15 -0400 Subject: [PATCH 06/13] Update graphx.py Made the graph symmetric when max_neighbors is used --- atomai/utils/graphx.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/atomai/utils/graphx.py b/atomai/utils/graphx.py index 7e15ce2e..76964a8d 100644 --- a/atomai/utils/graphx.py +++ b/atomai/utils/graphx.py @@ -138,7 +138,20 @@ def find_neighbors(self, **kwargs: float): if eucldist <= rij[(atom1, atom2)]: v.neighbors.append(self.vertices[n]) v.neighborscopy.append(self.vertices[n]) - + + #Making the graph symmetric when max_neighbors is used + for v in self.vertices: + id = v.id + rem_ids = [] + for nn in v.neighbors: + nn_neighbors_list = [nn.neighbors[l].id for l in range(len(nn.neighbors))] + if id not in nn_neighbors_list: + rem_ids.append(nn) + + for rem_id in rem_ids: + v.neighbors.remove(rem_id) + + def find_rings(self, v: Type[Node], rings: List[List[Type[Node]]] = [], From 35ed3d8ca7d519f7a0fa5cdc4d3958fbd72a86d3 Mon Sep 17 00:00:00 2001 From: Mani <55563282+saimani5@users.noreply.github.com> Date: Wed, 26 Oct 2022 05:55:15 -0400 Subject: [PATCH 07/13] Update graphx.py --- atomai/utils/graphx.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atomai/utils/graphx.py b/atomai/utils/graphx.py index 76964a8d..0a4c95be 100644 --- a/atomai/utils/graphx.py +++ b/atomai/utils/graphx.py @@ -129,8 +129,8 @@ def find_neighbors(self, **kwargs: float): nn = tree.query_ball_point(coords[:3], r=rmax) else: _, nn = tree.query(coords[:3], k=max_neighbors+1, distance_upper_bound = rmax) - for n, coords2 in zip(nn, self.coordinates[nn]): - if not n >= len(self.vertices): + if not n >= len(self.vertices): + for n, coords2 in zip(nn, self.coordinates[nn]): if self.vertices[n] != v: atom2 = self.map_dict[coords2[-1]] eucldist = np.linalg.norm( From 284ae64078818aa692fdd87a51a32246d99adc24 Mon Sep 17 00:00:00 2001 From: Mani <55563282+saimani5@users.noreply.github.com> Date: Wed, 26 Oct 2022 05:58:58 -0400 Subject: [PATCH 08/13] Update graphx.py --- atomai/utils/graphx.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/atomai/utils/graphx.py b/atomai/utils/graphx.py index 0a4c95be..e1bc582a 100644 --- a/atomai/utils/graphx.py +++ b/atomai/utils/graphx.py @@ -129,8 +129,10 @@ def find_neighbors(self, **kwargs: float): nn = tree.query_ball_point(coords[:3], r=rmax) else: _, nn = tree.query(coords[:3], k=max_neighbors+1, distance_upper_bound = rmax) - if not n >= len(self.vertices): - for n, coords2 in zip(nn, self.coordinates[nn]): + + for n in nn: + if not n >= len(self.vertices): + coords2 = self.coordinates[nn] if self.vertices[n] != v: atom2 = self.map_dict[coords2[-1]] eucldist = np.linalg.norm( From 922f2a17e7f5ce8db135886ef7dda56b3bcc8a0c Mon Sep 17 00:00:00 2001 From: Mani <55563282+saimani5@users.noreply.github.com> Date: Wed, 26 Oct 2022 06:01:11 -0400 Subject: [PATCH 09/13] Update graphx.py --- atomai/utils/graphx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomai/utils/graphx.py b/atomai/utils/graphx.py index e1bc582a..bff06c48 100644 --- a/atomai/utils/graphx.py +++ b/atomai/utils/graphx.py @@ -132,7 +132,7 @@ def find_neighbors(self, **kwargs: float): for n in nn: if not n >= len(self.vertices): - coords2 = self.coordinates[nn] + coords2 = self.coordinates[n] if self.vertices[n] != v: atom2 = self.map_dict[coords2[-1]] eucldist = np.linalg.norm( From bc503f3decbaeb33f7e7b68325578533fd7483fc Mon Sep 17 00:00:00 2001 From: Mani <55563282+saimani5@users.noreply.github.com> Date: Mon, 31 Oct 2022 02:22:04 -0400 Subject: [PATCH 10/13] Update graphx.py Added px2ang as an argument for the graph class. Right now, self.coordinates_ang is used for finding the neighbors but uses self. coordinates to form the nx_graph and to plot so that the plots are made in pixel units. --- atomai/utils/graphx.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/atomai/utils/graphx.py b/atomai/utils/graphx.py index bff06c48..1fea1d5a 100644 --- a/atomai/utils/graphx.py +++ b/atomai/utils/graphx.py @@ -61,7 +61,8 @@ class Graph: """ def __init__(self, coordinates: np.ndarray, - map_dict: Dict) -> None: + map_dict: Dict, + px2ang: float = 1) -> None: """ Initializes a graph object """ @@ -76,6 +77,8 @@ def __init__(self, coordinates: np.ndarray, v = Node(i, coords[:-1].tolist(), map_dict[coords[-1]]) self.vertices.append(v) self.coordinates = coordinates + self.coordinates_ang = deepcopy(coordinates) + self.coordinates_ang[:, :-1] = self.coordinates[:, :-1] * px2ang self.map_dict = map_dict self.size = len(coordinates) self.rings = [] @@ -102,14 +105,14 @@ def find_neighbors(self, **kwargs: float): Rij = get_interatomic_r e = kwargs.get("expand", 1.2) max_neighbors = kwargs.get("max_neighbors", -1) - tree = spatial.cKDTree(self.coordinates[:, :3]) - uval = np.unique(self.coordinates[:, -1]) + tree = spatial.cKDTree(self.coordinates_ang[:, :3]) + uval = np.unique(self.coordinates_ang[:, -1]) if len(uval) == 1: rmax = Rij([self.map_dict[uval[0]], self.map_dict[uval[0]]], e) if max_neighbors == -1: - neighbors = tree.query_ball_point(self.coordinates[:, :3], r=rmax) + neighbors = tree.query_ball_point(self.coordinates_ang[:, :3], r=rmax) else: - _, neighbors = tree.query(self.coordinates[:, :3], k=max_neighbors+1, distance_upper_bound = rmax) + _, neighbors = tree.query(self.coordinates_ang[:, :3], k=max_neighbors+1, distance_upper_bound = rmax) for v, nn in zip(self.vertices, neighbors): for n in nn: if not n >= len(self.vertices): @@ -123,7 +126,7 @@ def find_neighbors(self, **kwargs: float): rij = [Rij([a[0], a[1]], e) for a in apairs] rmax = np.max(rij) rij = dict(zip(apairs, rij)) - for v, coords in zip(self.vertices, self.coordinates): + for v, coords in zip(self.vertices, self.coordinates_ang): atom1 = self.map_dict[coords[-1]] if max_neighbors == -1: nn = tree.query_ball_point(coords[:3], r=rmax) @@ -132,7 +135,7 @@ def find_neighbors(self, **kwargs: float): for n in nn: if not n >= len(self.vertices): - coords2 = self.coordinates[n] + coords2 = self.coordinates_ang[n] if self.vertices[n] != v: atom2 = self.map_dict[coords2[-1]] eucldist = np.linalg.norm( From 211c08717573f80e13f511617797ebf243b4c62d Mon Sep 17 00:00:00 2001 From: Mani <55563282+saimani5@users.noreply.github.com> Date: Tue, 24 Jan 2023 20:29:39 -0500 Subject: [PATCH 11/13] Update fcnn.py Added n_channels argument for the ResHedNet which now incorporates the images with multiple channels --- atomai/nets/fcnn.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/atomai/nets/fcnn.py b/atomai/nets/fcnn.py index 107416f9..1c9124b0 100644 --- a/atomai/nets/fcnn.py +++ b/atomai/nets/fcnn.py @@ -231,6 +231,8 @@ class ResHedNet(nn.Module): Holistically nested edge detector with residual connections in each block Args: + n_channels: + Number of channels in the input layer nb_classes: Number of classes in the ground truth nb_filters: @@ -247,6 +249,7 @@ class ResHedNet(nn.Module): """ def __init__(self, + n_channels: int = 1, nb_classes: int = 1, nb_filters: int = 64, upsampling_mode: str = "bilinear", @@ -257,7 +260,7 @@ def __init__(self, super(ResHedNet, self).__init__() nbl = kwargs.get("layers", [3, 4, 5]) self.upsample = upsampling_mode - self.net1 = ResModule(2, nbl[0], 1, nb_filters, True) + self.net1 = ResModule(2, nbl[0], n_channels, nb_filters, True) self.net2 = nn.Sequential( nn.MaxPool2d(2, 2), ResModule(2, nbl[1], nb_filters, 2*nb_filters, True) From 89466da1b5a7681ce37d462d42b5a3923f82755a Mon Sep 17 00:00:00 2001 From: Mani <55563282+saimani5@users.noreply.github.com> Date: Tue, 24 Jan 2023 20:34:13 -0500 Subject: [PATCH 12/13] Update fcnn.py Added n_channels (number of input channels) to all the nets in the fcnn.py file --- atomai/nets/fcnn.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/atomai/nets/fcnn.py b/atomai/nets/fcnn.py index 1c9124b0..4800dafd 100644 --- a/atomai/nets/fcnn.py +++ b/atomai/nets/fcnn.py @@ -20,6 +20,8 @@ class Unet(nn.Module): Builds a fully convolutional Unet-like neural network model Args: + n_channels: + Number of channels in the input image nb_classes: Number of classes in the ground truth nb_filters: @@ -48,6 +50,7 @@ class Unet(nn.Module): (to maintain symmetry between encoder and decoder) """ def __init__(self, + n_channels: int = 1, nb_classes: int = 1, nb_filters: int = 16, dropout: bool = False, @@ -64,7 +67,7 @@ def __init__(self, padding_values = dilation_values.copy() dropout_vals = [.1, .2, .1] if dropout else [0, 0, 0] self.c1 = ConvBlock( - 2, nbl[0], 1, nb_filters, + 2, nbl[0], n_channels, nb_filters, batch_norm=batch_norm ) self.c2 = ConvBlock( @@ -148,6 +151,8 @@ class dilnet(nn.Module): by utilizing a combination of regular and dilated convolutions Args: + n_channels: + Number of channels in the input image nb_classes: Number of classes in the ground truth nb_filters: @@ -167,6 +172,7 @@ class dilnet(nn.Module): """ def __init__(self, + n_channels: int = 1, nb_classes: int = 1, nb_filters: int = 25, dropout: bool = False, @@ -184,7 +190,7 @@ def __init__(self, padding_values_2 = dilation_values_2.copy() dropout_vals = [.3, .3] if dropout else [0, 0] self.c1 = ConvBlock( - 2, nbl[0], 1, nb_filters, + 2, nbl[0], n_channels, nb_filters, batch_norm=batch_norm ) self.at1 = DilatedBlock( @@ -305,6 +311,8 @@ class SegResNet(nn.Module): with residual blocks for semantic segmentation Args: + n_channels: + Number of channels in the input image nb_classes: Number of classes in the ground truth nb_filters: @@ -324,6 +332,7 @@ class SegResNet(nn.Module): ''' def __init__(self, + n_channels: int = 1, nb_classes: int = 1, nb_filters: int = 32, batch_norm: bool = True, @@ -336,7 +345,7 @@ def __init__(self, super(SegResNet, self).__init__() nbl = kwargs.get("layers", [2, 2, 2]) self.c1 = ConvBlock( - 2, 1, 1, nb_filters, batch_norm=batch_norm + 2, 1, n_channels, nb_filters, batch_norm=batch_norm ) self.c2 = ResModule( 2, nbl[0], nb_filters, nb_filters*2, batch_norm=batch_norm From cb82fcf4cb9b5e08e96810d9c11cf08b8539a151 Mon Sep 17 00:00:00 2001 From: Mani <55563282+saimani5@users.noreply.github.com> Date: Tue, 24 Jan 2023 20:42:04 -0500 Subject: [PATCH 13/13] Update fcnn.py Added n_channels argument to the method init_fcnn_model --- atomai/nets/fcnn.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/atomai/nets/fcnn.py b/atomai/nets/fcnn.py index 4800dafd..5f52bdb3 100644 --- a/atomai/nets/fcnn.py +++ b/atomai/nets/fcnn.py @@ -398,12 +398,14 @@ def init_fcnn_model(model: Union[Type[nn.Module], str], meta_state_dict = { 'model_type': 'Seg', model: 'custom', 'nb_classes': nb_classes} return model, meta_state_dict + n_channels = kwargs.get('n_channels', 1) batch_norm = kwargs.get('batch_norm', True) dropout = kwargs.get('dropout', False) upsampling = kwargs.get('upsampling', "bilinear") meta_state_dict = { 'model_type': 'seg', 'model': model, + 'n_channels': n_channels, 'nb_classes': nb_classes, 'batch_norm': batch_norm, 'dropout': dropout, @@ -414,7 +416,7 @@ def init_fcnn_model(model: Union[Type[nn.Module], str], nb_filters = kwargs.get('nb_filters', 16) layers = kwargs.get("layers", [1, 2, 2, 3]) net = Unet( - nb_classes, nb_filters, dropout, + n_channels, nb_classes, nb_filters, dropout, batch_norm, upsampling, with_dilation, layers=layers ) @@ -423,7 +425,7 @@ def init_fcnn_model(model: Union[Type[nn.Module], str], nb_filters = kwargs.get('nb_filters', 25) layers = kwargs.get("layers", [1, 3, 3, 1]) net = dilnet( - nb_classes, nb_filters, + n_channels, nb_classes, nb_filters, dropout, batch_norm, upsampling, layers=layers ) @@ -431,14 +433,14 @@ def init_fcnn_model(model: Union[Type[nn.Module], str], nb_filters = kwargs.get('nb_filters', 32) layers = kwargs.get("layers", [2, 2, 2]) net = SegResNet( - nb_classes, nb_filters, + n_channels, nb_classes, nb_filters, batch_norm, upsampling, layers=layers ) elif isinstance(model, str) and model == 'ResHedNet': nb_filters = kwargs.get('nb_filters', 64) layers = kwargs.get("layers", [3, 4, 5]) net = ResHedNet( - nb_classes, nb_filters, + n_channels, nb_classes, nb_filters, upsampling, layers=layers ) else: