Beispiel #1
0
 def test_listyness(self):
     old = range(10)
     new = ObservableList(old)
     
     assert old == new
     
     # Make them differ in first elem
     old[0] = 17
     assert old != new
     
     assert old[3] == new[3]
     
     assert old[3:9:2] == new[3:9:2]
     
     with pytest.raises(IndexError):
         new[17]
     
     # Delete 1st elem, should be the same again
     del new[0]
     del old[0]
     assert old == new
     
     # Check len
     assert len(new) == 9
     assert new.length == 9
     
     new.insert(0, 'foo')
     old.insert(0, 'foo')
     assert old == new
     
     return
Beispiel #2
0
    def test_listyness(self):
        old = range(10)
        new = ObservableList(old)

        assert old == new

        # Make them differ in first elem
        old[0] = 17
        assert old != new

        assert old[3] == new[3]

        assert old[3:9:2] == new[3:9:2]

        with pytest.raises(IndexError):
            new[17]

        # Delete 1st elem, should be the same again
        del new[0]
        del old[0]
        assert old == new

        # Check len
        assert len(new) == 9
        assert new.length == 9

        new.insert(0, 'foo')
        old.insert(0, 'foo')
        assert old == new

        return
Beispiel #3
0
    def test_copy(self):
        import copy
        old = ObservableList(range(3))
        new = copy.copy(old)

        new.append('wibble')

        with pytest.raises(IndexError):
            old[3]
Beispiel #4
0
 def test_observation(self):
     def ResetAll(obs):
         for obPair in obs:
             for ob in obPair:
                 ob.Reset()
         return
 
     def CheckObservers(observers, pattern):
         for obPair, shouldChange in itertools.izip(observers, pattern):
             if shouldChange:
                 for ob in obPair:
                     assert ob.CallTime is not None
                 assert obPair[0].CallTime < obPair[1].CallTime
             else:
                 for ob in obPair:
                     assert ob.CallTime is None
         return
     
     lst = ObservableList()
     
     observers = self.MakeListObservers(lst)
     
     # Add an elem
     lst.append(Circle(4))
     CheckObservers(observers, (True, False, False, True))
     
     # Replace one
     ResetAll(observers)
     lst[0] = 18
     CheckObservers(observers, (False, False, True, False))
     
     # Delete one
     ResetAll(observers)
     del lst[0]
     CheckObservers(observers, (False, True, False, True))
     
     return
Beispiel #5
0
    def test_observation(self):
        def ResetAll(obs):
            for obPair in obs:
                for ob in obPair:
                    ob.Reset()
            return

        def CheckObservers(observers, pattern):
            for obPair, shouldChange in itertools.izip(observers, pattern):
                if shouldChange:
                    for ob in obPair:
                        assert ob.CallTime is not None
                    assert obPair[0].CallTime < obPair[1].CallTime
                else:
                    for ob in obPair:
                        assert ob.CallTime is None
            return

        lst = ObservableList()

        observers = self.MakeListObservers(lst)

        # Add an elem
        lst.append(Circle(4))
        CheckObservers(observers, (True, False, False, True))

        # Replace one
        ResetAll(observers)
        lst[0] = 18
        CheckObservers(observers, (False, False, True, False))

        # Delete one
        ResetAll(observers)
        del lst[0]
        CheckObservers(observers, (False, True, False, True))

        return
