Commit 9e5f5e49 authored by sfritschi's avatar sfritschi
Browse files

Searching for best neighbor for each throat simultaneously

parent fbe0f09e
......@@ -15,7 +15,7 @@ def main():
print("Min. number of throats per pore: %d" % min(pore_throat_counts))
print("Avg. number of throats per pore: %f" % (sum(pore_throat_counts) / len(pore_throat_counts)))
target = [3, 3, 3]
target = [5, 5, 5]
cutoff = 0.5 * max([basenet.ub[i] - basenet.lb[i] \
for i in range(len(basenet.ub))])
......
......@@ -102,6 +102,58 @@ class Network:
pore1.throats.add(throat); pore2.throats.add(throat)
return throat
class Ranking:
"""Ranking class maintaining ordered list of best candidates.
"""
def __init__(self, referenceVals: List[float]):
self.referenceVals = referenceVals
self.size = len(referenceVals)
self.rankings = [[] for _ in range(self.size)]
# Insert new candidate in appropriate place(s) of ranking
def insert(self, value: float, index: int):
for i in range(self.size):
ranking = self.rankings[i]
ref = self.referenceVals[i]
diff = abs(value - ref)
for j in range(len(ranking) + 1):
# Check if no match found
if j == len(ranking):
# Check if there's still space left
if j < i + 1:
ranking.append((value, index))
# Find correct placement for value
elif diff < abs(ranking[j][0] - ref):
ranking.insert(j, (value, index))
if len(ranking) > i + 1:
# Remove last element in ranking
ranking.pop()
# Correct placement found; done
break
# Extract best (unique) candidates from ranking
def extract_best(self) -> List[Tuple[float, int]]:
candidates = []
# Keep track of already extracted candidates
touched = set()
for i in range(self.size):
ranking = self.rankings[i]
# Special case: Not enough values
if len(ranking) < i + 1:
break # Nothing left to do
candidate = ranking[0]
k = 1
# Find best candidate among those
# not already chosen
while candidate[1] in touched:
candidate = ranking[k]
k += 1
candidates.append(candidate)
touched.add(candidate[1])
return candidates
class CellList:
"""CellList class dividing physical domain into equally-sized cells
......@@ -153,8 +205,11 @@ class CellList:
return 0 <= idx < self.totalCells
# Compute dictionary of all nbor candidates of given pore
def find_candidates(self, poreIdx: int) -> Dict[int, float]:
candidates = {}
def find_candidates(self, poreIdx: int, targetLens: List[float]) \
-> List[Tuple[float, int]]:
# Initialize ranking
ranking = Ranking(targetLens)
porePos = self.fetch_pos(poreIdx)
cellIdxTrip = self.pore_to_triplet(poreIdx)
......@@ -163,7 +218,8 @@ class CellList:
if (nborIdx == poreIdx): continue
l = distance(self.fetch_pos(nborIdx), porePos)
if (l < self.Lmax):
candidates[nborIdx] = l
# Insert neighbor pore in ranking
ranking.insert(l, nborIdx)
# TODO: Speed up finding of suitable candidates (e.g. multiprocessing)
for n in range(self.dim):
......@@ -171,15 +227,13 @@ class CellList:
cellIdx = self.flatten(cellIdxTrip[0] + i * (n == 0), \
cellIdxTrip[1] + i * (n == 1), \
cellIdxTrip[2] + i * (n == 2))
# Check if valid cell index
#assert(self.is_valid_index(nborIdx))
# Check all pores within current neighbor-cell
for nborIdx in self.poresSorted[cellIdx]:
l = distance(self.fetch_pos(nborIdx), porePos)
if (l < self.Lmax):
candidates[nborIdx] = l
return candidates
ranking.insert(l, nborIdx)
# Return list of best candidates for each throat
return ranking.extract_best()
def fetch_pos(self, poreIdx: int) -> List[float]:
lb = self.dim * poreIdx
......@@ -728,23 +782,68 @@ def generate_dendrogram(basenet: Network, targetsize: List[int], \
worker.start()
"""
max_throat_diff = 0.
for i, pore in enumerate(pores[:n]):
for poreIdx, pore in enumerate(pores[:n]):
# (re)run triangulation if maximal number of neighbors exceeds
# threshold given by 2x init. maximum (large nnbrs -> expensive search)
# check throats and neighborhood
if (not mute):
print(f"progress {((i+1) / n)*100.:.1f}%", end="\r", flush=True)
print(f"progress {((poreIdx+1) / n)*100.:.1f}%", end="\r", flush=True)
if (len(pore.throats) == 0): continue # no further connection needed
# Compute list of target throat lengths
targetLens = [distance(*throat_ends(throat,
[ub-lb for lb,ub in zip(basenet.lb,basenet.ub)]))
for throat in pore.throats]
throatR = [throat.r for throat in pore.throats]
# find candidates in neighborhood and respective throat lengths
# TODO: Search neighboring cells in parallel
candidates = cellList.find_candidates(pore.index)
#neighborhood = cellList.nbor_indices(pore)
#candidates = cellList.find_candidates(pore.index, targetLens)
candidates = cellList.find_candidates(poreIdx, targetLens)
# establish throat connections between pore and best candidate
# TODO: Perform this for all throats simultaneously
# (nbor, throat, actual length)
# Set of neighbor indices already connected to
#conpores = set()
for i, candidate in enumerate(candidates):
lt = candidate[0]
nborIdx = candidate[1]
# DEBUG: Update maximum difference between
# realised throat length and target throat length
diff = abs(lt - targetLens[i])
if (max_throat_diff < diff):
max_throat_diff = diff
nbor = pores[nborIdx]
nborc = nbor # memorize potential periodic copy
# find original of buffer layer pore
if (nbor.label != LABELS[0]):
j, lbl = nbor.label.split(' ',1)
nbor = pores[int(j)]
else:
lbl = LABELS[0]
# connect pore to nbor
throats.append([pore, nbor, lbl, throatR[i]])
# remove most similar throat of nbor
nborRanking = [(distance(*throat_ends(nthroat,
[ub-lb for lb,ub in zip(basenet.lb,basenet.ub)])),
nthroat) for nthroat in nbor.throats]
_, nthroat = min(nborRanking, key=lambda lth: abs(lth[0] - lt))
nbor.throats.remove(nthroat)
# remove fully connected nbor from search neighborhood
if (len(nbor.throats) == 0):
cellList.expel(nbor)
for cpore in copies[nbor]:
cellList.expel(cpore)
# update count of unrealised throats
k = k + (len(pore.throats) - len(candidates))
# remove fully connected pore from search neighborhood
cellList.expel(pore)
for cpore in copies[pore]:
cellList.expel(cpore)
"""
while (len(pore.throats) > 0):
#if (not mute):
# print("\b"*12 + ", throat {0:3d}".format(len(pore.throats)),
......@@ -753,7 +852,6 @@ def generate_dendrogram(basenet: Network, targetsize: List[int], \
lt = distance(*throat_ends(throat,
[ub-lb for lb,ub in zip(basenet.lb,basenet.ub)])) # target len.
"""
# Distribute cell indices of neighbor
for nborCellIdx in neighborhood:
in_q.put((conpores, pore.index, nborCellIdx, lt))
......@@ -783,7 +881,7 @@ def generate_dendrogram(basenet: Network, targetsize: List[int], \
lt = bestLen
# Update connected pores
conpores.add(bestIdx)
"""
if (len(candidates) == 0):
k = k+1; continue # no candidates left
nborIdx, ltc = min(candidates.items(), key=lambda pl: abs(pl[1] - lt))
......@@ -822,7 +920,7 @@ def generate_dendrogram(basenet: Network, targetsize: List[int], \
for cpore in copies[pore]:
cellList.expel(cpore)
"""
percent = k / (k + len(throats)) * 100.
print("\b"*24 + "{0:d} throats in total, {1:d} unrealised ({2:.1f}%)".\
format(len(throats), k, percent))
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment