Exemplo n.º 1
0
    def testStdVectorBucketTypeToPython(self):
        """ Test the buckets format conversion routine from C++ to Python. """
        empty_py_vector = stdVectorTypeBucketToPython(
            Backend.StdVectorTypeBucket(), Backend.StdVectorString())

        self.assertEqual(empty_py_vector, [])

        # Add a vector with content.
        cpp_map = Backend.StdVectorString(3)
        cpp_map[0] = "*"
        cpp_map[1] = "A"
        cpp_map[2] = "B"

        cpp_vector = Backend.StdVectorTypeBucket(4, Backend.TypeBucket(3))

        # [(1,"A")]
        cpp_vector[0][0] = 0
        cpp_vector[0][1] = 1
        cpp_vector[0][2] = 0

        # []
        cpp_vector[1][0] = 0
        cpp_vector[1][1] = 0
        cpp_vector[1][2] = 0

        # [(3,"A"), (1, "B")]
        cpp_vector[2][0] = 0
        cpp_vector[2][1] = 3
        cpp_vector[2][2] = 1

        # [(4,"A"), (5, "B")]
        cpp_vector[3][0] = 1
        cpp_vector[3][1] = 4
        cpp_vector[3][2] = 5

        # Translate to Python.
        py_vector = stdVectorTypeBucketToPython(cpp_vector, cpp_map)

        ref_py_vector = [[(1, "A")], [], [(3, "A"), (1, "B")],
                         [(4, "A"), (5, "B")]]

        # Check.
        self.assertEqual(py_vector, ref_py_vector)
Exemplo n.º 2
0
    def testStdVectorStringToStringList(self):
        """ Test the conversion of a std::vector<std::string> to a string list. """
        # Take a list of strings.
        cpp_list = Backend.StdVectorString()
        ref_list = ["AAA", "BB", "AbC", "def"]
        for s in ref_list:
            cpp_list.push_back(s)

        # Convert.
        py_repr = stdVectorStringToStringList(cpp_list)

        # Check the type.
        self.assertTrue(isinstance(py_repr, list))

        # Check the result.
        self.assertEqual(py_repr, ref_list)
Exemplo n.º 3
0
def stringListToStdVectorString(string_list):
    """
    Converts a list of strings to a std::vector<std::string> object.

    :param string_list: The list of strings.

    :returns: A corresponding std::vector<std::string> object.
    """
    # Get the size.
    size = len(string_list)
    # Setup the c++ object.
    cpp_list = Backend.StdVectorString()
    # Copy values over.
    for s in string_list:
        cpp_list.push_back(s)
    # Done.
    return cpp_list
Exemplo n.º 4
0
    def _backend(self, possible_types):
        """
        Query for the local configuration backend object.

        :param possible_types: A dict with the global mapping of type strings
                               to integers.

        :returns: The interactions object in C++
        """
        if self.__backend is None:
            # Construct the c++ backend object.
            cpp_types  = Backend.StdVectorString(self.__types)
            cpp_coords = numpy2DArrayToStdVectorStdVectorDouble(self.__coordinates)
            cpp_possible_types = Backend.StdMapStringInt(possible_types)

            # Send in the coordinates and types to construct the backend configuration.
            self.__backend = Backend.Configuration(cpp_coords,
                                                   cpp_types,
                                                   cpp_possible_types)

        # Return the backend.
        return self.__backend
Exemplo n.º 5
0
def bucketListToStdVectorStdVectorString(bucket_list):
    """
    Converts a list of the format [[(n,"A"), ...], ...]
    to a std::vector< std::vector<std::string> > representation.

    :param bucket_list: The list to convert.

    :returns: A corresponding std::vector<std::vector<std::string> > object.
    """
    cpp_list = Backend.StdVectorStdVectorString()

    # For each site.
    for ss in bucket_list:
        # For all types at this site.
        site_list = Backend.StdVectorString()
        for s in ss:
            # Add the number of types.
            for i in range(s[0]):
                site_list.push_back(s[1])
        cpp_list.push_back(site_list)

    # Done.
    return cpp_list
Exemplo n.º 6
0
    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 testUsage(self):
        """ Test that the KMCRateCalculatorPlugin can be used in a simulation. """
        # To get the random numbers and process numbers returned.
        ref_randoms = []
        ref_process_numbers = []
        ref_coordinates = []

        # Define a derrived class.
        class RateCalc(KMCRateCalculatorPlugin):
            # Overload the initialize function.
            def initialize(self):
                # Save something on the class here.
                self._times_called = 0

            # Overload the rate function.
            def rate(self, coords, types_befpre, types_after, rate_constant,
                     process_number, coordinate):
                # Do some simple counting and return the random number.
                self._times_called += 1
                rnd = numpy.random.uniform(0.0, 1.0)
                ref_randoms.append(rnd)
                ref_process_numbers.append(process_number)
                ref_coordinates.append(coordinate)
                return rnd

            # Overload the additive rate function.
            def useAdditiveRate(self):
                return False

        # Construct.
        calculator = RateCalc("DummyConfig")

        # Send it to C++ to get the rate out, call it 4 times.
        cpp_coords = Backend.StdVectorCoordinate()
        cpp_coords.push_back(Backend.Coordinate(1.0, 2.9, 3.4))
        cpp_types1 = Backend.StdVectorString()
        cpp_types1.push_back("A")
        cpp_types2 = Backend.StdVectorString()
        cpp_types2.push_back("B")
        rate_constant = 3.1415927
        ret_randoms = []
        process_numbers = [21, 12, 10, 2]
        global_xyz = numpy.array([[0.2, 0.4, 0.5], [1.1, 1.3, 1.4],
                                  [3.4, 4.3, 3.3], [4.2, 3.2, 1.9]])

        ret_randoms.append(
            Backend.getRate(calculator, cpp_coords, cpp_types1, cpp_types2,
                            rate_constant, process_numbers[0],
                            global_xyz[0, 0], global_xyz[0, 1], global_xyz[0,
                                                                           2]))
        ret_randoms.append(
            Backend.getRate(calculator, cpp_coords, cpp_types1, cpp_types2,
                            rate_constant, process_numbers[1],
                            global_xyz[1, 0], global_xyz[1, 1], global_xyz[1,
                                                                           2]))
        ret_randoms.append(
            Backend.getRate(calculator, cpp_coords, cpp_types1, cpp_types2,
                            rate_constant, process_numbers[2],
                            global_xyz[2, 0], global_xyz[2, 1], global_xyz[2,
                                                                           2]))
        ret_randoms.append(
            Backend.getRate(calculator, cpp_coords, cpp_types1, cpp_types2,
                            rate_constant, process_numbers[3],
                            global_xyz[3, 0], global_xyz[3, 1], global_xyz[3,
                                                                           2]))

        # Check that it was called 4 times.
        self.assertEqual(calculator._times_called, 4)

        # Check the values.
        self.assertAlmostEqual(ret_randoms, ref_randoms, 12)

        # Check the reference process numbers.
        self.assertEqual(ref_process_numbers[0], 21)
        self.assertEqual(ref_process_numbers[1], 12)
        self.assertEqual(ref_process_numbers[2], 10)
        self.assertEqual(ref_process_numbers[3], 2)

        # Check the reference coordinate.
        self.assertAlmostEqual(
            numpy.linalg.norm(global_xyz - numpy.array(ref_coordinates)), 0.0,
            10)
Exemplo n.º 8
0
    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)