def testConstructionFailBasisSites(self): """ Test that construction fails with the wrong basis sites input. """ # Set the input. coordinates = [[0.0, 0.0, 0.0], [1.0, 2.0, 3.0]] elements_before = ["A", "B"] elements_after = ["B", "A"] move_vectors = [(0, [1.0, 2.0, 3.0]), (1, [-1.0, -2.0, -3.0])] basis_sites = ["First"] self.assertRaises( Error, lambda: KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0)) basis_sites = 0 self.assertRaises( Error, lambda: KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0)) basis_sites = [1.0, 2.0] self.assertRaises( Error, lambda: KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, basis_sites=basis_sites, move_vectors=move_vectors, rate_constant=1.0))
def testConstructionFailRate(self): """ Test that construction fails with a wrong rate. """ # Set the input. coordinates = [[0.0, 0.0, 0.0], [1.0, 2.0, 3.0]] elements_before = ["A", "B"] elements_after = ["B", "A"] move_vectors = [(0, [1.0, 2.0, 3.0]), (1, [-1.0, -2.0, -3.0])] basis_sites = [0] # Negative rate. self.assertRaises( Error, lambda: KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=-1.0)) # Integer rate. self.assertRaises( Error, lambda: KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=345)) # Wrong type. self.assertRaises( Error, lambda: KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=[3.459]))
def testLocalConfigurations(self): """ Test that the local configurations are correctly set up """ coordinates = numpy.array([[1.0, 2.0, 3.0], [2.3, 5.5, 3.2]]) elements1 = ["First", "Second"] elements2 = ["Second", "First"] # Construct the process. process = KMCProcess(coordinates, elements1, elements2, basis_sites=[9], rate_constant=1.0) # Get the local configurations out. c1 = process.localConfigurations()[0] c2 = process.localConfigurations()[1] # Construct the two reference local configurations. ref_c1 = KMCLocalConfiguration(coordinates, elements1, center=0) ref_c2 = KMCLocalConfiguration(coordinates, elements2, center=0) # Check coordinates. self.assertAlmostEqual( numpy.linalg.norm(c1.coordinates() - ref_c1.coordinates()), 0.0, 12) self.assertAlmostEqual( numpy.linalg.norm(c2.coordinates() - ref_c2.coordinates()), 0.0, 12) # Check types. self.assertAlmostEqual(c1.types(), ref_c1.types()) self.assertAlmostEqual(c2.types(), ref_c2.types())
def testLocalConfigurations(self): """ Test that the local configurations are correctly set up """ coordinates = numpy.array([[1.0,2.0,3.0], [2.3,5.5,3.2]]) elements1 = ["First", "Second"] elements2 = ["Second", "First"] # Construct the process. process = KMCProcess(coordinates, elements1, elements2, basis_sites=[9], rate_constant=1.0) # Get the local configurations out. c1 = process.localConfigurations()[0] c2 = process.localConfigurations()[1] # Construct the two reference local configurations. ref_c1 = KMCLocalConfiguration(coordinates, elements1, center=0) ref_c2 = KMCLocalConfiguration(coordinates, elements2, center=0) # Check coordinates. self.assertAlmostEqual( numpy.linalg.norm(c1.coordinates() - ref_c1.coordinates()), 0.0, 12 ) self.assertAlmostEqual( numpy.linalg.norm(c2.coordinates() - ref_c2.coordinates()), 0.0, 12 ) # Check types. self.assertAlmostEqual( c1.types(), ref_c1.types() ) self.assertAlmostEqual( c2.types(), ref_c2.types() )
def testConstructionWithCustomRates(self): """ Test construction with custom rates. """ # A first process. coords = [[1.0, 2.0, 3.4], [12.0, 13.0, -1.0], [1.1, 1.2, 1.3]] types0 = ["A", "*", "B"] types1 = ["B", "*", "A"] rate_0_1 = 3.5 process_0 = KMCProcess(coords, types0, types1, basis_sites=[0, 1, 3], rate_constant=rate_0_1) # A second process. coords = [[1.0, 2.0, 3.4], [1.1, 1.2, 1.3]] types0 = ["A", "C"] types1 = ["C", "A"] rate_0_1 = 1.5 process_1 = KMCProcess(coords, types0, types1, basis_sites=[0, 1, 3], rate_constant=rate_0_1) processes = [process_0, process_1] # Test that it fails with the wrong rate calculator. interactions = KMCInteractions(processes=processes, implicit_wildcards=True) # Test that it fails if the rate calculator is of wrong type. self.assertRaises( Error, lambda: interactions.setRateCalculator( rate_calculator="CustomRateCalculator")) # Test that it fails if the rate calculator is instantiated. self.assertRaises( Error, lambda: interactions.setRateCalculator( rate_calculator=CustomRateCalculator("DummyConfig"))) # Construct the interactions object with a custom rate calculator class. kmc_interactions = KMCInteractions(processes=processes, implicit_wildcards=True) kmc_interactions.setRateCalculator( rate_calculator=CustomRateCalculator) # Test the stored name. self.assertEqual( kmc_interactions._KMCInteractions__rate_calculator_str, "CustomRateCalculator") # Test the stored rate calculator class. self.assertTrue( kmc_interactions._KMCInteractions__rate_calculator_class == CustomRateCalculator)
def testBackendNoFailWrongBasisMatch(self): """ Test for no failure when constructing backend with wrong n_basis """ # A first process. coords = [[1.0, 2.0, 3.4], [1.1, 1.2, 1.3]] types0 = ["A", "B"] types1 = ["B", "A"] rate_0_1 = 3.5 process_0 = KMCProcess(coords, types0, types1, basis_sites=[0, 4], rate_constant=rate_0_1) # A second process. types0 = ["A", "C"] types1 = ["C", "A"] rate_0_1 = 1.5 process_1 = KMCProcess(coords, types0, types1, basis_sites=[0, 1], rate_constant=rate_0_1) processes = [process_0, process_1] # Construct the interactions object. kmc_interactions = KMCInteractions(processes=processes) # Setup a dict with the possible types. possible_types = { "A": 13, "D": 2, "B": 3, "J": 4, "C": 5, } # Use a dummy argument for the configuration. config = "DummyConfig" # Get the backend - The [0,4] sites list for process_0 is simply ignored. cpp_interactions = kmc_interactions._backend(possible_types, 2, config) self.assertEqual(len(cpp_interactions.processes()[0].basisSites()), 1) self.assertEqual(cpp_interactions.processes()[0].basisSites()[0], 0) self.assertEqual(len(cpp_interactions.processes()[1].basisSites()), 2) self.assertEqual(cpp_interactions.processes()[1].basisSites()[0], 0) self.assertEqual(cpp_interactions.processes()[1].basisSites()[1], 1)
def testElementsAfter(self): """ Test the elements after query function. """ process = KMCProcess.__new__(KMCProcess) ref = ["123"] process.__elements_after = ref # Check by reference. self.assertTrue( process.__elements_after == ref )
def testElementsBefore(self): """ Test the elements before query function. """ process = KMCProcess.__new__(KMCProcess) ref = ["123"] process.__elements_before = ref # Check by reference. self.assertTrue(process.__elements_before == ref)
def testElementsBefore(self): """ Test the elements before query function. """ process = KMCProcess.__new__(KMCProcess) ref = ["123"] process.__elements_before = ref # Check by reference. self.assertTrue( process.__elements_before == ref )
def testElementsAfter(self): """ Test the elements after query function. """ process = KMCProcess.__new__(KMCProcess) ref = ["123"] process.__elements_after = ref # Check by reference. self.assertTrue(process.__elements_after == ref)
def testConstruction(self): """ Test that the KMCInteractions class can be constructed. """ # A first process. coords = [[1.0, 2.0, 3.4], [12.0, 13.0, -1.0], [1.1, 1.2, 1.3]] types0 = ["A", "*", "B"] types1 = ["B", "*", "A"] rate_0_1 = 3.5 process_0 = KMCProcess(coords, types0, types1, basis_sites=[0, 1, 3], rate_constant=rate_0_1) # A second process. coords = [[1.0, 2.0, 3.4], [1.1, 1.2, 1.3]] types0 = ["A", "C"] types1 = ["C", "A"] rate_0_1 = 1.5 process_1 = KMCProcess(coords, types0, types1, basis_sites=[0, 1, 3], rate_constant=rate_0_1) processes = [process_0, process_1] # Construct the interactions object. kmc_interactions = KMCInteractions(processes=processes) # Check the default implicit wildcard. self.assertTrue(kmc_interactions.implicitWildcards()) # Construct again with non default value. kmc_interactions = KMCInteractions(processes=processes, implicit_wildcards=False) # Check the wildcard again. self.assertFalse(kmc_interactions.implicitWildcards()) # Check the processes stored on the object. stored_processes = kmc_interactions._KMCInteractions__processes # Checks that the address is the same. self.assertTrue(stored_processes == processes)
def testConstructionFailWildcardMove(self): """ Test for failure if wildcards change place in the move. """ # This should fail. coords = [[1.0, 2.0, 3.4], [1.1, 1.2, 1.3]] types0 = ["*", "B"] types1 = ["B", "*"] sites = [0] rate_0_1 = 3.5 self.assertRaises( Error, lambda: KMCProcess(coords, types0, types1, sites, rate_0_1)) # This should fail. coords = [[1.0, 2.0, 3.4], [1.1, 1.2, 1.3]] types0 = ["*", "*"] types1 = ["B", "*"] sites = [0] rate_0_1 = 3.5 self.assertRaises( Error, lambda: KMCProcess(coords, types0, types1, sites, rate_0_1))
def testConstructionFailNoMove(self): """ Test for failure if no move takes place. """ # This should fail. coords = [[1.0, 2.0, 3.4], [1.1, 1.2, 1.3]] types0 = ["A", "B", "*"] types1 = ["A", "B", "*"] sites = [0] rate_0_1 = 3.5 self.assertRaises( Error, lambda: KMCProcess(coords, types0, types1, sites, rate_0_1))
def testConstructionFailNumberOfSites(self): """ Test that construction fails mismatch in the number of sites. """ # Set the input. coordinates = [[0.0, 0.0, 0.0],[1.0,2.0,3.0], [1.2,3.4,5.6]] elements_before = ["A", "B"] elements_after = ["B", "A", "B"] move_vectors = [(0, [1.0,2.0,3.0]), (1, [-1.0,-2.0,-3.0])] basis_sites = [0] self.assertRaises( Error, lambda : KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, basis_sites=basis_sites, move_vectors=move_vectors, rate_constant=1.0) ) elements_before = ["A", "B", "B"] elements_after = ["B", "A"] self.assertRaises( Error, lambda : KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, basis_sites=basis_sites, move_vectors=move_vectors, rate_constant=1.0) ) coordinates = [[0.0, 0.0, 0.0], [1.2,3.4,5.6]] elements_before = ["A", "B", "D"] elements_after = ["B", "A", "B"] basis_sites = [0] self.assertRaises( Error, lambda : KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, basis_sites=basis_sites, move_vectors=move_vectors, rate_constant=1.0) )
def testEqualOperatorUnsorted(self): """ Test the equal operator for unsorted coordinates. """ # Set the first input. coordinates_1 = [[0.0, 0.0, 0.0], [1.0, 3.0, 1.0], [1.0, 2.0, 3.0]] elements_before_1 = ["A", "C", "B"] elements_after_1 = ["B", "C", "A"] move_vectors_1 = [(0, [1.0,2.0,3.0]), (2, [-1.0,-2.0,-3.0])] basis_sites_1 = [0] # Set the second input. coordinates_2 = [[0.0, 0.0, 0.0], [1.0, 2.0, 3.0], [1.0, 3.0, 1.0],] elements_before_2 = ["A", "B", "C"] elements_after_2 = ["B", "A", "C"] move_vectors_2 = [(0, [1.0,2.0,3.0]), (1, [-1.0,-2.0,-3.0])] basis_sites_2 = [0] # Construct. p1 = KMCProcess(coordinates=coordinates_1, elements_before=elements_before_1, elements_after=elements_after_1, move_vectors=move_vectors_1, basis_sites=basis_sites_1, rate_constant=1.0) # Construct. p2 = KMCProcess(coordinates=coordinates_2, elements_before=elements_before_2, elements_after=elements_after_2, move_vectors=move_vectors_2, basis_sites=basis_sites_2, rate_constant=1.0) # These should be equal despite differing order. eq = (p1 == p2) self.assertTrue( eq )
def testConstructionFailsWrongWildcard(self): """ Test that we fail to construct with other than bool input for the implicit wildcard flag """ # A first process. coords = [[1.0, 2.0, 3.4], [12.0, 13.0, -1.0], [1.1, 1.2, 1.3]] types0 = ["A", "*", "B"] types1 = ["B", "*", "A"] rate_0_1 = 3.5 process_0 = KMCProcess(coords, types0, types1, basis_sites=[0, 1, 3], rate_constant=rate_0_1) # A second process. coords = [[1.0, 2.0, 3.4], [1.1, 1.2, 1.3]] types0 = ["A", "C"] types1 = ["C", "A"] rate_0_1 = 1.5 process_1 = KMCProcess(coords, types0, types1, basis_sites=[0, 1, 3], rate_constant=rate_0_1) processes = [process_0, process_1] # Construct and fail. self.assertRaises( Error, lambda: KMCInteractions(processes=processes, implicit_wildcards=0)) self.assertRaises( Error, lambda: KMCInteractions(processes=processes, implicit_wildcards="True")) self.assertRaises( Error, lambda: KMCInteractions(processes=processes, implicit_wildcards=[False]))
def testConstructionFailNoList(self): """ Test that the construction fails if the interactions list is not a list. """ # Setup. coords = [[1.0, 2.0, 3.4], [12.0, 13.0, -1.0], [1.1, 1.2, 1.3]] types0 = ["A", "*", "B"] types1 = ["B", "*", "A"] rate_0_1 = 3.5 process_0 = KMCProcess(coords, types0, types1, basis_sites=[0, 1, 3], rate_constant=rate_0_1) # Construct and fail. self.assertRaises(Error, lambda: KMCInteractions(processes=process_0))
def testConstruction(self): """ Test that the KMCProcess class can be constructed. """ # Set the input. coordinates = [[0.0, 0.0, 0.0], [1.0, 2.0, 3.0]] elements_before = ["A", "B"] elements_after = ["B", "A"] basis_sites = [0] move_vectors = [(0, [1.0, 2.0, 3.0]), (1, [-1.0, -2.0, -3.0])] # Construct. p = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0) # Check that we got a valid instance. self.assertTrue(isinstance(p, KMCProcess))
def testReconstructMoveVectors(self): """ Test that the helper function to reconstruct move vectors works as intended. """ # Get an empty process. process = KMCProcess.__new__(KMCProcess) # Give it coordinate values. coordinates = [[ 0.0, 0.0, 0.0], [ 1.0, 2.0, 3.0], [-1.0, 1.0, 5.0], [ 8.0, 4.0, 7.0]] process._KMCProcess__coordinates = coordinates # Give it element values. process._KMCProcess__elements_before = ["A","B","D","F"] process._KMCProcess__elements_after = ["A","F","D","B"] move_vectors = process._KMCProcess__reconstructMoveVectors() self.assertTrue( move_vectors is not None ) self.assertEqual( len(move_vectors), 2 ) self.assertEqual( move_vectors[0][0], 1 ) self.assertEqual( move_vectors[1][0], 3 ) ref_v1 = numpy.array([ 7., 2., 4.]) norm = numpy.linalg.norm(move_vectors[0][1] - ref_v1) self.assertAlmostEqual( norm, 0.0, 10 ) ref_v2 = numpy.array([-7., -2., -4.]) norm = numpy.linalg.norm(move_vectors[1][1] - ref_v2) self.assertAlmostEqual( norm, 0.0, 10 ) # Give it new element values. process._KMCProcess__elements_before = ["A","B","G","F"] process._KMCProcess__elements_after = ["A","F","D","B"] move_vectors = process._KMCProcess__reconstructMoveVectors() self.assertTrue( move_vectors is None )
def testReconstructMoveVectors(self): """ Test that the helper function to reconstruct move vectors works as intended. """ # Get an empty process. process = KMCProcess.__new__(KMCProcess) # Give it coordinate values. coordinates = [[ 0.0, 0.0, 0.0], [ 1.0, 2.0, 3.0], [-1.0, 1.0, 5.0], [ 8.0, 4.0, 7.0]] process._coordinates = coordinates # Give it element values. process._elements_before = ["A","B","D","F"] process._elements_after = ["A","F","D","B"] move_vectors = process._KMCProcess__reconstructMoveVectors() self.assertTrue( move_vectors is not None ) self.assertEqual( len(move_vectors), 2 ) self.assertEqual( move_vectors[0][0], 1 ) self.assertEqual( move_vectors[1][0], 3 ) ref_v1 = numpy.array([ 7., 2., 4.]) norm = numpy.linalg.norm(move_vectors[0][1] - ref_v1) self.assertAlmostEqual( norm, 0.0, 10 ) ref_v2 = numpy.array([-7., -2., -4.]) norm = numpy.linalg.norm(move_vectors[1][1] - ref_v2) self.assertAlmostEqual( norm, 0.0, 10 ) # Give it new element values. process._elements_before = ["A","B","G","F"] process._elements_after = ["A","F","D","B"] move_vectors = process._KMCProcess__reconstructMoveVectors() self.assertTrue( move_vectors is None )
def testConstructionSorting(self): """ Test that the coordinates elements and move vectors gets sorted """ # Set the input. coordinates = [[0.0, 0.0, 0.0], [3.0, 3.0, 3.0], [1.0, 1.0, 1.0], [1.1, 1.1, 1.1], [1.5, 1.5, 1.5], [2.5, 2.5, 2.5]] elements_before = ["A", "B", "C", "P", "D", "E"] elements_after = ["B", "C", "D", "P", "A", "E"] basis_sites = [0] rate_constant = 1.0 move_vectors = [(0, [ 1.5, 1.5, 1.5]), (1, [-3.0,-3.0,-3.0]), (2, [ 2.0, 2.0, 2.0]), (4, [-0.5,-0.5,-0.5])] # Construct. p = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0) # Get the configurations out. config_before = p.localConfigurations()[0] config_after = p.localConfigurations()[1] # Check that the coordinates, elements and move vectors # have been sorted. ref_coords = numpy.array([[ 0., 0., 0. ], [ 1., 1., 1. ], [ 1.1, 1.1, 1.1], [ 1.5, 1.5, 1.5], [ 2.5, 2.5, 2.5], [ 3., 3., 3.]]) # Before move. coords = config_before.coordinates() norm = numpy.linalg.norm(ref_coords - coords) self.assertAlmostEqual( norm, 0.0, 10 ) # After move. coords = config_after.coordinates() norm = numpy.linalg.norm(ref_coords - coords) self.assertAlmostEqual( norm, 0.0, 10 ) # Check the elements before move. ref_types = [[(1, "A")], [(1, "C")], [(1, "P")], [(1, "D")], [(1, "E")], [(1, "B")]] self.assertEqual( ref_types, config_before.types() ) # Check the elements after move. ref_types = [[(1, "B")], [(1, "D")], [(1, "P")], [(1, "A")], [(1, "E")], [(1, "C")]] self.assertEqual( ref_types, config_after.types() ) ref_vectors = [(0, [ 1.5, 1.5, 1.5]), (1, [ 2.0, 2.0, 2.0]), (3, [-0.5,-0.5,-0.5]), (5, [-3.0,-3.0,-3.0])] ret_vectors = p.moveVectors() for ref, ret in zip(ref_vectors, ret_vectors): # Check the 'from' index. self.assertEqual(ref[0], ret[0]) # Check the vector. norm = numpy.linalg.norm(numpy.array(ref[1]) - numpy.array(ret[1])) self.assertAlmostEqual( norm, 0.0, 10 )
def testEqualOperatorMoveVectors(self): """ Test the equal operator w.r.t. the move vectors. """ # Set the input. coordinates = [[0.0, 0.0, 0.0],[1.0,2.0,3.0]] elements_before = ["A", "B"] elements_after = ["B", "A"] move_vectors = [(0, [1.0,2.0,3.0]), (1, [-1.0,-2.0,-3.0])] basis_sites = [0] # Construct. p1 = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0) # Construct. p2 = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=None, basis_sites=basis_sites, rate_constant=1.0) # The same move vectors should be reconstructed, so there are equal. eq = (p1 == p2) self.assertTrue( eq ) # If se explicitly set the move vectors to empty on p2 they are not equal. p2._move_vectors = [] eq = (p1 == p2) self.assertFalse( eq ) # And the other way around. eq = (p2 == p1) self.assertFalse( eq ) # Now, make the other one empty also. p1._move_vectors = [] eq = (p1 == p2) self.assertTrue( eq ) # Set explicitly to different vectors. p1._move_vectors = move_vectors = [(0, [1.0,2.0,3.0]), (1, [-1.0,-2.0,-3.0])] p2._move_vectors = move_vectors = [(1, [1.0,2.0,3.0]), (0, [-1.0,-2.0,-3.0])] eq = (p1 == p2) self.assertFalse( eq ) # And the vector. p2._move_vectors = move_vectors = [(0, [1.0,2.0,3.0]), (1, [-1.0,-2.1,-3.0])] eq = (p1 == p2) self.assertFalse( eq ) # The length. p2._move_vectors = move_vectors = [(0, [1.0,2.0,3.0]), (1, [-1.0,-2.1,-3.0]), (2, [ 1.0,-2.1,-3.0])] eq = (p1 == p2) self.assertFalse( eq )
def testBackendWithCustomRates(self): """ Test that we can construct the backend object with custom rates. """ # A first process. coords = [[1.0, 2.0, 3.4], [1.1, 1.2, 1.3]] types0 = ["A", "B"] types1 = ["B", "A"] rate_0_1 = 3.5 process_0 = KMCProcess(coords, types0, types1, basis_sites=[0], rate_constant=rate_0_1) # A second process. types0 = ["A", "C"] types1 = ["C", "A"] rate_0_1 = 1.5 process_1 = KMCProcess(coords, types0, types1, basis_sites=[0], rate_constant=rate_0_1) processes = [process_0, process_1] # Set the custom rates class to use. custom_rates_class = CustomRateCalculator # Set the rate function on the custom rates calculator for testing. ref_rnd = numpy.random.uniform(0.0, 1.0) def testRateFunction(obj, coords, types_before, types_after, rate_const, process_number, global_coordinate): return ref_rnd # Store the original. custom_rate_function = custom_rates_class.rate try: custom_rates_class.rate = testRateFunction # Construct the interactions object. kmc_interactions = KMCInteractions(processes=processes, implicit_wildcards=False) # Setup a dict with the possible types. possible_types = { "A": 13, "D": 2, "B": 3, "J": 4, "C": 5, } # Use a dummy argument for the configuration. config = "DummyConfig" # Test that it fails if the rate calculator is of wrong class. kmc_interactions.setRateCalculator(rate_calculator=Error) self.assertRaises( Error, lambda: kmc_interactions._backend(possible_types, 2, config)) # Test that it fails if the rate calculator is the base class. kmc_interactions.setRateCalculator( rate_calculator=KMCRateCalculatorPlugin) self.assertRaises( Error, lambda: kmc_interactions._backend(possible_types, 2, config)) # But this should work. kmc_interactions.setRateCalculator( rate_calculator=custom_rates_class) # Construct the backend. cpp_interactions = kmc_interactions._backend( possible_types, 2, config) # Test that the configuration on the custom rate class is the one given. self.assertTrue( kmc_interactions._KMCInteractions__rate_calculator. configuration == config) # <- Check by reference. # Get the rate calculator reference out of the C++ object and # check that a call from C++ calls the Python extension. cpp_coords = Backend.StdVectorDouble() cpp_types1 = Backend.StdVectorString() cpp_types2 = Backend.StdVectorString() rate_constant = 543.2211 process_number = 33 coordinate = (1.2, 3.4, 5.6) self.assertAlmostEqual( cpp_interactions.rateCalculator().backendRateCallback( cpp_coords, cpp_coords.size() / 3, cpp_types1, cpp_types2, rate_constant, process_number, coordinate[0], coordinate[1], coordinate[2]), ref_rnd, 12) self.assertAlmostEqual( kmc_interactions._KMCInteractions__rate_calculator. backendRateCallback(cpp_coords, cpp_coords.size() / 3, cpp_types1, cpp_types2, rate_constant, process_number, coordinate[0], coordinate[1], coordinate[2]), ref_rnd, 12) finally: # Reset the class. custom_rates_class.rate = custom_rate_function # Construct a C++ RateCalculator object directly and check that this object # returns the rate given to it. cpp_rate_calculator = Backend.RateCalculator() self.assertAlmostEqual( cpp_rate_calculator.backendRateCallback( cpp_coords, cpp_coords.size() / 3, cpp_types1, cpp_types2, rate_constant, process_number, coordinate[0], coordinate[1], coordinate[2]), rate_constant, 12)
def testScript(self): """ Test that the KMCInteractions can generate its own script. """ # A first process. coords = [[1.0, 2.0, 3.4], [1.1, 1.2, 1.3]] types0 = ["A", "B"] types1 = ["B", "A"] rate_0_1 = 3.5 process_0 = KMCProcess(coords, types0, types1, basis_sites=[0], rate_constant=rate_0_1) # A second process. types0 = ["A", "C"] types1 = ["C", "A"] rate_0_1 = 1.5 process_1 = KMCProcess(coords, types0, types1, basis_sites=[0], rate_constant=rate_0_1) processes = [process_0, process_1] # Construct the interactions object. kmc_interactions = KMCInteractions(processes=processes) script = kmc_interactions._script() ref_script = """ # ----------------------------------------------------------------------------- # Interactions coordinates = [[ 0.000000e+00, 0.000000e+00, 0.000000e+00], [ 1.000000e-01, -8.000000e-01, -2.100000e+00]] elements_before = ['A','B'] elements_after = ['B','A'] move_vectors = [( 0,[ 1.000000e-01, -8.000000e-01, -2.100000e+00]), ( 1,[ -1.000000e-01, 8.000000e-01, 2.100000e+00])] basis_sites = [0] rate_constant = 3.500000e+00 process_0 = KMCProcess( coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=rate_constant) coordinates = [[ 0.000000e+00, 0.000000e+00, 0.000000e+00], [ 1.000000e-01, -8.000000e-01, -2.100000e+00]] elements_before = ['A','C'] elements_after = ['C','A'] move_vectors = [( 0,[ 1.000000e-01, -8.000000e-01, -2.100000e+00]), ( 1,[ -1.000000e-01, 8.000000e-01, 2.100000e+00])] basis_sites = [0] rate_constant = 1.500000e+00 process_1 = KMCProcess( coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=rate_constant) processes = [process_0, process_1] interactions = KMCInteractions( processes=processes, implicit_wildcards=True) """ self.assertEqual(script, ref_script) # Get a script with another name and another number of processes. processes = [process_0] kmc_interactions = KMCInteractions(processes=processes, implicit_wildcards=False) script = kmc_interactions._script(variable_name="my_kmc_interactions") ref_script = """ # ----------------------------------------------------------------------------- # Interactions coordinates = [[ 0.000000e+00, 0.000000e+00, 0.000000e+00], [ 1.000000e-01, -8.000000e-01, -2.100000e+00]] elements_before = ['A','B'] elements_after = ['B','A'] move_vectors = [( 0,[ 1.000000e-01, -8.000000e-01, -2.100000e+00]), ( 1,[ -1.000000e-01, 8.000000e-01, 2.100000e+00])] basis_sites = [0] rate_constant = 3.500000e+00 process_0 = KMCProcess( coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=rate_constant) processes = [process_0] my_kmc_interactions = KMCInteractions( processes=processes, implicit_wildcards=False) """ self.assertEqual(script, ref_script)
def testScript(self): """ Test that a script can be created. """ # Setup a unitcell. unit_cell = KMCUnitCell(cell_vectors=numpy.array([[2.8,0.0,0.0], [0.0,3.2,0.0], [0.0,0.5,3.0]]), basis_points=[[0.0,0.0,0.0], [0.5,0.5,0.5], [0.25,0.25,0.75]]) # Setup the lattice. lattice = KMCLattice(unit_cell=unit_cell, repetitions=(4,4,1), periodic=(True,True,False)) types = ['A','A','A','A','B','B', 'A','A','A','B','B','B', 'B','B','A','A','B','A', 'B','B','B','A','B','A', 'B','A','A','A','B','B', 'B','B','B','B','B','B', 'A','A','A','A','B','B', 'B','B','A','B','B','A'] # Setup the configuration. config = KMCConfiguration(lattice=lattice, types=types, possible_types=['A','C','B']) # A first process. coords = [[1.0,2.0,3.4],[1.1,1.2,1.3]] types0 = ["A","B"] types1 = ["B","A"] rate_0_1 = 3.5 process_0 = KMCProcess(coords, types0, types1, basis_sites=[0], rate_constant=rate_0_1) # A second process. types0 = ["A","C"] types1 = ["C","A"] rate_0_1 = 1.5 process_1 = KMCProcess(coords, types0, types1, basis_sites=[0], rate_constant=rate_0_1) # Construct the interactions object. processes = [process_0, process_1] interactions = KMCInteractions(processes) # Construct the model. model = KMCLatticeModel(config, interactions) # Get the script. script = model._script() ref_script = """ # ----------------------------------------------------------------------------- # Unit cell cell_vectors = [[ 2.800000e+00, 0.000000e+00, 0.000000e+00], [ 0.000000e+00, 3.200000e+00, 0.000000e+00], [ 0.000000e+00, 5.000000e-01, 3.000000e+00]] basis_points = [[ 0.000000e+00, 0.000000e+00, 0.000000e+00], [ 5.000000e-01, 5.000000e-01, 5.000000e-01], [ 2.500000e-01, 2.500000e-01, 7.500000e-01]] unit_cell = KMCUnitCell( cell_vectors=cell_vectors, basis_points=basis_points) # ----------------------------------------------------------------------------- # Lattice lattice = KMCLattice( unit_cell=unit_cell, repetitions=(4,4,1), periodic=(True, True, False)) # ----------------------------------------------------------------------------- # Configuration types = ['A','A','A','A','B','B','A','A','A','B','B','B','B', 'B','A','A','B','A','B','B','B','A','B','A','B','A', 'A','A','B','B','B','B','B','B','B','B','A','A','A', 'A','B','B','B','B','A','B','B','A'] possible_types = ['A','C','B'] configuration = KMCConfiguration( lattice=lattice, types=types, possible_types=possible_types) # ----------------------------------------------------------------------------- # Interactions coordinates = [[ 0.000000e+00, 0.000000e+00, 0.000000e+00], [ 1.000000e-01, -8.000000e-01, -2.100000e+00]] elements_before = ['A','B'] elements_after = ['B','A'] move_vectors = [( 0,[ 1.000000e-01, -8.000000e-01, -2.100000e+00]), ( 1,[ -1.000000e-01, 8.000000e-01, 2.100000e+00])] basis_sites = [0] rate_constant = 3.500000e+00 process_0 = KMCProcess( coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=rate_constant) coordinates = [[ 0.000000e+00, 0.000000e+00, 0.000000e+00], [ 1.000000e-01, -8.000000e-01, -2.100000e+00]] elements_before = ['A','C'] elements_after = ['C','A'] move_vectors = [( 0,[ 1.000000e-01, -8.000000e-01, -2.100000e+00]), ( 1,[ -1.000000e-01, 8.000000e-01, 2.100000e+00])] basis_sites = [0] rate_constant = 1.500000e+00 process_1 = KMCProcess( coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=rate_constant) processes = [process_0, process_1] interactions = KMCInteractions( processes=processes, implicit_wildcards=True) # ----------------------------------------------------------------------------- # Lattice model model = KMCLatticeModel( configuration=configuration, interactions=interactions) """ self.assertEqual(script, ref_script) # Get the script again, with a different variable name. script = model._script(variable_name="my_model") ref_script = """ # ----------------------------------------------------------------------------- # Unit cell cell_vectors = [[ 2.800000e+00, 0.000000e+00, 0.000000e+00], [ 0.000000e+00, 3.200000e+00, 0.000000e+00], [ 0.000000e+00, 5.000000e-01, 3.000000e+00]] basis_points = [[ 0.000000e+00, 0.000000e+00, 0.000000e+00], [ 5.000000e-01, 5.000000e-01, 5.000000e-01], [ 2.500000e-01, 2.500000e-01, 7.500000e-01]] unit_cell = KMCUnitCell( cell_vectors=cell_vectors, basis_points=basis_points) # ----------------------------------------------------------------------------- # Lattice lattice = KMCLattice( unit_cell=unit_cell, repetitions=(4,4,1), periodic=(True, True, False)) # ----------------------------------------------------------------------------- # Configuration types = ['A','A','A','A','B','B','A','A','A','B','B','B','B', 'B','A','A','B','A','B','B','B','A','B','A','B','A', 'A','A','B','B','B','B','B','B','B','B','A','A','A', 'A','B','B','B','B','A','B','B','A'] possible_types = ['A','C','B'] configuration = KMCConfiguration( lattice=lattice, types=types, possible_types=possible_types) # ----------------------------------------------------------------------------- # Interactions coordinates = [[ 0.000000e+00, 0.000000e+00, 0.000000e+00], [ 1.000000e-01, -8.000000e-01, -2.100000e+00]] elements_before = ['A','B'] elements_after = ['B','A'] move_vectors = [( 0,[ 1.000000e-01, -8.000000e-01, -2.100000e+00]), ( 1,[ -1.000000e-01, 8.000000e-01, 2.100000e+00])] basis_sites = [0] rate_constant = 3.500000e+00 process_0 = KMCProcess( coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=rate_constant) coordinates = [[ 0.000000e+00, 0.000000e+00, 0.000000e+00], [ 1.000000e-01, -8.000000e-01, -2.100000e+00]] elements_before = ['A','C'] elements_after = ['C','A'] move_vectors = [( 0,[ 1.000000e-01, -8.000000e-01, -2.100000e+00]), ( 1,[ -1.000000e-01, 8.000000e-01, 2.100000e+00])] basis_sites = [0] rate_constant = 1.500000e+00 process_1 = KMCProcess( coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=rate_constant) processes = [process_0, process_1] interactions = KMCInteractions( processes=processes, implicit_wildcards=True) # ----------------------------------------------------------------------------- # Lattice model my_model = KMCLatticeModel( configuration=configuration, interactions=interactions) """ # Check. self.assertEqual(script, ref_script)
def testConstructionFailCoordinates(self): """ Test that construction fails with the wrong coordinates format. """ # Set the input. elements_before = ["A", "B"] elements_after = ["B", "A"] move_vectors = [(0, [1.0, 2.0, 3.0]), (1, [-1.0, -2.0, -3.0])] basis_sites = [0] # Fail on wrong dimension. self.assertRaises( Error, lambda: KMCProcess(coordinates=[[0.0, 0.0], [1.0, 2.0, 3.0]], elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0)) # Fail on wrong dimension. self.assertRaises( Error, lambda: KMCProcess(coordinates=[[0.0, 0.0, 1.3], [2.0, 3.0]], elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0)) # Fail on wrong dimension. self.assertRaises( Error, lambda: KMCProcess(coordinates=[[0.0, 0.0, 1.3, 3.4, 2.0, 3.0]], elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0)) # Fail on wrong type. self.assertRaises( Error, lambda: KMCProcess(coordinates=[[0, 0, 1], [3, 2, 3]], elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0)) # Fail on wrong type. self.assertRaises( Error, lambda: KMCProcess(coordinates="[[0, 0, 1], [3, 2, 3]]", elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0)) # Fail on wrong type. self.assertRaises( Error, lambda: KMCProcess(coordinates=[["0.1", "0.4", "1.3"], ["3.1", "2.1", "3"]], elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0))
def testConstructionFailMoveVectors(self): """ Test that the wrong move vector input gives and error. """ coordinates = [[0.0, 0.0, 0.0], [1.0, 2.0, 3.0]] elements_before = ["A", "B"] elements_after = ["B", "A"] basis_sites = [0] # The move vectors do not match configuration. move_vectors = [(1, [1.0, 2.0, 3.0]), (0, [-1.0, -2.0, -3.0])] self.assertRaises( Error, lambda: KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0)) move_vectors = [(0, [1.1, 2.0, 3.0]), (1, [-1.0, -2.0, -3.0])] self.assertRaises( Error, lambda: KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0)) move_vectors = [(0, [1.0, 2.0, 3.0])] self.assertRaises( Error, lambda: KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0)) # Wrong format. move_vectors = [(0, [0.0])] self.assertRaises( Error, lambda: KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0)) move_vectors = [(0, [1.0, 2.0, 3.0]), (1.2, [-1.0, -2.0, -3.0])] self.assertRaises( Error, lambda: KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0)) move_vectors = "[(0, [1.0,2.0,3.0]),(1, [-1.0,-2.0,-3.0])]" self.assertRaises( Error, lambda: KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0))
def testScript(self): """ Test that the process can generate its own valid script. """ # Set the input. coordinates = [[0.0, 0.0, 0.0], [1.0, 2.0, 3.0]] elements_before = ["A", "B"] elements_after = ["B", "A"] move_vectors = [(0, [1.0, 2.0, 3.0]), (1, [-1.0, -2.0, -3.0])] basis_sites = [0, 1, 4] # Construct with given move vectors. p = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0) # Get the script. script = p._script() ref_script = """coordinates = [[ 0.000000e+00, 0.000000e+00, 0.000000e+00], [ 1.000000e+00, 2.000000e+00, 3.000000e+00]] elements_before = ['A','B'] elements_after = ['B','A'] move_vectors = [( 0,[ 1.000000e+00, 2.000000e+00, 3.000000e+00]), ( 1,[ -1.000000e+00, -2.000000e+00, -3.000000e+00])] basis_sites = [0,1,4] rate_constant = 1.000000e+00 process = KMCProcess( coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=rate_constant) """ # Check. self.assertEqual(ref_script, script) # Construct with default move vectors. p = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, basis_sites=basis_sites, rate_constant=1.0) # Get the script. script = p._script() # The generated script is still the same. self.assertEqual(ref_script, script) # Construct with complicated move and no move vectors. coordinates = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] elements_before = ["A", "B", "C"] elements_after = ["C", "A", "B"] basis_sites = [0, 1, 4] p = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, basis_sites=basis_sites, rate_constant=1.0) # Get the script. script = p._script() ref_script = """coordinates = [[ 0.000000e+00, 0.000000e+00, 0.000000e+00], [ 1.000000e+00, 0.000000e+00, 0.000000e+00], [ 0.000000e+00, 1.000000e+00, 0.000000e+00]] elements_before = ['A','B','C'] elements_after = ['C','A','B'] move_vectors = None basis_sites = [0,1,4] rate_constant = 1.000000e+00 process = KMCProcess( coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=rate_constant) """ self.assertEqual(script, ref_script)
def testCalculationNonOrthogonal(self): """ Test a calculation with the on-the-fly MSD analysis. """ # Setup a system, a periodic 10 atoms long 1D chain. unit_cell = KMCUnitCell(cell_vectors=numpy.array([[2.0,1.0,0.0], [0.0,1.0,0.0], [0.0,2.0,1.0]]), basis_points=[[0.0,0.0,0.0]]) # And a lattice. lattice = KMCLattice(unit_cell=unit_cell, repetitions=(10,10,10), periodic=(True,True,True)) # Setup an initial configuration with one B in a sea of A:s. types = ["A"]*10*10*10 types[5] = "B" config = KMCConfiguration(lattice=lattice, types=types, possible_types=["A","B"]) # Setup a diffusion process to the left. coordinates_p0 = [[0.0, 0.0, 0.0],[-1.0, 0.0, 0.0]] p0 = KMCProcess(coordinates=coordinates_p0, elements_before=["B","A"], elements_after=["A","B"], move_vectors=None, basis_sites=[0], rate_constant=1.0) coordinates_p1 = [[0.0, 0.0, 0.0],[1.0, 0.0, 0.0]] p1 = KMCProcess(coordinates=coordinates_p1, elements_before=["B","A"], elements_after=["A","B"], move_vectors=None, basis_sites=[0], rate_constant=1.0) coordinates_p2 = [[0.0, 0.0, 0.0],[0.0,-1.0, 0.0]] p2 = KMCProcess(coordinates=coordinates_p2, elements_before=["B","A"], elements_after=["A","B"], move_vectors=None, basis_sites=[0], rate_constant=1.0) coordinates_p3 = [[0.0, 0.0, 0.0],[0.0, 1.0, 0.0]] p3 = KMCProcess(coordinates=coordinates_p3, elements_before=["B","A"], elements_after=["A","B"], move_vectors=None, basis_sites=[0], rate_constant=1.0) coordinates_p4 = [[0.0, 0.0, 0.0],[0.0, 0.0,-1.0]] p4 = KMCProcess(coordinates=coordinates_p4, elements_before=["B","A"], elements_after=["A","B"], move_vectors=None, basis_sites=[0], rate_constant=1.0) coordinates_p5 = [[0.0, 0.0, 0.0],[0.0, 0.0, 1.0]] p5 = KMCProcess(coordinates=coordinates_p5, elements_before=["B","A"], elements_after=["A","B"], move_vectors=None, basis_sites=[0], rate_constant=1.0) interactions = KMCInteractions(processes=[p0, p1, p2, p3, p4, p5], implicit_wildcards=True) model = KMCLatticeModel(configuration=config, interactions=interactions) # Setup the analysis. msd = OnTheFlyMSD(history_steps=400, n_bins=10, t_max=25.0, track_type="B") # Setup the control parameters. control_parameters = KMCControlParameters(number_of_steps=4000, dump_interval=100, analysis_interval=1, seed=2013) # Run the model. model.run(control_parameters=control_parameters, analysis=[msd]) # Get the results out. results = msd.results() time_steps = msd.timeSteps() std_dev = msd.stdDev() bin_counters = msd.binCounters() # Compare against references. ref_results = numpy.array([[ 11.10849324 , 32.89332622 , 56.86314552 , 84.47799379 , 110.30394149, 135.26081658, 162.25612518, 189.40268295, 219.32538873, 252.00244119], [ 17.33153679 , 50.69982999 , 82.74958435 , 111.33382274 , 136.44824258, 164.84499628, 193.94367236, 234.25340515, 272.64453361, 302.94924061], [ 2.98786918 , 8.65022668 , 14.01808716 , 18.62678885 , 22.65708384, 26.03107861, 30.03937616, 35.1483 , 40.68319007, 47.21074474], [ 28.44003004 , 83.59315621 , 139.61272987 , 195.81181652 , 246.75218407, 300.10581285, 356.19979754, 423.65608811, 491.96992234, 554.95168181], [ 14.09636242 , 41.5435529 , 70.88123268 , 103.10478264 , 132.96102533, 161.29189519, 192.29550134, 224.55098295, 260.00857879, 299.21318593], [ 20.31940597 , 59.35005667 , 96.76767151 , 129.96061158 , 159.10532643, 190.87607489, 223.98304852, 269.40170515, 313.32772368, 350.15998535], [ 31.42789922 , 92.24338289 , 153.63081703 , 214.43860537 , 269.40926791, 326.13689146, 386.2391737 , 458.8043881 , 532.65311241, 602.16242655]]) diff = numpy.linalg.norm(ref_results - results) self.assertAlmostEqual(diff, 0.0, 6) ref_time_steps = numpy.array([ 1.25, 3.75, 6.25, 8.75, 11.25, 13.75, 16.25, 18.75, 21.25, 23.75]) diff = numpy.linalg.norm(ref_time_steps - time_steps) self.assertAlmostEqual(diff, 0.0, 8) ref_std_dev = numpy.array([[ 0.59348826 , 2.92235801 , 6.47651272 , 11.36067446 , 16.79740936, 22.78018427, 29.72954492, 37.27728411, 45.97782684, 55.88661276], [ 0.92596389 , 4.50435001 , 9.42488725 , 14.97226982 , 20.7787406, 27.76265504, 35.53552825, 46.10457783, 57.15527613, 67.18509081], [ 0.15963149 , 0.76851636 , 1.59661093 , 2.50494685 , 3.45028752, 4.38406911 , 5.5039955 , 6.91771175 , 8.52853689 , 10.46993274], [ 1.07441492 , 5.2514756 , 11.24398775 , 18.62020347 , 26.57035045, 35.73918442, 46.14937581, 58.95988 , 72.92611647, 87.02483617], [ 0.53253608 , 2.60984229 , 5.70856048 , 9.80447485 , 14.31728377, 19.20802777, 24.91387536, 31.25058126, 38.54181941, 46.9211633 ], [ 0.76763185 , 3.72847956 , 7.7933761 , 12.35825842 , 17.13251009, 22.73116664, 29.01932554, 37.49242051, 46.4454696 , 54.91039375], [ 0.96941939 , 4.731515 , 10.1024813 , 16.6495642 , 23.68662473, 31.71206536, 40.85854085, 52.13448317, 64.46787783, 77.10029967]]) diff = numpy.linalg.norm(ref_std_dev - std_dev) self.assertAlmostEqual(diff, 0.0, 6) ref_bin_counters = (59930, 59996, 59545, 59256, 59064, 59076, 58284, 58294, 57817, 57349) self.assertEqual(bin_counters, ref_bin_counters)
def testBackend(self): """ Test that the generated backend object is what we expect. """ # A first process. coords = [[1.0, 2.0, 3.4], [12.0, 13.0, -1.0], [1.1, 1.2, 1.3]] types0 = ["A", "D", "B"] types1 = ["B", "F", "A"] rate_0_1 = 3.5 process_0 = KMCProcess(coords, types0, types1, basis_sites=[0, 1, 3], rate_constant=rate_0_1) # A second process. coords = [[1.0, 2.0, 3.4], [1.1, 1.2, 1.3]] types0 = ["A", "C"] types1 = ["C", "A"] rate_0_1 = 1.5 process_1 = KMCProcess(coords, types0, types1, basis_sites=[0, 1, 3], rate_constant=rate_0_1) processes = [process_0, process_1] # Construct the interactions object. kmc_interactions = KMCInteractions(processes=processes) # Setup a dict with the possible types. possible_types = { "A": 13, "B": 3, "J": 4, "C": 5, } # Use a dummy argument for the configuration. config = "DummyConfig" # Check that setting up the backend fails if we have types in the processes that do # not corresponds to a type in the list of possible types. self.assertRaises( Error, lambda: kmc_interactions._backend(possible_types, 2, config)) possible_types = { "A": 13, "B": 3, "D": 2, "J": 4, "C": 5, } self.assertRaises( Error, lambda: kmc_interactions._backend(possible_types, 2, config)) possible_types = { "A": 13, "B": 3, "F": 2, "J": 4, "C": 5, } self.assertRaises( Error, lambda: kmc_interactions._backend(possible_types, 2, config)) # Both "D" and "F" must be present. possible_types["D"] = 123 # Get the backend. cpp_interactions = kmc_interactions._backend(possible_types, 2, config) # Check the type. self.assertTrue(isinstance(cpp_interactions, Backend.Interactions)) # Get the processes out. cpp_processes = cpp_interactions.processes() # Check the length of the processes. self.assertEqual(cpp_processes.size(), 2) # Get the elements out of the second process. match_types = cpp_processes[1].processMatchList()[0].match_types update_types = cpp_processes[1].processMatchList()[0].update_types # Match type should be "A" -> 15 and update type "C" -> 5 self.assertEqual(match_types[13], 1) self.assertEqual(update_types[5], 1) # Get the elements out of the second process. match_types = cpp_processes[1].processMatchList()[1].match_types update_types = cpp_processes[1].processMatchList()[1].update_types # Match type should be "C" -> 5 and update type "A" -> 13 self.assertEqual(match_types[5], 1) self.assertEqual(update_types[13], 1)
def testConstructionSorting(self): """ Test that the coordinates elements and move vectors gets sorted """ # Set the input. coordinates = [[0.0, 0.0, 0.0], [3.0, 3.0, 3.0], [1.0, 1.0, 1.0], [1.1, 1.1, 1.1], [1.5, 1.5, 1.5], [2.5, 2.5, 2.5]] elements_before = ["A", "B", "C", "P", "D", "E"] elements_after = ["B", "C", "D", "P", "A", "E"] basis_sites = [0] rate_constant = 1.0 move_vectors = [(0, [1.5, 1.5, 1.5]), (1, [-3.0, -3.0, -3.0]), (2, [2.0, 2.0, 2.0]), (4, [-0.5, -0.5, -0.5])] # Construct. p = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0) # Get the configurations out. config_before = p.localConfigurations()[0] config_after = p.localConfigurations()[1] # Check that the coordinates, elements and move vectors # have been sorted. ref_coords = numpy.array([[0., 0., 0.], [1., 1., 1.], [1.1, 1.1, 1.1], [1.5, 1.5, 1.5], [2.5, 2.5, 2.5], [3., 3., 3.]]) # Before move. coords = config_before.coordinates() norm = numpy.linalg.norm(ref_coords - coords) self.assertAlmostEqual(norm, 0.0, 10) # After move. coords = config_after.coordinates() norm = numpy.linalg.norm(ref_coords - coords) self.assertAlmostEqual(norm, 0.0, 10) # Check the elements before move. ref_types = [[(1, "A")], [(1, "C")], [(1, "P")], [(1, "D")], [(1, "E")], [(1, "B")]] self.assertEqual(ref_types, config_before.types()) # Check the elements after move. ref_types = [[(1, "B")], [(1, "D")], [(1, "P")], [(1, "A")], [(1, "E")], [(1, "C")]] self.assertEqual(ref_types, config_after.types()) ref_vectors = [(0, [1.5, 1.5, 1.5]), (1, [2.0, 2.0, 2.0]), (3, [-0.5, -0.5, -0.5]), (5, [-3.0, -3.0, -3.0])] ret_vectors = p.moveVectors() for ref, ret in zip(ref_vectors, ret_vectors): # Check the 'from' index. self.assertEqual(ref[0], ret[0]) # Check the vector. norm = numpy.linalg.norm(numpy.array(ref[1]) - numpy.array(ret[1])) self.assertAlmostEqual(norm, 0.0, 10)
def testScript(self): """ Test that the process can generate its own valid script. """ # Set the input. coordinates = [[0.0, 0.0, 0.0],[1.0,2.0,3.0]] elements_before = ["A", "B"] elements_after = ["B", "A"] move_vectors = [(0, [1.0, 2.0, 3.0]), (1, [-1.0, -2.0, -3.0])] basis_sites = [0, 1, 4] # Construct with given move vectors. p = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0) # Get the script. script = p._script() ref_script = """coordinates = [[ 0.000000e+00, 0.000000e+00, 0.000000e+00], [ 1.000000e+00, 2.000000e+00, 3.000000e+00]] elements_before = ['A','B'] elements_after = ['B','A'] move_vectors = [( 0,[ 1.000000e+00, 2.000000e+00, 3.000000e+00]), ( 1,[ -1.000000e+00, -2.000000e+00, -3.000000e+00])] basis_sites = [0,1,4] rate_constant = 1.000000e+00 process = KMCProcess( coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=rate_constant) """ # Check. self.assertEqual(ref_script, script) # Construct with default move vectors. p = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, basis_sites=basis_sites, rate_constant=1.0) # Get the script. script = p._script() # The generated script is still the same. self.assertEqual(ref_script, script) # Construct with complicated move and no move vectors. coordinates = [[0.0, 0.0, 0.0],[1.0,0.0,0.0], [0.0,1.0,0.0]] elements_before = ["A", "B", "C"] elements_after = ["C", "A", "B"] basis_sites = [0, 1, 4] p = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, basis_sites=basis_sites, rate_constant=1.0) # Get the script. script = p._script() ref_script = """coordinates = [[ 0.000000e+00, 0.000000e+00, 0.000000e+00], [ 1.000000e+00, 0.000000e+00, 0.000000e+00], [ 0.000000e+00, 1.000000e+00, 0.000000e+00]] elements_before = ['A','B','C'] elements_after = ['C','A','B'] move_vectors = None basis_sites = [0,1,4] rate_constant = 1.000000e+00 process = KMCProcess( coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=rate_constant) """ self.assertEqual(script, ref_script)
def testEqualOperator(self): """ Test the equal operator. """ # Set the input. coordinates = [[0.0, 0.0, 0.0], [1.0, 2.0, 3.0]] elements_before = ["A", "B"] elements_after = ["B", "A"] move_vectors = [(0, [1.0, 2.0, 3.0]), (1, [-1.0, -2.0, -3.0])] basis_sites = [0] # Construct. p1 = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0) # Construct. p2 = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0) # Check. eq = (p1 == p2) self.assertTrue(eq) # Set the input again, different coordinates. coordinates = [[0.0, 0.0, 0.0], [1.0, 2.0, 3.0001]] move_vectors = [(0, [1.0, 2.0, 3.0001]), (1, [-1.0, -2.0, -3.0001])] # Construct. p3 = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0) # Check. eq = (p1 == p3) self.assertFalse(eq) # Set the input again, different length. coordinates = [[0.0, 0.0, 0.0], [1.0, 2.0, 3.], [1.0, 2.0, 3.0]] elements_before = ["A", "B", "C"] elements_after = ["B", "A", "A"] basis_sites = [0] move_vectors = None # Construct. p4 = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0) # Check. eq = (p1 == p4) self.assertFalse(eq) # Set the input again, different basis sites. coordinates = [[0.0, 0.0, 0.0], [1.0, 2.0, 3.]] elements_before = ["A", "B"] elements_after = ["B", "A"] basis_sites = [1] # Construct. p5 = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0) # Check. eq = (p1 == p5) self.assertFalse(eq) # Set the input again, different length of the basis sites. coordinates = [[0.0, 0.0, 0.0], [1.0, 2.0, 3.]] elements_before = ["A", "B"] elements_after = ["B", "A"] basis_sites = [0, 2] # Construct. p6 = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0) # Check. eq = (p1 == p6) self.assertFalse(eq) # Set the input again, different elements before. coordinates = [[0.0, 0.0, 0.0], [1.0, 2.0, 3.]] elements_before = ["A", "D"] elements_after = ["B", "A"] basis_sites = [0] # Construct. p7 = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0) # Check. eq = (p1 == p7) self.assertFalse(eq) # Set the input again, different elements after. coordinates = [[0.0, 0.0, 0.0], [1.0, 2.0, 3.]] elements_before = ["A", "B"] elements_after = ["D", "A"] basis_sites = [0] # Construct. p7 = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0) # Check. eq = (p1 == p7) self.assertFalse(eq)
def testCalculation(self): """ Test a calculation with the on-the-fly MSD analysis. """ # Setup a system, a periodic 10 atoms long 1D chain. unit_cell = KMCUnitCell(cell_vectors=numpy.array([[1.0,0.0,0.0], [0.0,1.0,0.0], [0.0,0.0,1.0]]), basis_points=[[0.0,0.0,0.0]]) # And a lattice. lattice = KMCLattice(unit_cell=unit_cell, repetitions=(10,10,10), periodic=(True,True,True)) # Setup an initial configuration with one B in a sea of A:s. types = ["A"]*10*10*10 types[5] = "B" config = KMCConfiguration(lattice=lattice, types=types, possible_types=["A","B"]) # Setup a diffusion process to the left. coordinates_p0 = [[0.0, 0.0, 0.0],[-1.0, 0.0, 0.0]] p0 = KMCProcess(coordinates=coordinates_p0, elements_before=["B","A"], elements_after=["A","B"], move_vectors=None, basis_sites=[0], rate_constant=1.0) coordinates_p1 = [[0.0, 0.0, 0.0],[1.0, 0.0, 0.0]] p1 = KMCProcess(coordinates=coordinates_p1, elements_before=["B","A"], elements_after=["A","B"], move_vectors=None, basis_sites=[0], rate_constant=1.0) coordinates_p2 = [[0.0, 0.0, 0.0],[0.0,-1.0, 0.0]] p2 = KMCProcess(coordinates=coordinates_p2, elements_before=["B","A"], elements_after=["A","B"], move_vectors=None, basis_sites=[0], rate_constant=1.0) coordinates_p3 = [[0.0, 0.0, 0.0],[0.0, 1.0, 0.0]] p3 = KMCProcess(coordinates=coordinates_p3, elements_before=["B","A"], elements_after=["A","B"], move_vectors=None, basis_sites=[0], rate_constant=1.0) coordinates_p4 = [[0.0, 0.0, 0.0],[0.0, 0.0,-1.0]] p4 = KMCProcess(coordinates=coordinates_p4, elements_before=["B","A"], elements_after=["A","B"], move_vectors=None, basis_sites=[0], rate_constant=1.0) coordinates_p5 = [[0.0, 0.0, 0.0],[0.0, 0.0, 1.0]] p5 = KMCProcess(coordinates=coordinates_p5, elements_before=["B","A"], elements_after=["A","B"], move_vectors=None, basis_sites=[0], rate_constant=1.0) interactions = KMCInteractions(processes=[p0, p1, p2, p3, p4, p5], implicit_wildcards=True) model = KMCLatticeModel(configuration=config, interactions=interactions) # Setup the analysis. msd = OnTheFlyMSD(history_steps=400, n_bins=10, t_max=25.0, track_type="B") # Setup the control parameters. control_parameters = KMCControlParameters(number_of_steps=4000, dump_interval=100, analysis_interval=1, seed=2013) # Run the model. model.run(control_parameters=control_parameters, analysis=[msd]) # Get the results out. results = msd.results() time_steps = msd.timeSteps() std_dev = msd.stdDev() bin_counters = msd.binCounters() # Compare against references. ref_results = numpy.array([[ 2.77712331 , 8.22333156 , 14.21578638 , 21.11949845 , 27.57598537, 33.81520414, 40.5640313 , 47.35067074, 54.83134718, 63.0006103 ], [ 2.80810946 , 8.48503234 , 13.7997313 , 17.62812205 , 22.37202018, 29.12157221, 35.40750463, 41.44944591, 48.94392653, 56.67111894], [ 2.98786918 , 8.65022668 , 14.01808716 , 18.62678885 , 22.65708384, 26.03107861, 30.03937616, 35.1483 , 40.68319007, 47.21074474], [ 5.58523277 , 16.70836389 , 28.01551768 , 38.74762049 , 49.94800555, 62.93677636, 75.97153593, 88.80011665, 103.77527371, 119.67172924], [ 5.76499249 , 16.87355824 , 28.23387354 , 39.7462873 , 50.23306921, 59.84628275, 70.60340745, 82.49897073, 95.51453725, 110.21135504], [ 5.79597864 , 17.13525902 , 27.81781846 , 36.2549109 , 45.02910402, 55.15265082, 65.44688079, 76.59774591, 89.62711659, 103.88186368], [ 8.57310195 , 25.35859057 , 42.03360484 , 57.37440934 , 72.60508939, 88.96785497, 106.01091209, 123.94841665, 144.45846377, 166.88247398]]) diff = numpy.linalg.norm(ref_results - results) self.assertAlmostEqual(diff, 0.0, 6) ref_time_steps = numpy.array([ 1.25, 3.75, 6.25, 8.75, 11.25, 13.75, 16.25, 18.75, 21.25, 23.75]) diff = numpy.linalg.norm(ref_time_steps - time_steps) self.assertAlmostEqual(diff, 0.0, 8) ref_std_dev = numpy.array( [[ 0.14837207, 0.7305895 , 1.61912818, 2.84016862, 4.19935234, 5.69504607, 7.43238623, 9.31932103, 11.49445671, 13.97165319], [ 0.15002755, 0.75383991, 1.57174096, 2.37064526, 3.40687718, 4.90455993, 6.48757634, 8.15787162, 10.26025939, 12.5679611 ], [ 0.15963149, 0.76851636, 1.59661093, 2.50494685, 3.45028752, 4.38406911, 5.5039955 , 6.91771175, 8.52853689, 10.46993274], [ 0.21100039, 1.04965011, 2.25628521, 3.68460183, 5.37841647, 7.49505328, 9.84289993, 12.35824143, 15.38290727, 18.76634124], [ 0.2177914 , 1.06002792, 2.27387093, 3.77956739, 5.40911222, 7.12701069, 9.14740325, 11.48131598, 14.15839455, 17.28281115], [ 0.218962 , 1.07646844, 2.24036311, 3.44756425, 4.84874766, 6.56805258, 8.47932177, 10.66004723, 13.28568526, 16.29025096], [ 0.26444438, 1.30073885, 2.76405291, 4.45469653, 6.38348309, 8.65082886, 11.21442742, 14.08440462, 17.48404426, 21.36747194]]) diff = numpy.linalg.norm(ref_std_dev - std_dev) self.assertAlmostEqual(diff, 0.0, 6) ref_bin_counters = (59930, 59996, 59545, 59256, 59064, 59076, 58284, 58294, 57817, 57349) self.assertEqual(bin_counters, ref_bin_counters)
def testBackend(self): """ Test that the backend object is correctly constructed. """ # Setup a unitcell. unit_cell = KMCUnitCell(cell_vectors=numpy.array([[2.8,0.0,0.0], [0.0,3.2,0.0], [0.0,0.5,3.0]]), basis_points=[[0.0,0.0,0.0], [0.5,0.5,0.5], [0.25,0.25,0.75]]) # Setup the lattice. lattice = KMCLattice(unit_cell=unit_cell, repetitions=(4,4,1), periodic=(True,True,False)) types = ['A','A','A','A','B','B', 'A','A','A','B','B','B', 'B','B','A','A','B','A', 'B','B','B','A','B','A', 'B','A','A','A','B','B', 'B','B','B','B','B','B', 'A','A','A','A','B','B', 'B','B','A','B','B','A'] # Setup the configuration. config = KMCConfiguration(lattice=lattice, types=types, possible_types=['A','C','B']) # A first process. coords = [[1.0,2.0,3.4],[1.1,1.2,1.3]] types0 = ["A","B"] types1 = ["B","A"] sites = [0,1,2,3,4] rate_0_1 = 3.5 process_0 = KMCProcess(coords, types0, types1, basis_sites=sites, rate_constant=rate_0_1) # A second process. types0 = ["A","C"] types1 = ["C","A"] rate_0_1 = 1.5 process_1 = KMCProcess(coords, types0, types1, basis_sites=sites, rate_constant=rate_0_1) # Construct the interactions object. processes = [process_0, process_1] interactions = KMCInteractions(processes=processes) # Construct the model. model = KMCLatticeModel(config, interactions) # Get the c++ backend out. cpp_model = model._backend() # Check that this backend object is stored on the class. self.assertTrue(model._KMCLatticeModel__backend == cpp_model)
def testEqualOperatorMoveVectors(self): """ Test the equal operator w.r.t. the move vectors. """ # Set the input. coordinates = [[0.0, 0.0, 0.0], [1.0, 2.0, 3.0]] elements_before = ["A", "B"] elements_after = ["B", "A"] move_vectors = [(0, [1.0, 2.0, 3.0]), (1, [-1.0, -2.0, -3.0])] basis_sites = [0] # Construct. p1 = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=move_vectors, basis_sites=basis_sites, rate_constant=1.0) # Construct. p2 = KMCProcess(coordinates=coordinates, elements_before=elements_before, elements_after=elements_after, move_vectors=None, basis_sites=basis_sites, rate_constant=1.0) # The same move vectors should be reconstructed, so there are equal. eq = (p1 == p2) self.assertTrue(eq) # If se explicitly set the move vectors to empty on p2 they are not equal. p2._move_vectors = [] eq = (p1 == p2) self.assertFalse(eq) # And the other way around. eq = (p2 == p1) self.assertFalse(eq) # Now, make the other one empty also. p1._move_vectors = [] eq = (p1 == p2) self.assertTrue(eq) # Set explicitly to different vectors. p1._move_vectors = move_vectors = [(0, [1.0, 2.0, 3.0]), (1, [-1.0, -2.0, -3.0])] p2._move_vectors = move_vectors = [(1, [1.0, 2.0, 3.0]), (0, [-1.0, -2.0, -3.0])] eq = (p1 == p2) self.assertFalse(eq) # And the vector. p2._move_vectors = move_vectors = [(0, [1.0, 2.0, 3.0]), (1, [-1.0, -2.1, -3.0])] eq = (p1 == p2) self.assertFalse(eq) # The length. p2._move_vectors = move_vectors = [(0, [1.0, 2.0, 3.0]), (1, [-1.0, -2.1, -3.0]), (2, [1.0, -2.1, -3.0])] eq = (p1 == p2) self.assertFalse(eq)
def testRunRngTypeDevice(self): """ Test to use the PRNG DEVICE. """ # Cell. cell_vectors = [[ 1.000000e+00, 0.000000e+00, 0.000000e+00], [ 0.000000e+00, 1.000000e+00, 0.000000e+00], [ 0.000000e+00, 0.000000e+00, 1.000000e+00]] basis_points = [[ 0.000000e+00, 0.000000e+00, 0.000000e+00]] unit_cell = KMCUnitCell( cell_vectors=cell_vectors, basis_points=basis_points) # Lattice. lattice = KMCLattice( unit_cell=unit_cell, repetitions=(4,4,1), periodic=(True, True, False)) # Configuration. types = ['B']*16 possible_types = ['A','B'] configuration = KMCConfiguration( lattice=lattice, types=types, possible_types=possible_types) # Interactions. coordinates = [[ 0.000000e+00, 0.000000e+00, 0.000000e+00]] process_0 = KMCProcess(coordinates, ['A'], ['B'], basis_sites=[0], rate_constant=4.0) process_1 = KMCProcess(coordinates, ['B'], ['A'], basis_sites=[0], rate_constant=1.0) processes = [process_0, process_1] interactions = KMCInteractions(processes) # Setup the model. ab_flip_model_DEVICE = KMCLatticeModel(configuration, interactions) support_device = False if (not support_device): # If DEVICE is not supported on your system this is the test you should run. self.assertRaises( Error, lambda: ab_flip_model_DEVICE.run(KMCControlParameters(number_of_steps=10000, dump_interval=5000, seed=2013, rng_type="DEVICE"))) else: # If DEVICE is supported the aboove test will fail, and you should run this tests instead. # Run the model for 10000 steps with DEVICE. ab_flip_model_DEVICE.run(KMCControlParameters(number_of_steps=10000, dump_interval=5000, seed=2013, rng_type="DEVICE")) # Get the simulation time out. t_DEVICE = ab_flip_model_DEVICE._KMCLatticeModel__cpp_timer.simulationTime() self.assertTrue(t_DEVICE < 410.0 and t_DEVICE > 370.0)