Beispiel #6
0
class Profile(Observable):
    """This class represents the parameters necessary to perform a
    setup for HemeLb and supplies the functionality to do it.

    The required parameters are below with defaults and all must be
    specified to actually create the setup files.
    
    """
    # Required parameters and defaults.
    _CloneOrder = ['StlFileUnitId', 'StlFile', 'VoxelSize']
    _Args = {
        'StlFile': None,
        'StlFileUnitId': 1,
        'Iolets': ObservableList(),
        'VoxelSize': 0.,
        'TimeStepSeconds': 1e-4,
        'DurationSeconds': 5.0,
        'SeedPoint': Vector(),
        'OutputGeometryFile': None,
        'OutputXmlFile': None
    }
    _UnitChoices = [metre, millimetre, micrometre]

    def __init__(self, **kwargs):
        """Required arguments may be set here through keyword arguments.
        """
        # Set attributes on this instance according to the keyword
        # args given here or the default dict if they aren't present.
        for a, default in Profile._Args.iteritems():
            setattr(self, a, kwargs.pop(a, copy(default)))
            continue
        # Raise an error on a kwarg we don't understand
        for k in kwargs:
            raise TypeError(
                "__init__() got an unexpected keyword argument '%'" % k)

        # We need a reader to get the polydata
        self.StlReader = vtkSTLReader()

        # And a way to estimate the voxel size
        self.SideLengthCalculator = AverageSideLengthCalculator()
        self.SideLengthCalculator.SetInputConnection(
            self.StlReader.GetOutputPort())

        # Dependencies for properties
        self.AddDependency('HaveValidStlFile', 'StlFile')
        self.AddDependency('HaveValidOutputXmlFile', 'OutputXmlFile')
        self.AddDependency('HaveValidOutputGeometryFile', 'OutputGeometryFile')
        self.AddDependency('HaveValidSeedPoint', 'SeedPoint.x')
        self.AddDependency('HaveValidSeedPoint', 'SeedPoint.y')
        self.AddDependency('HaveValidSeedPoint', 'SeedPoint.z')
        self.AddDependency('IsReadyToGenerate', 'HaveValidStlFile')
        self.AddDependency('IsReadyToGenerate', 'HaveValidOutputXmlFile')
        self.AddDependency('IsReadyToGenerate', 'HaveValidOutputGeometryFile')
        self.AddDependency('IsReadyToGenerate', 'HaveValidSeedPoint')
        self.AddDependency('StlFileUnit', 'StlFileUnitId')
        self.AddDependency('VoxelSizeMetres', 'VoxelSize')
        self.AddDependency('VoxelSizeMetres', 'StlFileUnit.SizeInMetres')

        # When the STL changes, we should reset the voxel size and
        # update the vtkSTLReader.
        self.AddObserver('StlFile', self.OnStlFileChanged)
        return

    def UpdateAttributesBasedOnCmdLineArgs(self, cmdLineArgsDict):
        """ Helper method that takes a dictionary with the arguments provided 
        to the setup tool via command line (cmdLineArgsDict) and sets/updates 
        the relevant class attributes.
        """
        # Some attributes need to be set in a given order to avoid side effects.
        # Set them first
        for attrName in self._CloneOrder:
            if attrName in cmdLineArgsDict:
                val = cmdLineArgsDict[attrName]
                if val is not None:
                    setattr(self, attrName, val)
                    cmdLineArgsDict.pop(attrName)

        # Set the rest
        for k, val in cmdLineArgsDict.iteritems():
            if val is not None:
                setattr(self, k, val)

    def OnStlFileChanged(self, change):
        self.StlReader.SetFileName(self.StlFile)
        self.VoxelSize = self.SideLengthCalculator.GetOutputValue()
        return

    @property
    def HaveValidStlFile(self):
        """Read only property indicating if our STL file is valid.
        """
        return IsFileValid(self.StlFile, ext='.stl', exists=True)

    @property
    def HaveValidSeedPoint(self):
        if np.isfinite(self.SeedPoint.x) and np.isfinite(
                self.SeedPoint.y) and np.isfinite(self.SeedPoint.z):
            return True
        return False

    @property
    def HaveValidOutputXmlFile(self):
        return IsFileValid(self.OutputXmlFile, ext='.xml')

    @property
    def HaveValidOutputGeometryFile(self):
        return IsFileValid(self.OutputGeometryFile, ext='.gmy')

    @property
    def IsReadyToGenerate(self):
        """Read only property indicating if we have enough information
        to do the setup.
        """
        if not self.HaveValidSeedPoint:
            return False
        if not self.HaveValidOutputXmlFile:
            return False
        if not self.HaveValidOutputGeometryFile:
            return False
        if not self.HaveValidStlFile:
            return False
        return True

    @property
    def StlFileUnit(self):
        return self._UnitChoices[self.StlFileUnitId]

    @property
    def VoxelSizeMetres(self):
        return self.VoxelSize * self.StlFileUnit.SizeInMetres

    @VoxelSizeMetres.setter
    def VoxelSizeMetres(self, value):
        self.VoxelSize = value / self.StlFileUnit.SizeInMetres
        return

    def LoadFromFile(self, filename):
        restored = cPickle.Unpickler(file(filename)).load()
        # Now adjust the paths of filenames relative to the Profile file.
        # Note that this will work if an absolute path has been pickled as
        # os.path.join will discard previous path elements when it gets an
        # absolute path. (Of course, this will only work if that path is
        # correct!)
        basePath = os.path.dirname(os.path.abspath(filename))
        restored.StlFile = os.path.abspath(
            os.path.join(basePath, restored.StlFile))
        restored.OutputGeometryFile = os.path.abspath(
            os.path.join(basePath, restored.OutputGeometryFile))
        restored.OutputXmlFile = os.path.abspath(
            os.path.join(basePath, restored.OutputXmlFile))

        self.CloneFrom(restored)
        return

    def Save(self, filename):
        outfile = file(filename, 'w')
        self.BasePath = os.path.dirname(filename)
        try:
            pickler = cPickle.Pickler(outfile, protocol=2)
            pickler.dump(self)
        finally:
            del self.BasePath

        return

    def Generate(self):
        from HemeLbSetupTool.Model.OutputGeneration import PolyDataGenerator
        generator = PolyDataGenerator(self)
        generator.Execute()
        return

    def ResetVoxelSize(self, ignored=None):
        """Action to reset the voxel size to its default value.
        """
        self.VoxelSize = self.SideLengthCalculator.GetOutputValue()
        return

    def __getstate__(self):
        # First, use the superclass's getstate
        state = Observable.__getstate__(self)
        # Now we need to make the paths relative to the directory of the pickle file
        state['StlFile'] = os.path.relpath(self.StlFile, self.BasePath)
        state['OutputXmlFile'] = os.path.relpath(self.OutputXmlFile,
                                                 self.BasePath)
        state['OutputGeometryFile'] = os.path.relpath(self.OutputGeometryFile,
                                                      self.BasePath)
        return state

    pass