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 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 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 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 testCustomRatesRun(self): """ Test the run of an A-B flip model with custom rates. """ # 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=(10,10,1), periodic=(True, True, False)) # Configuration. types = ['B']*100 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'], None, [0], 4.0) process_1 = KMCProcess(coordinates, ['B'], ['A'], None, [0], 1.0) processes = [process_0, process_1] interactions = KMCInteractions(processes, implicit_wildcards=True) # Custom rates. rate_calculator = CustomRateCalculator interactions.setRateCalculator(rate_calculator) # Setup the model. ab_flip_model = KMCLatticeModel(configuration, interactions) # Run the model with a trajectory file. name = os.path.abspath(os.path.dirname(__file__)) name = os.path.join(name, "..", "TestUtilities", "Scratch") trajectory_filename = os.path.join(name, "ab_flip_traj_custom.py") self.__files_to_remove.append(trajectory_filename) # The control parameters. control_parameters = KMCControlParameters(number_of_steps=1000, dump_interval=500, seed=2013) # Run the model for 1000 steps. ab_flip_model.run(control_parameters, trajectory_filename=trajectory_filename) # Read the first last frames from the trajectory file and check that # the fraction of A is close to 75% in the last, and 0 in the first. if MPICommons.isMaster(): global_dict = {} local_dict = {} execfile(trajectory_filename, global_dict, local_dict) # Count the first frame. elem = local_dict["types"][0] nA = len([ ee for ee in elem if ee == "A" ]) nB = len([ ee for ee in elem if ee == "B" ]) self.assertEqual(nA, 0) self.assertEqual(nB, 100) # Count the last frame. elem = local_dict["types"][-1] nA = len([ ee for ee in elem if ee == "A" ]) nB = len([ ee for ee in elem if ee == "B" ]) # Note that the average over a long simulation should be # 75% A using the modified rate function. In this particular # step the A population is 74%. value = 1.0 * nA / (nA + nB) self.assertAlmostEqual(0.74, value, 2)
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 # Construct the interactions object. kmc_interactions = KMCInteractions(processes=processes, implicit_wildcards=False) kmc_interactions.setRateCalculator(rate_calculator=custom_rates_class) # Set the rate function on the custom rates calculator for testing. ref_rnd = numpy.random.uniform(0.0,1.0) def testRateFunction(coords, types_before, types_after, rate_const, process_number, global_coordinate): return ref_rnd kmc_interactions._KMCInteractions__rate_calculator.rate = testRateFunction # Setup a dict with the possible types. possible_types = { "A" : 13, "D" : 2, "B" : 3, "J" : 4, "C" : 5, } # Construct the backend. cpp_interactions = kmc_interactions._backend(possible_types, 2) # 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 ) # 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 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 # Construct the interactions object. kmc_interactions = KMCInteractions(processes=processes, implicit_wildcards=False) kmc_interactions.setRateCalculator(rate_calculator=custom_rates_class) # Set the rate function on the custom rates calculator for testing. ref_rnd = numpy.random.uniform(0.0, 1.0) def testRateFunction(coords, types_before, types_after, rate_const, process_number, global_coordinate): return ref_rnd kmc_interactions._KMCInteractions__rate_calculator.rate = testRateFunction # Setup a dict with the possible types. possible_types = { "A": 13, "D": 2, "B": 3, "J": 4, "C": 5, } # Construct the backend. cpp_interactions = kmc_interactions._backend(possible_types, 2) # 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) # 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)