Commit 4c0a5a02 authored by sfritschi's avatar sfritschi
Browse files

Analyzed scaling of cell lists

parent 4fc26d98
import sys
sys.path.append('../')
import matplotlib.pyplot as plt
import numpy as np
from netflow import *
def main():
# Load basnet
basenet = netflow.load_network_from('../netflow/network/network.h5')
print("Network statistics:")
print("Throats: %d" % len(basenet.throats))
pore_throat_counts = [len(pore.throats) for pore in basenet.pores]
print("Max. number of throats per pore: %d" % max(pore_throat_counts))
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)))
cutoff = 0.5 * max([basenet.ub[i] - basenet.lb[i] \
for i in range(len(basenet.ub))])
end = 8
target_sizes = np.arange(end) + 1
avg_vals = np.empty(end, dtype=np.float64)
max_vals = np.empty(end, dtype=np.float64)
for i in range(1, end+1):
target = [i, i, i]
print(target)
max_, _, avg = netflow.cell_list_scaling(basenet=basenet, targetsize=target, \
cutoff=cutoff, sd=42)
avg_vals[i-1] = avg
max_vals[i-1] = max_
# Plot scaling of average number of pores per cell for different targetsizes
plt.figure()
plt.title(r"Scaling of Cell-List statistics w.r.t. Target-Size")
plt.xlabel(r"target size")
plt.ylabel(r"average #pores per cell")
plt.plot(target_sizes, avg_vals, "--bo")
plt.grid()
plt.savefig("plots/cell_scaling_avg.png")
plt.close()
plt.figure()
plt.title(r"Scaling of Cell-List statistics w.r.t. Target-Size")
plt.xlabel(r"target size")
plt.ylabel(r"maximum #pores per cell")
plt.plot(target_sizes, max_vals, "--ro")
plt.grid()
plt.savefig("plots/cell_scaling_max.png")
plt.close()
if __name__ == '__main__':
main()
......@@ -10,9 +10,10 @@ def main():
basenet = netflow.load_network_from('../netflow/network/network.h5')
print("Network statistics:")
print("Throats: %d" % len(basenet.throats))
print("Max. number of throats per pore: %d" % max([len(pore.throats) for pore in basenet.pores]))
print("Min. number of throats per pore: %d" % min([len(pore.throats) for pore in basenet.pores]))
print("Avg. number of throats per pore: %f" % (sum([len(pore.throats) for pore in basenet.pores]) / len(basenet.pores)))
pore_throat_counts = [len(pore.throats) for pore in basenet.pores]
print("Max. number of throats per pore: %d" % max(pore_throat_counts))
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]
cutoff = 0.5 * max([basenet.ub[i] - basenet.lb[i] \
......
......@@ -120,22 +120,6 @@ class CellList:
for pore in pores:
cellIdx = self.pore_to_index(pore)
self.poresSorted[cellIdx].add(pore)
""" DEBUG
cellCounts = [0] * self.totalCells
for pore in pores:
cellIdx = self.pore_to_index(pore)
cellCounts[cellIdx] += 1
n = len(pores)
max_ = max(cellCounts)
min_ = min(cellCounts)
avg = sum(cellCounts) / len(cellCounts)
print("Cell statistics:")
print("Number of cells (%d, %d, %d)" % (self.nCells[0], self.nCells[1], self.nCells[2]))
print("Max. pores per cell: %d percent: %f" % (max_, max_ / n * 100.))
print("Min. pores per cell: %d percent: %f" % (min_, min_ / n * 100.))
print("Avg. pores per cell: %f percent: %f" % (avg, avg / n * 100.))
raise AssertionError("Stop")
"""
# Helper for converting 3D index triple into 1D (flattened) index
def flatten(self, i: int, j: int, k: int) -> int:
......@@ -180,6 +164,22 @@ class CellList:
candidates[nbor] = l
return candidates
def cell_stats(self):
cellCounts = [len(self.poresSorted[i]) for i in range(self.totalCells)]
n = sum(cellCounts)
max_ = max(cellCounts)
min_ = min(cellCounts)
avg = n / self.totalCells
"""
print("Cell statistics:")
print("Number of cells (%d, %d, %d)" % (self.nCells[0], self.nCells[1], self.nCells[2]))
print("Max. pores per cell: %d (%f%%)" % (max_, max_ / n * 100.))
print("Min. pores per cell: %d (%f%%)" % (min_, min_ / n * 100.))
print("Avg. pores per cell: %.1f (%f%%)" % (avg, avg / n * 100.))
"""
return (max_, min_, avg)
# Remove pore from sorted pores
def expel(self, pore: Pore):
poreIdx = self.pore_to_index(pore)
......@@ -454,6 +454,98 @@ def generate_imperial(basenet: Network, targetsize: List[float], \
for throat in throats: network.connect_pores(pore1=pores[throat[0]],
pore2=pores[throat[1]], label=throat[2], r=throat[3])
return network
def cell_list_scaling(basenet: Network, targetsize: List[int], \
cutoff: float = float('inf'), sd: int = None, mute: bool = False):
from random import seed, random, randint
from itertools import product
seed(sd)
d = len(targetsize) # number of spatial dimensions
# check target size multiplicator (must be >= 1)
if any([i < 1 for i in targetsize]):
raise NameError('targetsize must be >= 1!')
# size of new network
L = list(map(lambda lb,ub,i: (ub-lb)*i, basenet.lb, basenet.ub, targetsize))
# check target size (must be > basenet.Lmax)
if any([Lc < basenet.Lmax for Lc in L]):
raise NameError('targetsize leads network < Lmax of basenet!')
# pores, distributed based on dendrogram of basenet
if (not mute): print("distributing pores...", end="", flush=True)
# make indexable and discard in-/outflow pores
basepores = [pore for pore in basenet.pores \
if ((pore.label[:len(LABELS[1])] != LABELS[1]) \
and (pore.label[:len(LABELS[2])] != LABELS[2]))]
# dendrogram-based or uniform pore distribution
pores = []
if (cutoff != cutoff): # uniform
print("\b"*21 + "uniform pore distribution")
# loop over network sections & add uniformly distributed pores drawn from basenet
for s in product(*[range(k) for k in targetsize]):
for k, pore in enumerate(basepores):
pos = [random()*l for l in L]
pores.append(Pore(pos=pos, r=pore.r, label=LABELS[0],
throats=pore.throats.copy()))
else: # dendrogram-based
# extract cluster hierarchy from basenet
centroids = [pore.pos for pore in basepores]
from scipy.cluster import hierarchy
clustree = hierarchy.linkage(centroids, method = 'centroid')
# determine cluster centroids and weights
weights = len(basepores)*[1] # pores have weight = 1
for cluster in clustree:
p1 = int(cluster[0]); p2 = int(cluster[1])
w1 = weights[p1]; w2 = weights[p2]
centroids.append(list(map(lambda x1,x2: (w1*x1 + w2*x2)/(w1 + w2),
centroids[p1], centroids[p2])))
weights.append(w1 + w2)
# loop over network sections (twisted basenet copies)
for s in product(*[range(k) for k in targetsize]):
# twist centers of sufficiently small cluster
touched = [False]*len(centroids)
# positions of pores based on rotations of linked cluster-pairs
for k in range(len(centroids)-1,len(basepores)-1,-1):
i = k-len(basepores) # index of cluster in clustree
ctr = centroids[k] # center of rotation
dist = clustree[i,2] # cluster distance
# check if cluster/pore needs to be twisted
if ((dist < cutoff) or touched[k]):
p1 = int(clustree[i,0]); p2 = int(clustree[i,1])
w1 = weights[p1]; w2 = weights[p2]
vec = random_direction(d)
centroids[p1] = \
[ctr[j] + w2*dist/(w1+w2)*vec[j] for j in range(d)]
centroids[p2] = \
[ctr[j] - w1*dist/(w1+w2)*vec[j] for j in range(d)]
touched[p1] = touched[p2] = True
# add section pores in random order to pores of new network
for k, pore in enumerate(basepores):
pos = [c-lb + si*(ub-lb) \
for c,si,lb,ub in zip(centroids[k],s,basenet.lb,basenet.ub)]
pores.insert(randint(0,len(pores)), Pore(pos=pos,
r=pore.r, label=LABELS[0], throats=pore.throats.copy()))
print("\b"*21 + "left {0:d} of {1:d} clusters (incl. {2:d} pores) untouched".\
format(sum([int(not j) for j in touched]), len(touched), len(basepores)))
# flip pores outside back into domain
for pore in pores:
for k in range(d):
if pore.pos[k] < 0:
pore.pos[k] = L[k] + pore.pos[k]
elif pore.pos[k] >= L[k]:
pore.pos[k] = pore.pos[k] - L[k]
# add pore buffer layers for spatial periodicity
n = len(pores)
copies = __add_buffer_layers(pores, L, basenet.Lmax)
# Domain size including periodic buffer layers on all sides
trueDomainSize = [L[i] + 2 * basenet.Lmax for i in range(d)]
# Initialize cell-list; Place each pore in respective cell-set
cellList = CellList(pores, trueDomainSize, basenet.Lmax, basenet.Lmax)
# Print cell stats to console
max_, min_, avg = cellList.cell_stats()
return (max_, min_, avg)
def generate_dendrogram(basenet: Network, targetsize: List[int], \
cutoff: float = float('inf'), sd: int = None, mute: bool = False) \
......
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