# Iterating over cell neighbors¶

We have already learned how to iterate over cells in the simulation. Quite often in the multi-cell simulations there is a need to visit neighbors of a single cell. We define a neighbor as an adjacent cell which has common surface area with the cell in mind. To enable neighbor tracking you have to include NeighborTracker plugin in the XML or in Python code which replaces XML. For details see CompuCellPythonTutorial/NeighborTracker example. Take a look at the implementation of the step function where we visit cell neighbors:

def step(self, mcs):
for cell in self.cellList:
print "*********NEIGHBORS OF CELL WITH ID ", cell.id,
for neighbor, commonSurfaceArea in self.getCellNeighborDataList(cell):
if neighbor:
print "neighbor.id", neighbor.id, " commonSurfaceArea=", commonSurfaceArea
else:
print "Medium commonSurfaceArea=", commonSurfaceArea


In the outer for loop we iterate over all cells. During each iteration this loop picks a single cell. For each such cell we construct the inner loop where we access a list of cell neighbors:

for neighbor, commonSurfaceArea in self.getCellNeighborDataList(cell):


Notice that during each iteration loop Python returns two objects: neighbor and common surface area. neighbor points to a cell object that has nonzero common surface area with the cell from the outer loop. It can happen that the neighbor object returned by the inner loop is None. This means that this particular cell from the outer loop touches Medium. Take a look at the if-else statement in the example code above. If you want to paste neighbor iteration code template into your simulation go to CC3D Python->Visit->Cell Neighbors in Twedit++.

If you are puzzled why loop above has two variables after for it is because self.getCellNeighborDataList(cell) object when iterated over will return tuples of two objects. Let’s do an experiment:

for neighbor_tuple in self.getCellNeighborDataList(cell):
print neighbor_tuple
if neighbor_tuple[0]:
print 'Cell id = ', neighbor_tuple[0].id
else:
print 'Got Medium Cell '
print 'Common Surface Area = ', neighbor_tuple[1]


The output will be:

neighbor_tuple= (<CompuCell.CellG; proxy of <Swig Object of type 'std::vector< CompuCell3D::CellG * >::value_type' at 0x0000000007388EA0> >, 5)
Cell id =  11
Common Surface Area =  5
neighbor_tuple= (None, 4)
Got Medium Cell
Common Surface Area =  4


Now you can see neighbor_tuple is indeed an object that has two components. First one neighbor_tuple[0] points to cell object, second one neighbor_tuple[1] is a common surface area.

In general, when Python iterates over a list-like object that returns tuples you have two choices how to write the for loop. You can either use

for neighbor_tuple in self.getCellNeighborDataList(cell):
print neighbor_tuple[0],neighbor_tuple[1]


and refer to to the elements of the returned tuple using indices or you can be more explicit and unpack the tuple directly into two variables and access them by different “names”:

for neighbor, commonSurfaceArea in self.getCellNeighborDataList(cell):
print neighbor, commonSurfaceArea


## Neighbor Iteration Helpers¶

In addition to a plain-vanilla iteration over neighbors the CellNeighborDataList object that you get using self.getCellNeighborDataList(cell) has few useful tools that summarize properties of cell neighbors.

## Common Surface Area With Cells of Given Types¶

Sometimes we are interested in a common surface area of a given cell with ALL neighbors that are of specific type. CellNeighborDataList has a convenience function commonSurfaceAreaWithCellTypes that computes it. Here is an example

for cell in self.cellList:
neighborList = self.getCellNeighborDataList(cell)
common_area_with_types = neighborList.commonSurfaceAreaWithCellTypes(cell_type_list=[1, 2])
print 'Common surface of cell.id={} with cells of types [1,2] = {}'.format(cell.id, common_area_with_types)


The example output is:

Common surface of cell.id=10 with cells of types [1,2] = 24
Common surface of cell.id=11 with cells of types [1,2] = 22


