...
 
Commits (3)
from methods import SubsamplingMethod
import numpy as np
from itertools import combinations
from methods import BoxSelectionSubsamplingMethod
from helpers import box_contains_contour
class CrossBoxSelector(SubsamplingMethod):
def __init__(self, particleContainer, desiredFraction:float = 0.1) -> None:
class CrossBoxSelector(BoxSelectionSubsamplingMethod):
def __init__(self, particleContainer, desiredFraction: float = 0.1) -> None:
super(CrossBoxSelector, self).__init__(particleContainer, desiredFraction)
self.fraction = desiredFraction
self.filterWidth: float = 1000
self.filterHeight: float = 1000
self.numBoxesAcross: int = 3 #either 3 or 5
self.numBoxesAcross: int = 3 # either 3 or 5
@property
def boxSize(self) -> float:
assert self.get_maximum_achievable_fraction() >= self.fraction
maxFraction = self.get_maximum_achievable_fraction()
if maxFraction < self.fraction:
self.fraction = maxFraction
totalBoxArea: float = ((self.filterWidth*self.filterHeight)*self.fraction)
boxArea: float = totalBoxArea / (2*self.numBoxesAcross - 1)
return boxArea**0.5
......@@ -66,4 +72,113 @@ class CrossBoxSelector(SubsamplingMethod):
start: float = i * filterSize / self.numBoxesAcross + (maxBoxSize - boxSize) / 2
tileStarts.append(start)
return tileStarts
\ No newline at end of file
return tileStarts
class SpiralSelector(BoxSelectionSubsamplingMethod):
def __init__(self, particleContainer, desiredFraction: float = 0.1) -> None:
super(SpiralSelector, self).__init__(particleContainer, desiredFraction)
self.filterWidth: float
self.filterHeight: float
self.boxSize: float = 50
self.numBoxes = 20
@property
def spiralSlope(self) -> float:
assert self.filterHeight == self.filterWidth
return self.armDistance / (2*np.pi)
@property
def armDistance(self) -> float:
return np.sqrt(2) * self.boxSize
@property
def actuallyCoveredFraction(self) -> float:
return self.numBoxes*self.boxSize**2 / (self.filterHeight*self.filterWidth)
def get_topLeft_of_boxes(self) -> list:
"""
Calculates the topLeft-points (x, y) of all measure boxes
The method uses an approximation for the spiral and is not purely accurate.
:return list:"""
filterCenter: tuple = self.filterWidth/2 - self.boxSize/2, self.filterHeight/2 - self.boxSize/2
slope = self.spiralSlope
theta: float = 0
boxDistance = self.boxSize * 1.1
topLefts: list = []
for i in range(self.numBoxes):
newPoint: tuple = self._get_xy_at_angle(theta, filterCenter)
topLefts.append(newPoint)
theta += boxDistance / (slope * np.sqrt(1 + theta**2))
boxDistance *= 1.05
topLefts = self._move_and_scale_toplefts(topLefts)
return topLefts
def _move_and_scale_toplefts(self, topLefts: list) -> list:
"""
The spiral approximation leads to boxes that are outside the filter size limits.
This function moves and scales the topLeft-Points so that all measure boxes lie within the filter limits.
:return list:
"""
assert self.filterHeight == self.filterWidth # elliptical filters are not supportet here..
xCoords: np.array = np.array([float(point[0]) for point in topLefts]) - self.filterWidth / 2
yCoords: np.array = np.array([float(point[1]) for point in topLefts]) - self.filterHeight / 2
xCoordsBoxMiddles: np.array = xCoords + self.boxSize/2
yCoordsBoxMiddles: np.array = yCoords + self.boxSize/2
lastBoxCenter: tuple = (xCoordsBoxMiddles[-1], yCoordsBoxMiddles[-1])
distanceLastCenter: float = np.linalg.norm(lastBoxCenter)
maxDistanceInLastBox: float = self._get_max_distance_of_boxCenter_to_center(lastBoxCenter)
halfBoxDistance: float = maxDistanceInLastBox - distanceLastCenter
desiredDistanceTotal: float = self.filterHeight / 2
desiredDistanceCenter: float = desiredDistanceTotal - halfBoxDistance
scaleFactor: float = desiredDistanceCenter / distanceLastCenter
xCoordsBoxMiddles *= scaleFactor
yCoordsBoxMiddles *= scaleFactor
xCoords = xCoordsBoxMiddles + (self.filterWidth - self.boxSize)/2
yCoords = yCoordsBoxMiddles + (self.filterHeight - self.boxSize)/2
newTopLefts = zip(np.round(xCoords), np.round(yCoords))
return list(tuple(newTopLefts))
def _get_max_distance_of_boxCenter_to_center(self, boxCenter: tuple, center: tuple = (0, 0)) -> float:
"""
Calculates the maximal distance of a box to the given center
:param topLeft:
:param boxSize:
:return:
"""
center = np.array(center)
boxSize = self.boxSize
coords: np.array = np.array([[boxCenter[0] - 0.5*boxSize, boxCenter[1] - 0.5*boxSize],
[boxCenter[0] + 0.5*boxSize, boxCenter[1] - 0.5*boxSize],
[boxCenter[0] - 0.5*boxSize, boxCenter[1] + 0.5*boxSize],
[boxCenter[0] + 0.5*boxSize, boxCenter[1] + 0.5*boxSize]])
distances: np.array = np.linalg.norm(coords - center, axis=1)
return np.max(distances)
def _get_xy_at_angle(self, theta: float, centerXY: tuple = (0, 0)) -> tuple:
distance: float = self.spiralSlope * theta
return distance * np.cos(theta) + centerXY[0], distance * np.sin(theta) + centerXY[1]
def _boxes_are_overlapping(self, topLefts: list) -> bool:
"""
Calculates if there is any overlap of the boxes
:return:
"""
overlaps: bool = False
for topLeft1, topLeft2 in combinations(topLefts, 2):
if abs(topLeft1[0] - topLeft2[0]) < self.boxSize and abs(topLeft1[1] - topLeft2[1]) < self.boxSize:
overlaps = True
break
return overlaps
......@@ -35,7 +35,7 @@ class FilterGraphItem(QtWidgets.QGraphicsItem):
"""
The Graphical Representation of the actual filter
"""
def __init__(self, filterWidth:float=500, filterHeight:float=500):
def __init__(self, filterWidth: float = 500, filterHeight: float = 500):
super(FilterGraphItem, self).__init__()
self.width = filterWidth
self.height = filterHeight
......
from PyQt5 import QtWidgets
from filterView import FilterView
from measureModes import CrossBoxMode, CrossBoxesControls
from gui.filterView import FilterView
from gui.measureModes import MeasureMode, CrossBoxMode, CrossBoxesControls, SpiralBoxMode
class MainView(QtWidgets.QWidget):
......@@ -12,8 +12,9 @@ class MainView(QtWidgets.QWidget):
self.setLayout(self.layout)
self.modeSelector: QtWidgets.QComboBox = QtWidgets.QComboBox()
self.modeSelector.currentTextChanged.connect(self._switch_to_mode)
self.measureModes: dict = {}
self.activeMode = None
self.activeMode: MeasureMode = None
self.activeModeControl: QtWidgets.QGroupBox = QtWidgets.QGroupBox()
self.controlGroup = QtWidgets.QGroupBox()
......@@ -31,20 +32,30 @@ class MainView(QtWidgets.QWidget):
self._switch_to_default_mode()
def _add_measure_modes(self) -> None:
self.modeSelector.addItem('crossSelection')
self.measureModes['spiralSelection'] = SpiralBoxMode(self.filterView)
self.measureModes['crossSelection'] = CrossBoxMode(self.filterView)
self.modeSelector.addItem('spiralSelection')
self.modeSelector.addItem('crossSelection')
def _switch_to_default_mode(self) -> None:
modes: list = list(self.measureModes.keys())
self._activate_mode(modes[0])
def _switch_to_mode(self) -> None:
newMode: str = self.modeSelector.currentText()
self._activate_mode(newMode)
def _activate_mode(self, modeName: str) -> None:
self.activeModeControl.setParent(None)
self.controlGroupLayout.removeWidget(self.activeModeControl)
requestedMode: MeasureMode = self.measureModes[modeName]
if requestedMode is not self._activate_mode:
self.activeModeControl.setParent(None)
self.controlGroupLayout.removeWidget(self.activeModeControl)
self.activeMode = requestedMode
self.activeModeControl = self.activeMode.get_control_groupBox()
self.controlGroupLayout.insertWidget(2, self.activeModeControl)
self.activeMode = self.measureModes[modeName]
self.activeModeControl = self.activeMode.get_control_groupBox()
self.controlGroupLayout.insertWidget(2, self.activeModeControl)
self.activeMode.update_measure_viewItems()
if __name__ == '__main__':
......
from PyQt5 import QtCore, QtWidgets
# import os, sys, inspect
# currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
# parentdir = os.path.dirname(currentdir)
# sys.path.insert(0, parentdir)
# del currentdir, parentdir
from filterView import FilterView, MeasureBoxGraphItem
from geometricOperations import CrossBoxSelector
from gui.filterView import FilterView, MeasureBoxGraphItem
from geometricMethods import CrossBoxSelector, SpiralSelector
class MeasureMode(QtCore.QObject):
......@@ -88,4 +83,59 @@ class CrossBoxesControls(QtWidgets.QGroupBox):
if maxCoverage < self.coverageSpinbox.value():
self.coverageSpinbox.valueChanged.disconnect()
self.coverageSpinbox.setValue(maxCoverage)
self.coverageSpinbox.valueChanged.connect(self._config_changed)
\ No newline at end of file
self.coverageSpinbox.valueChanged.connect(self._config_changed)
class SpiralBoxMode(MeasureMode):
def __init__(self, *args):
super(SpiralBoxMode, self).__init__(*args)
self.uiControls: SpiralBoxControls = SpiralBoxControls(self)
self.spiralBoxGenerator: SpiralSelector = SpiralSelector(None)
self.update_measure_viewItems()
def update_measure_viewItems(self) -> None:
self.spiralBoxGenerator.filterHeight = self.filterView.filter.height
self.spiralBoxGenerator.filterWidth = self.filterView.filter.width
self.spiralBoxGenerator.boxSize = self.uiControls.boxSizeSpinbox.value()
self.spiralBoxGenerator.numBoxes = self.uiControls.numBoxesSpinbox.value()
viewItems = []
topLefts: list = self.spiralBoxGenerator.get_topLeft_of_boxes()
boxSize = self.spiralBoxGenerator.boxSize
for (x, y) in topLefts:
newBox: MeasureBoxGraphItem = MeasureBoxGraphItem(x, y, boxSize, boxSize)
viewItems.append(newBox)
self.filterView.update_measure_boxes(viewItems)
class SpiralBoxControls(QtWidgets.QGroupBox):
"""
Gives a groupbox with the controls for setting up the cross boxes.
"""
def __init__(self, measureModeParent: MeasureMode):
super(SpiralBoxControls, self).__init__()
self.setTitle('Spiral Box Controls')
self.measureModeParent = measureModeParent
layout = QtWidgets.QHBoxLayout()
self.setLayout(layout)
layout.addWidget(QtWidgets.QLabel('Box Size:'))
self.boxSizeSpinbox = QtWidgets.QSpinBox()
self.boxSizeSpinbox.setValue(50)
self.boxSizeSpinbox.setMaximum(1000)
self.boxSizeSpinbox.valueChanged.connect(self._config_changed)
layout.addWidget(self.boxSizeSpinbox)
layout.addStretch()
layout.addWidget(QtWidgets.QLabel('Num Boxes:'))
self.numBoxesSpinbox = QtWidgets.QSpinBox()
self.numBoxesSpinbox.setValue(10)
self.numBoxesSpinbox.valueChanged.connect(self._config_changed)
layout.addWidget(self.numBoxesSpinbox)
def _config_changed(self):
self.measureModeParent.update_measure_viewItems()
......@@ -5,6 +5,9 @@ Created on Tue Jan 28 19:32:50 2020
@author: luna
"""
from PyQt5 import QtCore, QtGui
import numpy as np
class ParticleBinSorter(object):
def __init__(self):
......@@ -20,7 +23,7 @@ class ParticleBinSorter(object):
return particlesInBins
def _get_empty_bins(self):
return [[] for i in range(len(self.bins)+1)]
return [[] for _ in range(len(self.bins)+1)]
def _get_binIndex_of_particle(self, particle):
size = particle.getParticleSize()
......@@ -30,4 +33,18 @@ class ParticleBinSorter(object):
break
else:
binIndex += 1
return binIndex
\ No newline at end of file
return binIndex
def box_contains_contour(boxXY: tuple, boxWidthHeight: tuple, contour: np.array) -> bool:
contourPolygon = QtGui.QPolygonF()
for point in contour:
contourPolygon.append(QtCore.QPointF(point[0, 0], point[0, 1]))
boxPolygon = QtGui.QPolygonF()
boxPolygon.append(QtCore.QPointF(boxXY[0], boxXY[1]))
boxPolygon.append(QtCore.QPointF(boxXY[0], boxXY[1] + boxWidthHeight[1]))
boxPolygon.append(QtCore.QPointF(boxXY[0] + boxWidthHeight[0], boxXY[1]))
boxPolygon.append(QtCore.QPointF(boxXY[0] + boxWidthHeight[0], boxXY[1] + boxWidthHeight[1]))
return contourPolygon.intersects(boxPolygon)
......@@ -9,21 +9,46 @@ import random
import numpy as np
from helpers import ParticleBinSorter
class SubsamplingMethod(object):
def __init__(self, particleConatainer, desiredFraction: float = 0.2):
super(SubsamplingMethod, self).__init__()
self.particleContainer = particleConatainer
self.fraction = desiredFraction
def apply_subsampling_method(self):
def apply_subsampling_method(self) -> tuple:
"""
Takes all particles from the supplied particle conatiner and returns a new list of particles that
were measured by applying that subsampling procedure. Also, the actualy measured fraction is returned.
(The desired fraction may not always be achievable)
:returns actuallyMeasuredFraction, listOfSubParticles:
"""
raise NotImplementedError
class RandomSampling(SubsamplingMethod):
#def __init__(self, particleContainer, desiredFraction=0.1):
#super(RandomSampling, self).__init__(particleContainer)
#self.fraction = desiredFraction
class BoxSelectionSubsamplingMethod(SubsamplingMethod):
def __init__(self, *args):
super(BoxSelectionSubsamplingMethod, self).__init__(*args)
def apply_subsampling_method(self) -> tuple:
subParticles: list = []
topLefts: list = self.get_topLeft_of_boxes()
boxSize = self.boxSize
for particle in self.particleContainer.particles:
for topLeft in topLefts:
if box_contains_contour(topLeft, (boxSize, boxSize), particle.contour):
subParticles.append(particle)
return self.fraction, subParticles
def get_topLeft_of_boxes(self) -> list:
raise NotImplementedError
def get_parameterCombos_for_fraction(self) -> list:
raise NotImplementedError
class RandomSampling(SubsamplingMethod):
def apply_subsampling_method(self):
numOrigParticles = len(self.particleContainer.particles)
numParticles = self._get_number_of_random_particles(numOrigParticles)
......@@ -73,7 +98,7 @@ class SizeBinFractioning(SubsamplingMethod):
subParticlesPerBin: list = []
for particles in particlesInBins:
numParticlesInBin: int = len(particles)
numSubParticlesPerBin:int = np.int(np.round(numParticlesInBin * self.fraction))
numSubParticlesPerBin: int = np.int(np.round(numParticlesInBin * self.fraction))
if numSubParticlesPerBin == 0 and numParticlesInBin > 0:
numSubParticlesPerBin = 1
......@@ -81,10 +106,3 @@ class SizeBinFractioning(SubsamplingMethod):
subParticlesPerBin.append(subParticlesInBin)
return subParticlesPerBin
class SelectSquaresFromFilter(SubsamplingMethod):
def __init__(self, particleContainer, desiredFraction):
super(SelectSquaresFromFilter, self).__init__(particleContainer)
self.fraction = desiredFraction
......@@ -45,7 +45,7 @@ for fraction in fractions:
iterErrors.append(resultComparer._get_mp_count_error(origParticles, randomParticles, randomFraction))
bins, errorsPerBin = resultComparer._get_mp_count_error_per_bin(origParticles, randomParticles, randomFraction)
binIterErrors.append(errorsPerBin)
errors.append(round(np.mean(iterErrors)*100)) #from fraction to %
fractionBinErrors = []
for binIndex in range(len(bins)+1):
......
import unittest
from geometricOperations import CrossBoxSelector
import numpy as np
from geometricMethods import CrossBoxSelector, SpiralSelector
class TestSelectBoxes(unittest.TestCase):
class TestSelectCrossBoxes(unittest.TestCase):
def setUp(self) -> None:
self.crossBoxSelector = CrossBoxSelector(None)
......@@ -10,7 +12,7 @@ class TestSelectBoxes(unittest.TestCase):
self.crossBoxSelector.fraction = 0.1
self.crossBoxSelector.numBoxesAcross = 3
topLeftCorners:list = self.crossBoxSelector.get_topLeft_of_boxes()
topLeftCorners: list = self.crossBoxSelector.get_topLeft_of_boxes()
self.assertEqual(len(topLeftCorners), 5)
self.crossBoxSelector.numBoxesAcross = 5
......@@ -44,7 +46,8 @@ class TestSelectBoxes(unittest.TestCase):
horizontalTileStarts: list = self.crossBoxSelector._get_horizontal_box_starts(halfBoxSize)
verticalTileStarts: list = self.crossBoxSelector._get_vertical_box_starts(halfBoxSize)
expectedOffset = (maxBoxSize - halfBoxSize) / 2
self.assertEqual(horizontalTileStarts, [0+expectedOffset, 100/5+expectedOffset, 2*100/5+expectedOffset, 3*100/5+expectedOffset, 4*100/5+expectedOffset])
self.assertEqual(horizontalTileStarts, [0+expectedOffset, 100/5+expectedOffset, 2*100/5+expectedOffset,
3*100/5+expectedOffset, 4*100/5+expectedOffset])
self.assertEqual(horizontalTileStarts, verticalTileStarts)
def test_get_box_size(self) -> None:
......@@ -59,4 +62,59 @@ class TestSelectBoxes(unittest.TestCase):
areaPerBox: float = totalBoxArea / numBoxes
boxSize: float = areaPerBox**0.5
self.assertEqual(self.crossBoxSelector.boxSize, boxSize)
\ No newline at end of file
self.assertEqual(self.crossBoxSelector.boxSize, boxSize)
class TestSelectSpiralBoxes(unittest.TestCase):
def setUp(self) -> None:
self.spiralBoxSelector: SpiralSelector = SpiralSelector(None)
def test_move_and_scale_toplefts(self):
self.spiralBoxSelector.filterHeight = 100
self.spiralBoxSelector.filterWidth = 100
self.spiralBoxSelector.boxSize = 10
topLefts = [(45, 45), (0, 45), (90, 45)]
newTopLefts = self.spiralBoxSelector._move_and_scale_toplefts(topLefts)
self.assertEqual(newTopLefts[0], (45, 45))
self.assertEqual(newTopLefts[1], (0, 45))
self.assertEqual(newTopLefts[2], (90, 45))
def test_get_max_distance_of_boxCenter_to_center(self):
boxCenter = 0, 0
self.spiralBoxSelector.boxSize = 1
maxDistance: float = self.spiralBoxSelector._get_max_distance_of_boxCenter_to_center(boxCenter)
self.assertEqual(maxDistance, np.sqrt(0.5**2 + 0.5**2))
self.spiralBoxSelector.boxSize = 2
maxDistance: float = self.spiralBoxSelector._get_max_distance_of_boxCenter_to_center(boxCenter)
self.assertEqual(maxDistance, np.sqrt(2))
boxCenter = 1, 0
self.spiralBoxSelector.boxSize = 2
maxDistance: float = self.spiralBoxSelector._get_max_distance_of_boxCenter_to_center(boxCenter)
self.assertEqual(maxDistance, np.sqrt(2**2 + 1**2))
boxCenter = -1, -3
self.spiralBoxSelector.boxSize = 2
maxDistance: float = self.spiralBoxSelector._get_max_distance_of_boxCenter_to_center(boxCenter)
self.assertEqual(maxDistance, np.sqrt(4**2 + 2**2))
def test_boxes_are_overlapping(self):
self.spiralBoxSelector.boxSize = 10
topLefts: list = [(0, 0), (10, 10), (20, 10)]
overlaps: bool = self.spiralBoxSelector._boxes_are_overlapping(topLefts)
self.assertEqual(overlaps, False)
topLefts: list = [(0, 0), (9, 10)]
overlaps: bool = self.spiralBoxSelector._boxes_are_overlapping(topLefts)
self.assertEqual(overlaps, False)
topLefts: list = [(0, 0), (9, 9)]
overlaps: bool = self.spiralBoxSelector._boxes_are_overlapping(topLefts)
self.assertEqual(overlaps, True)
topLefts: list = [(-2, 0), (5, 9)]
overlaps: bool = self.spiralBoxSelector._boxes_are_overlapping(topLefts)
self.assertEqual(overlaps, True)
import unittest
from pytestqt import qtbot
from PyQt5.QtWidgets import QApplication
import sys
from gui.mainView import MainView
from gui.measureModes import CrossBoxesControls
app = QApplication(sys.argv)
class TestFilterViewGUI(unittest.TestCase):
def setUp(self) -> None:
pass
def test_hello(qtbot):
widget = MainView()
qtbot.addWidget(widget)
print('nu')
def test_gui(self):
#NEEDS TO BE IMPLEMENTED, too much was refactored to make the old test pass...
self.assertTrue(False)
\ No newline at end of file
#
# class TestMainViewGUI(unittest.TestCase):
# def setUp(self) -> None:
# # self.qbot = qtbot.QtBot(None)
# self.mainView: MainView = MainView()
# # self.qbot.addWidget(self.mainView)
#
# def test_switchModes_modes(self, qtbot = qtbot.QtBot):
# self.mainView._activate_mode('crossSelection')
# controls = self.mainView.activeModeControl
# self.assertTrue(type(controls) == CrossBoxesControls)
#
# numBoxComboBox = controls.numBoxesSelector
# qtbot.addWidget(self.mainView)
\ No newline at end of file
......@@ -7,12 +7,14 @@ Created on Tue Jan 28 19:35:04 2020
"""
import unittest
from helpers import ParticleBinSorter
from helpers import ParticleBinSorter, box_contains_contour
import numpy as np
import sys
sys.path.append("C://Users//xbrjos//Desktop//Python")
import gepard
from gepard.analysis.particleAndMeasurement import Particle
class TestBinSorter(unittest.TestCase):
def setUp(self):
self.sorter = ParticleBinSorter()
......@@ -20,10 +22,13 @@ class TestBinSorter(unittest.TestCase):
def test_sort_particles_into_bins(self):
particleList = []
upperBinLimit = None
for upperBinLimit in self.bins:
newParticle = Particle()
newParticle.longSize = newParticle.shortSize = upperBinLimit - 1
particleList.append(newParticle)
lastParticle = Particle()
lastParticle.longSize = lastParticle.shortSize = upperBinLimit + 1
particleList.append(lastParticle)
......@@ -58,7 +63,18 @@ class TestBinSorter(unittest.TestCase):
particle.longSize = particle.shortSize = 1000
binIndex = self.sorter._get_binIndex_of_particle(particle)
self.assertEqual(binIndex, 7)
if __name__ == '__main__':
unittest.main()
\ No newline at end of file
class TestOther(unittest.TestCase):
def test_box_contains_contour(self):
boxXY: tuple = 0, 0
boxWidthHeight: tuple = 10, 10
contourPoints = np.array([[[0, 0]], [[5, 5]], [[3, 3]]]) # fully enclosed
self.assertTrue(box_contains_contour(boxXY, boxWidthHeight, contourPoints))
contourPoints = np.array([[[-5, -5]], [[0, 5]], [[-5, -10]]]) # only one point touches border
self.assertTrue(box_contains_contour(boxXY, boxWidthHeight, contourPoints))
contourPoints = np.array([[[-5, -5]], [[-1, 5]], [[-5, -10]]]) # outside the box
self.assertFalse(box_contains_contour(boxXY, boxWidthHeight, contourPoints))
......@@ -16,11 +16,13 @@ from gepard.analysis.particleAndMeasurement import Particle
from methods import IvlevaSubsampling, RandomSampling, SizeBinFractioning
from helpers import ParticleBinSorter
def get_default_particle_container(numParticles=1000):
particleContainer = ParticleContainer(None)
particleContainer.initializeParticles(numParticles)
return particleContainer
class TestIvleva(unittest.TestCase):
def test_get_ivleva_fraction(self):
self.particleContainer = get_default_particle_container()
......@@ -62,7 +64,7 @@ class TestSizeBinFractioning(unittest.TestCase):
self.sizeBinFrac = SizeBinFractioning(None)
sorter = ParticleBinSorter()
sizes = [limit-1 for limit in sorter.bins]
sizes.append(sorter.bins[-1]+1) #the last bin, that goes until infinity
sizes.append(sorter.bins[-1]+1) # the last bin, that goes until infinity
self.numMPparticlesPerBin = 10
self.particles = []
......@@ -84,10 +86,6 @@ class TestSizeBinFractioning(unittest.TestCase):
for subParticles in subParticlesPerBin:
self.assertEqual(len(subParticles), numParticlesPerBinExpected)
if __name__ == '__main__':
unittest.main()
\ No newline at end of file
unittest.main()