As you can see commonSurfaceAreaWithCellTypes returns a number that is a total common surtface area of a given cell with other cells of the type that you specify as argument to commonSurfaceAreaWithCellTypes function as shown above

## Common Surface Area With Cells of a Given Type - Detailed view¶

If you want to break the above common surface area by cell types. i.e. you want to know what was the common surface area with cells of type 1, what was the common surface area with cells of type 2, etc…, you want to use neighborList.commonSurfaceAreaByType() call :

for cell in self.cellList:
neighborList = self.getCellNeighborDataList(cell)
common_area_with_types = neighborList.commonSurfaceAreaWithCellTypes(cell_type_list=[1, 2])
print 'Common surface of cell.id={} with cells of types [1,2] = {}'.format(cell.id, common_area_with_types)

common_area_by_type_dict = neighborList.commonSurfaceAreaByType()
print 'Common surface of cell.id={} with neighbors \ndetails {}'.format(cell.id, common_area_by_type_dict)


The output may look as follows:

Common surface of cell.id=10 with cells of types [1,2] = 20
Common surface of cell.id=10 with neighbors
details defaultdict(<type 'int'>, {1L: 15, 2L: 5})

Common surface of cell.id=11 with cells of types [1,2] = 24
Common surface of cell.id=11 with neighbors
details defaultdict(<type 'int'>, {1L: 15, 2L: 9})


For cell with id=10 we have that the total common surface area with cell types 1 and 2 is 20 and if we “zoom-in” we can see that cell with id=10 had common surface area of 15 with cell of types 1 and 5 with cells of type 2 The two contact areas by type ad up to 20 as expected because this particular cell is in contact only with cells of type 1 and 2.

Similar thinking explains common surface areas for cell 11.

A more interesting thing is to look at cell with id==. In this particular simulation this cell was in contact with Medium and the output looks as follows:

Common surface of cell.id=1 with cells of types [1,2] = 12
Common surface of cell.id=1 with neighbors
details defaultdict(<type 'int'>, {0: 10, 1L: 1, 2L: 11})


Now you see that the overlap with cells of type 0, 1, 2 was 10, 1, 11 and this does not add up to 12 - the total contact area between cell with id=1 and cells of type 1 and 2. However if we replaced

common_area_with_types = neighborList.commonSurfaceAreaWithCellTypes(cell_type_list=[1, 2])


with

common_area_with_types = neighborList.commonSurfaceAreaWithCellTypes(cell_type_list=[0, 1, 2])


all the surfaced areas for cell with id=1 woudl add up as they did for cells with id=10

## Counting Neighbors of Particular Type¶

If you want to know how many neighbors of a given type a given cell has you can do “manual” iteration of all neighbors and keep track of how many of them were of a particular type or you can use a convenience function neighborCountByType. neighborCountByType will return a dicitonary where the key is a type io the neighbor and the value is how many neighbors of this type are in contact with a given cell

Here is an example:

for cell in self.cellList:
neighborList = self.getCellNeighborDataList(cell)
neighbor_count_by_type_dict = neighborList.neighborCountByType()
print 'Neighbor count for cell.id={} is {}'.format(cell.id, neighbor_count_by_type_dict)


and the output is:

Neighbor count for cell.id=1 is defaultdict(<type 'int'>, {0: 1, 1L: 1, 2L: 2})
Neighbor count for cell.id=2 is defaultdict(<type 'int'>, {0: 1, 1L: 2, 2L: 1})
...
Neighbor count for cell.id=11 is defaultdict(<type 'int'>, {1L: 4, 2L: 2})
Neighbor count for cell.id=12 is defaultdict(<type 'int'>, {1L: 2, 2L: 3})


Here is an explanation: cell with id==2 had one neighbor of type Medium (key 0), two neighbor of type 1 (key 1), and one neighbor of type 2 (key 2)

Cell with id=11 was in contact with six cells - 4 of them were of type 1 and two were of type 2