Exemple #1
0
// -------------------------------------------------------------------------- //
//
void Test_Configuration::testMatchLists()
{
    // Setup a configuration.
    std::vector< std::vector<double> > basis(3, std::vector<double>(3,0.0));
    basis[1][0] = 0.25;
    basis[1][1] = 0.25;
    basis[1][2] = 0.25;
    basis[2][0] = 0.75;
    basis[2][1] = 0.75;
    basis[2][2] = 0.75;

    std::vector<int> basis_sites(3);
    basis_sites[0] = 0;
    basis_sites[1] = 1;
    basis_sites[2] = 2;

    std::vector<std::string> basis_elements(3);
    basis_elements[0] = "A";
    basis_elements[1] = "B";
    basis_elements[2] = "B";

    // Make a 37x18x19 structure.
    const int nI = 37;
    const int nJ = 18;
    const int nK = 19;
    const int nB = 3;

    // Coordinates and elements.
    std::vector<std::vector<double> > coordinates;
    std::vector<std::string> elements;

    for (int i = 0; i < nI; ++i)
    {
        for (int j = 0; j < nJ; ++j)
        {
            for (int k = 0; k < nK; ++k)
            {
                for (int b = 0; b < nB; ++b)
                {
                    std::vector<double> c(3);
                    c[0] = i + basis[b][0];
                    c[1] = j + basis[b][1];
                    c[2] = k + basis[b][2];
                    coordinates.push_back(c);
                    elements.push_back(basis_elements[b]);
                }
            }
        }
    }

    elements[0]    = "V";
    elements[216]  = "V";
    elements[1434] = "V";
    elements[2101] = "V";

    // Possible types.
    std::map<std::string, int> possible_types;
    possible_types["*"] = 0;
    possible_types["A"] = 1;
    possible_types["B"] = 2;
    possible_types["V"] = 3;

    // Setup the configuration.
    Configuration configuration(coordinates, elements, possible_types);

    // Setup the lattice map.
    std::vector<int> repetitions(3);
    repetitions[0] = nI;
    repetitions[1] = nJ;
    repetitions[2] = nK;
    std::vector<bool> periodicity(3, true);
    LatticeMap lattice_map(nB, repetitions, periodicity);

    // Try to access the match lists before initialization. They should be
    // empty.
    CPPUNIT_ASSERT( configuration.minimalMatchList(10).empty()   );
    CPPUNIT_ASSERT( configuration.minimalMatchList(2101).empty() );
    CPPUNIT_ASSERT( configuration.minimalMatchList(1434).empty() );

    // Init the match lists.
    configuration.initMatchLists(lattice_map, 1);

    // This did something.
    CPPUNIT_ASSERT( !configuration.minimalMatchList(10).empty()   );
    CPPUNIT_ASSERT( !configuration.minimalMatchList(2101).empty() );
    CPPUNIT_ASSERT( !configuration.minimalMatchList(1434).empty() );

    // Get the match list the hard way.
    const std::vector<MinimalMatchListEntry> ref_1434 = \
        configuration.minimalMatchList( 1434,
                                        lattice_map.neighbourIndices(1434),
                                        lattice_map);
    // Check the size.
    CPPUNIT_ASSERT_EQUAL( static_cast<int>(ref_1434.size()),
                          static_cast<int>(configuration.minimalMatchList(1434).size()) );

    // Check the values.
    for (size_t i = 0; i < ref_1434.size(); ++i)
    {
        CPPUNIT_ASSERT_EQUAL( ref_1434[i].match_type,
                              configuration.minimalMatchList(1434)[i].match_type );
        CPPUNIT_ASSERT_EQUAL( ref_1434[i].update_type,
                              configuration.minimalMatchList(1434)[i].update_type );
        CPPUNIT_ASSERT_EQUAL( ref_1434[i].index,
                              configuration.minimalMatchList(1434)[i].index );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( ref_1434[i].distance,
                                      configuration.minimalMatchList(1434)[i].distance,
                                      1.0e-14 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( ref_1434[i].coordinate.x(),
                                      configuration.minimalMatchList(1434)[i].coordinate.x(),
                                      1.0e-14 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( ref_1434[i].coordinate.y(),
                                      configuration.minimalMatchList(1434)[i].coordinate.y(),
                                      1.0e-14 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( ref_1434[i].coordinate.z(),
                                      configuration.minimalMatchList(1434)[i].coordinate.z(),
                                      1.0e-14 );

    }

    // Setup a process that changes V to B.

    // Get a process that finds a V between two B and turns one of
    // the Bs into an A.
    std::vector<std::string> process_elements1(3);
    process_elements1[0] = "V";
    process_elements1[1] = "B";
    process_elements1[2] = "B";

    std::vector<std::string> process_elements2(3);
    process_elements2[0] = "B";
    process_elements2[1] = "A";
    process_elements2[2] = "B";

    std::vector<std::vector<double> > process_coordinates(3, std::vector<double>(3, 0.0));

    process_coordinates[1][0] = -0.25;
    process_coordinates[1][1] = -0.25;
    process_coordinates[1][2] = -0.25;
    process_coordinates[2][0] =  0.25;
    process_coordinates[2][1] =  0.25;
    process_coordinates[2][2] =  0.25;

    const double rate = 13.7;
    Configuration c1(process_coordinates, process_elements1, possible_types);
    Configuration c2(process_coordinates, process_elements2, possible_types);
    Process p(c1, c2, rate, basis_sites);

    // Now, add index 1434 to the process.
    // We know by construction that these match.
    p.addSite(1434, 0.0);

    // For site 1434
    // 350 changes from 1 to 0
    // 1434 changes from 2 to 1
    // All other must remain unchanged.
    CPPUNIT_ASSERT_EQUAL( configuration.types()[1434], 3 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[350],  2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[1433], 2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[349],  2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[351],  1 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[2517], 1 );

    // Peform the process.
    configuration.performProcess(p, 1434);

    // Check that the types were correctly updated.
    CPPUNIT_ASSERT_EQUAL( configuration.types()[1434], 2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[350],  1 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[1433], 2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[349],  2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[351],  1 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[2517], 1 );

    // Check that updating the matchlist gets us the correct values.
    configuration.updateMatchList(1434);

    // Reference.
    const std::vector<MinimalMatchListEntry> ref2_1434 =        \
        configuration.minimalMatchList( 1434,
                                        lattice_map.neighbourIndices(1434),
                                        lattice_map);
    // Check the size.
    CPPUNIT_ASSERT_EQUAL( static_cast<int>(ref2_1434.size()),
                          static_cast<int>(configuration.minimalMatchList(1434).size()) );

    // Check the values.
    for (size_t i = 0; i < ref2_1434.size(); ++i)
    {
        CPPUNIT_ASSERT_EQUAL( ref2_1434[i].match_type,
                              configuration.minimalMatchList(1434)[i].match_type );
        CPPUNIT_ASSERT_EQUAL( ref2_1434[i].update_type,
                              configuration.minimalMatchList(1434)[i].update_type );
        CPPUNIT_ASSERT_EQUAL( ref2_1434[i].index,
                              configuration.minimalMatchList(1434)[i].index );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( ref2_1434[i].distance,
                                      configuration.minimalMatchList(1434)[i].distance,
                                      1.0e-14 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( ref2_1434[i].coordinate.x(),
                                      configuration.minimalMatchList(1434)[i].coordinate.x(),
                                      1.0e-14 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( ref2_1434[i].coordinate.y(),
                                      configuration.minimalMatchList(1434)[i].coordinate.y(),
                                      1.0e-14 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( ref2_1434[i].coordinate.z(),
                                      configuration.minimalMatchList(1434)[i].coordinate.z(),
                                      1.0e-14 );

    }
}
Exemple #2
0
// -------------------------------------------------------------------------- //
//
void Test_Configuration::testPerformProcess()
{
    // Setup a realistic system.
    std::vector< std::vector<double> > basis(3, std::vector<double>(3,0.0));
    basis[1][0] = 0.25;
    basis[1][1] = 0.25;
    basis[1][2] = 0.25;
    basis[2][0] = 0.75;
    basis[2][1] = 0.75;
    basis[2][2] = 0.75;

    std::vector<int> basis_sites(3);
    basis_sites[0] = 0;
    basis_sites[1] = 1;
    basis_sites[2] = 2;
    std::vector<std::string> basis_elements(3);
    basis_elements[0] = "A";
    basis_elements[1] = "B";
    basis_elements[2] = "B";

    // Make a 37x18x19 structure.
    const int nI = 37;
    const int nJ = 18;
    const int nK = 19;
    const int nB = 3;

    // Coordinates and elements.
    std::vector<std::vector<double> > coordinates;
    std::vector<std::string> elements;

    for (int i = 0; i < nI; ++i)
    {
        for (int j = 0; j < nJ; ++j)
        {
            for (int k = 0; k < nK; ++k)
            {
                for (int b = 0; b < nB; ++b)
                {
                    std::vector<double> c(3);
                    c[0] = i + basis[b][0];
                    c[1] = j + basis[b][1];
                    c[2] = k + basis[b][2];
                    coordinates.push_back(c);
                    elements.push_back(basis_elements[b]);
                }
            }
        }
    }

    elements[0]    = "V";
    elements[216]  = "V";   // These affects process 0,1 and 3
    elements[1434] = "V";
    elements[2101] = "V";   // This affects process 0,1 and 2

    // Possible types.
    std::map<std::string, int> possible_types;
    possible_types["*"] = 0;
    possible_types["A"] = 1;
    possible_types["B"] = 2;
    possible_types["V"] = 3;

    // Setup the configuration.
    Configuration configuration(coordinates, elements, possible_types);

    // Setup the lattice map.
    std::vector<int> repetitions(3);
    repetitions[0] = nI;
    repetitions[1] = nJ;
    repetitions[2] = nK;
    std::vector<bool> periodicity(3, true);
    LatticeMap lattice_map(nB, repetitions, periodicity);

    // Init the match lists.
    configuration.initMatchLists(lattice_map, 1);

    // Get a process that finds a V between two B and turns one of
    // the Bs into an A.
    std::vector<std::string> process_elements1(3);
    process_elements1[0] = "V";
    process_elements1[1] = "B";
    process_elements1[2] = "B";

    std::vector<std::string> process_elements2(3);
    process_elements2[0] = "B";
    process_elements2[1] = "A";
    process_elements2[2] = "B";

    std::vector<std::vector<double> > process_coordinates(3, std::vector<double>(3, 0.0));

    process_coordinates[1][0] = -0.25;
    process_coordinates[1][1] = -0.25;
    process_coordinates[1][2] = -0.25;
    process_coordinates[2][0] =  0.25;
    process_coordinates[2][1] =  0.25;
    process_coordinates[2][2] =  0.25;

    const double rate = 13.7;
    Configuration c1(process_coordinates, process_elements1, possible_types);
    Configuration c2(process_coordinates, process_elements2, possible_types);
    Process p(c1, c2, rate, basis_sites);

    // Now, add index 1434 to the process.
    // We know by construction that these match.
    p.addSite(1434, 0.0);

    // For site 1434
    // 350 changes from 1 to 0
    // 1434 changes from 2 to 1
    // All other must remain unchanged.
    CPPUNIT_ASSERT_EQUAL( configuration.types()[1434], 3 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[350],  2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[1433], 2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[349],  2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[351],  1 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[2517], 1 );

    // Peform the process.
    configuration.performProcess(p, 1434);

    // Check that the types were correctly updated.
    CPPUNIT_ASSERT_EQUAL( configuration.types()[1434], 2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[350],  1 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[1433], 2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[349],  2 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[351],  1 );
    CPPUNIT_ASSERT_EQUAL( configuration.types()[2517], 1 );

    // Check that the correct indices were added to the list of affected.
    const std::vector<int> affected = p.affectedIndices();
    CPPUNIT_ASSERT_EQUAL( affected[0], 1434 );
    CPPUNIT_ASSERT_EQUAL( affected[1], 350  );

}
// -------------------------------------------------------------------------- //
//
void Test_Interactions::testUpdateProcessIDMoves()
{
    // Setup two valid processes.
    std::vector<Process> processes;

    std::vector<std::string> process_elements1(3);
    process_elements1[0] = "A";
    process_elements1[1] = "B";
    process_elements1[2] = "V";

    std::vector<std::string> process_elements2(3);
    process_elements2[0] = "B";
    process_elements2[1] = "A";
    process_elements2[2] = "A";

    std::vector<std::vector<double> > process_coordinates1(3, std::vector<double>(3, 0.0));
    process_coordinates1[1][0] = -1.0;
    process_coordinates1[1][1] =  0.0;
    process_coordinates1[1][2] =  0.0;

    process_coordinates1[2][0] =  0.3;
    process_coordinates1[2][1] =  0.3;
    process_coordinates1[2][2] =  0.3;

    std::vector<int> move_origins;
    move_origins.push_back(0);
    move_origins.push_back(1);

    std::vector<Coordinate> move_vectors;
    move_vectors.push_back( Coordinate(-1.0, 0.0, 0.0) );
    move_vectors.push_back( Coordinate( 1.0, 0.0, 0.0) );

    // Possible types.
    std::map<std::string, int> possible_types;
    possible_types["*"] = 0;
    possible_types["A"] = 1;
    possible_types["B"] = 2;
    possible_types["V"] = 3;

    const double rate = 13.7;
    const Configuration c1(process_coordinates1, process_elements1, possible_types);
    const Configuration c2(process_coordinates1, process_elements2, possible_types);

    // Let this process be valid at site 0.
    processes.push_back(Process(c1,c2,rate,std::vector<int>(1,0), move_origins, move_vectors));

    // Let this process be valid at sites 0 and 2.
    std::vector<int> sites_vector(2,0);
    sites_vector[1] = 2;
    processes.push_back(Process(c1,c2,rate,sites_vector, move_origins, move_vectors));

    std::vector<std::vector<double> > process_coordinates2(3, std::vector<double>(3, 0.0));

    process_coordinates2[1][0] =  0.7;
    process_coordinates2[1][1] =  0.7;
    process_coordinates2[1][2] = -0.3;

    process_coordinates2[2][0] =  1.0;
    process_coordinates2[2][1] =  1.0;
    process_coordinates2[2][2] =  1.0;

    move_vectors[0] = Coordinate( 0.7, 0.7, -0.3);
    move_vectors[1] = Coordinate(-0.7,-0.7,  0.3);


    const Configuration c3(process_coordinates2, process_elements1, possible_types);
    const Configuration c4(process_coordinates2, process_elements2, possible_types);

    // Let the process be valid at site 1.
    processes.push_back(Process(c3,c4,rate,std::vector<int>(1,1), move_origins, move_vectors));

    Interactions interactions(processes, true);

    // Generate a corresponding configuration.
    std::vector<std::vector<double> > config_coordinates;
    std::vector<std::string> elements;
    for (int i = 0; i < 5; ++i)
    {
        for (int j = 0; j < 5; ++j)
        {
            for (int k = 0; k < 5; ++k)
            {
                std::vector<double> coord(3);
                coord[0] = 0.0 + i*1.0;
                coord[1] = 0.0 + j*1.0;
                coord[2] = 0.0 + k*1.0;
                config_coordinates.push_back(coord);
                elements.push_back("V");

                coord[0] = 0.3 + i*1.0;
                coord[1] = 0.3 + j*1.0;
                coord[2] = 0.3 + k*1.0;
                elements.push_back("B");
                config_coordinates.push_back(coord);
            }
        }
    }

    // Get the config and lattice map.
    Configuration config(config_coordinates, elements, possible_types);
    const LatticeMap lattice_map(2, std::vector<int>(3,5), std::vector<bool>(3,true));

    // Now, setup the matchlists in the configuration.
    config.initMatchLists(lattice_map, interactions.maxRange());

    // Check the process match lists before we start.
    CPPUNIT_ASSERT_EQUAL(static_cast<int>(interactions.processes()[0]->minimalMatchList().size()), 3);
    CPPUNIT_ASSERT_EQUAL(static_cast<int>(interactions.processes()[1]->minimalMatchList().size()), 3);
    CPPUNIT_ASSERT_EQUAL(static_cast<int>(interactions.processes()[2]->minimalMatchList().size()), 3);

    // Check the id moves before update.
    {
        const std::vector< std::pair<int, int> > & id_moves = interactions.processes()[0]->idMoves();
        CPPUNIT_ASSERT_EQUAL( static_cast<int>(id_moves.size()), 2 );
        CPPUNIT_ASSERT_EQUAL( id_moves[0].first,  0 );
        CPPUNIT_ASSERT_EQUAL( id_moves[0].second, 2 );
        CPPUNIT_ASSERT_EQUAL( id_moves[1].first,  2 );
        CPPUNIT_ASSERT_EQUAL( id_moves[1].second, 0 );
    }

    // Update the interactions according to the configuration match lists.
    // This also updates the id moves on the processes.
    interactions.updateProcessMatchLists(config, lattice_map);

    // Check the id moves after update.
    {
        const std::vector<MinimalMatchListEntry> & match = interactions.processes()[0]->minimalMatchList();
        CPPUNIT_ASSERT_EQUAL( static_cast<int>(match.size()), 6 );

        const std::vector< std::pair<int, int> > & id_moves = interactions.processes()[0]->idMoves();
        CPPUNIT_ASSERT_EQUAL( static_cast<int>(id_moves.size()), 2 );
        CPPUNIT_ASSERT_EQUAL( id_moves[0].first,  0 );
        CPPUNIT_ASSERT_EQUAL( id_moves[0].second, 5 );
        CPPUNIT_ASSERT_EQUAL( id_moves[1].first,  5 );
        CPPUNIT_ASSERT_EQUAL( id_moves[1].second, 0 );

        // Wildcards are now added.
        CPPUNIT_ASSERT_EQUAL( match[0].match_type,  1 );
        CPPUNIT_ASSERT_EQUAL( match[1].match_type,  3 );
        CPPUNIT_ASSERT_EQUAL( match[2].match_type,  0 );
        CPPUNIT_ASSERT_EQUAL( match[3].match_type,  0 );
        CPPUNIT_ASSERT_EQUAL( match[4].match_type,  0 );
        CPPUNIT_ASSERT_EQUAL( match[5].match_type,  2 );
    }
}
// -------------------------------------------------------------------------- //
//
void Test_Interactions::testUpdateProcessMatchLists()
{
    // Setup two valid processes.
    std::vector<Process> processes;

    std::vector<std::string> process_elements1(3);
    process_elements1[0] = "A";
    process_elements1[1] = "B";
    process_elements1[2] = "V";

    std::vector<std::string> process_elements2(3);
    process_elements2[0] = "B";
    process_elements2[1] = "A";
    process_elements2[2] = "A";

    std::vector<std::vector<double> > process_coordinates1(3, std::vector<double>(3, 0.0));
    process_coordinates1[1][0] = -1.0;
    process_coordinates1[1][1] =  0.0;
    process_coordinates1[1][2] =  0.0;

    process_coordinates1[2][0] =  0.3;
    process_coordinates1[2][1] =  0.3;
    process_coordinates1[2][2] =  0.3;

    // Possible types.
    std::map<std::string, int> possible_types;
    possible_types["*"] = 0;
    possible_types["A"] = 1;
    possible_types["B"] = 2;
    possible_types["V"] = 3;

    const double rate = 13.7;
    const Configuration c1(process_coordinates1, process_elements1, possible_types);
    const Configuration c2(process_coordinates1, process_elements2, possible_types);

    // Let this process be valid at site 0.
    processes.push_back(Process(c1,c2,rate,std::vector<int>(1,0)));

    // Let this process be valid at sites 0 and 2.
    std::vector<int> sites_vector(2,0);
    sites_vector[1] = 2;
    processes.push_back(Process(c1,c2,rate,sites_vector));

    std::vector<std::vector<double> > process_coordinates2(3, std::vector<double>(3, 0.0));

    process_coordinates2[1][0] =  0.7;
    process_coordinates2[1][1] =  0.7;
    process_coordinates2[1][2] = -0.3;

    process_coordinates2[2][0] =  1.0;
    process_coordinates2[2][1] =  1.0;
    process_coordinates2[2][2] =  1.0;

    const Configuration c3(process_coordinates2, process_elements1, possible_types);
    const Configuration c4(process_coordinates2, process_elements2, possible_types);

    // Let the process be valid at site 1.
    processes.push_back(Process(c3,c4,rate,std::vector<int>(1,1)));

    Interactions interactions(processes, true);

    // Generate a corresponding configuration.
    std::vector<std::vector<double> > config_coordinates;
    std::vector<std::string> elements;
    for (int i = 0; i < 5; ++i)
    {
        for (int j = 0; j < 5; ++j)
        {
            for (int k = 0; k < 5; ++k)
            {
                std::vector<double> coord(3);
                coord[0] = 0.0 + i*1.0;
                coord[1] = 0.0 + j*1.0;
                coord[2] = 0.0 + k*1.0;
                config_coordinates.push_back(coord);
                elements.push_back("V");

                coord[0] = 0.3 + i*1.0;
                coord[1] = 0.3 + j*1.0;
                coord[2] = 0.3 + k*1.0;
                elements.push_back("B");
                config_coordinates.push_back(coord);
            }
        }
    }

    // Get the config and lattice map.
    Configuration config(config_coordinates, elements, possible_types);

    // Make sure we do this on a non-periodic lattice map, to make sure
    // the most central cell is choosen for determining wildcard positions.
    const LatticeMap lattice_map(2, std::vector<int>(3,5), std::vector<bool>(3,false));

    // Now, setup the matchlists in the configuration.
    config.initMatchLists(lattice_map, interactions.maxRange());

    // Check the process match lists before we start.
    CPPUNIT_ASSERT_EQUAL(static_cast<int>(interactions.processes()[0]->minimalMatchList().size()), 3);
    CPPUNIT_ASSERT_EQUAL(static_cast<int>(interactions.processes()[1]->minimalMatchList().size()), 3);
    CPPUNIT_ASSERT_EQUAL(static_cast<int>(interactions.processes()[2]->minimalMatchList().size()), 3);

    // Update the interactions according to the configuration match lists.
    interactions.updateProcessMatchLists(config, lattice_map);

    // Check a few coordinates and match types.
    {
        const std::vector<MinimalMatchListEntry> & match = interactions.processes()[0]->minimalMatchList();

        CPPUNIT_ASSERT_EQUAL( static_cast<int>(match.size()), 6 );

        // Wildcards are now added.
        CPPUNIT_ASSERT_EQUAL( match[0].match_type,  1 );
        CPPUNIT_ASSERT_EQUAL( match[1].match_type,  3 );
        CPPUNIT_ASSERT_EQUAL( match[2].match_type,  0 );
        CPPUNIT_ASSERT_EQUAL( match[3].match_type,  0 );
        CPPUNIT_ASSERT_EQUAL( match[4].match_type,  0 );
        CPPUNIT_ASSERT_EQUAL( match[5].match_type,  2 );

        // These are not changed - but sorted.
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[0].coordinate.x(),  process_coordinates1[0][0], 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[0].coordinate.y(),  process_coordinates1[0][1], 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[0].coordinate.z(),  process_coordinates1[0][2], 1.0e-10 );

        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[1].coordinate.x(),  process_coordinates1[2][0], 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[1].coordinate.y(),  process_coordinates1[2][1], 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[1].coordinate.z(),  process_coordinates1[2][2], 1.0e-10 );

        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[5].coordinate.x(),  process_coordinates1[1][0], 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[5].coordinate.y(),  process_coordinates1[1][1], 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[5].coordinate.z(),  process_coordinates1[1][2], 1.0e-10 );

        // Here are the added wildcards.
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[2].coordinate.x(), -0.7, 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[2].coordinate.y(),  0.3, 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[2].coordinate.z(),  0.3, 1.0e-10 );

        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[3].coordinate.x(),  0.3, 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[3].coordinate.y(), -0.7, 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[3].coordinate.z(),  0.3, 1.0e-10 );

        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[4].coordinate.x(),  0.3, 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[4].coordinate.y(),  0.3, 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[4].coordinate.z(), -0.7, 1.0e-10 );

    }


    {
        // This one is not changed, since it was applicable to more than one basis site.
        const std::vector<MinimalMatchListEntry> & match = interactions.processes()[1]->minimalMatchList();
        CPPUNIT_ASSERT_EQUAL( static_cast<int>(match.size()), 3 );
        // Not changed - but sorted.
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[0].coordinate.x(),  process_coordinates1[0][0], 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[0].coordinate.y(),  process_coordinates1[0][1], 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[0].coordinate.z(),  process_coordinates1[0][2], 1.0e-10 );

        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[1].coordinate.x(),  process_coordinates1[2][0], 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[1].coordinate.y(),  process_coordinates1[2][1], 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[1].coordinate.z(),  process_coordinates1[2][2], 1.0e-10 );

        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[2].coordinate.x(),  process_coordinates1[1][0], 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[2].coordinate.y(),  process_coordinates1[1][1], 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[2].coordinate.z(),  process_coordinates1[1][2], 1.0e-10 );

    }


    {
        const std::vector<MinimalMatchListEntry> & match = interactions.processes()[2]->minimalMatchList();
        CPPUNIT_ASSERT_EQUAL( static_cast<int>(match.size()), 47 );

        // Not changed.
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[0].coordinate.x(),  process_coordinates2[0][0], 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[0].coordinate.y(),  process_coordinates2[0][1], 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[0].coordinate.z(),  process_coordinates2[0][2], 1.0e-10 );

        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[13].coordinate.x(),  process_coordinates2[1][0], 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[13].coordinate.y(),  process_coordinates2[1][1], 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[13].coordinate.z(),  process_coordinates2[1][2], 1.0e-10 );

        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[46].coordinate.x(),  process_coordinates2[2][0], 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[46].coordinate.y(),  process_coordinates2[2][1], 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[46].coordinate.z(),  process_coordinates2[2][2], 1.0e-10 );


        // These are the added wildcards.
        for (int i = 0; i < 47; ++i)
        {
            if (i != 0 && i != 13 && i != 46)
            {
                CPPUNIT_ASSERT_EQUAL( match[i].match_type, 0 );
            }
        }

        // Check one coordinate.
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[17].coordinate.x(),-0.3, 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[17].coordinate.y(),-0.3, 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[17].coordinate.z(),-1.3, 1.0e-10 );

        // Check another one.
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[18].coordinate.x(),-1.0, 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[18].coordinate.y(),-1.0, 1.0e-10 );
        CPPUNIT_ASSERT_DOUBLES_EQUAL( match[18].coordinate.z(), 0.0, 1.0e-10 );

    }
}
// -------------------------------------------------------------------------- //
//
void Test_Interactions::testMaxRange()
{
    // Setup two valid processes.
    std::vector<Process> processes;

    std::vector<std::string> process_elements1(3);
    process_elements1[0] = "A";
    process_elements1[1] = "A";
    process_elements1[2] = "A";

    std::vector<std::string> process_elements2(3);
    process_elements2[0] = "B";
    process_elements2[1] = "A";
    process_elements2[2] = "A";

    std::vector<std::vector<double> > process_coordinates(3, std::vector<double>(3, 0.0));
    process_coordinates[1][0] = -0.1;
    process_coordinates[1][1] = -0.1;
    process_coordinates[1][2] = -0.1;

    // Possible types.
    std::map<std::string, int> possible_types;
    possible_types["A"] = 0;
    possible_types["B"] = 1;
    possible_types["V"] = 2;

    const double rate = 13.7;
    const Configuration c1(process_coordinates, process_elements1, possible_types);
    const Configuration c2(process_coordinates, process_elements2, possible_types);

    std::vector<int> sites_vector(0);
    processes.push_back(Process(c1,c2,rate,sites_vector));
    processes.push_back(Process(c1,c2,rate,sites_vector));

    // Setup the interactions object.
    const Interactions interactions(processes, true);

    // This should have the max range 1.
    CPPUNIT_ASSERT_EQUAL( interactions.maxRange(), 1 );

    // Adding a process with a -1.1 site should make the max range become 2.
    process_coordinates[1][0] =  0.0;
    process_coordinates[1][1] =  0.0;
    process_coordinates[1][2] = -1.1;

    const Configuration c3(process_coordinates, process_elements1, possible_types);
    const Configuration c4(process_coordinates, process_elements2, possible_types);
    processes.push_back(Process(c3,c4,rate,sites_vector));

    // This should have the max range 2.
    const Interactions interactions2(processes, true);
    CPPUNIT_ASSERT_EQUAL( interactions2.maxRange(), 2 );

    // Check the same thing in y.
    process_coordinates[1][0] =  0.0;
    process_coordinates[1][1] = -2.1;
    process_coordinates[1][2] =  0.0;

    const Configuration c5(process_coordinates, process_elements1, possible_types);
    const Configuration c6(process_coordinates, process_elements2, possible_types);
    processes[2] = Process(c5,c6,rate,sites_vector);

    // This should have the max range 3.
    const Interactions interactions3(processes, true);
    CPPUNIT_ASSERT_EQUAL( interactions3.maxRange(), 3 );

    // And in x.
    process_coordinates[1][0] = -3.1;
    process_coordinates[1][1] =  0.0;
    process_coordinates[1][2] =  0.0;

    const Configuration c7(process_coordinates, process_elements1, possible_types);
    const Configuration c8(process_coordinates, process_elements2, possible_types);
    processes[2] = Process(c7,c8,rate,sites_vector);

    // This should have the max range 4.
    const Interactions interactions4(processes, true);
    CPPUNIT_ASSERT_EQUAL( interactions4.maxRange(), 4 );

    // And in the positive direction.

    // Adding a process with a 5.1 site should make the max range become 5.
    process_coordinates[1][0] =  0.0;
    process_coordinates[1][1] =  0.0;
    process_coordinates[1][2] =  5.1;

    const Configuration c9(process_coordinates, process_elements1, possible_types);
    const Configuration c10(process_coordinates, process_elements2, possible_types);
    processes[2] = Process(c9,c10,rate,sites_vector);

    // This should have the max range 5.
    const Interactions interactions5(processes, true);
    CPPUNIT_ASSERT_EQUAL( interactions5.maxRange(), 5 );


    // Check the same thing in y.
    process_coordinates[1][0] =  0.0;
    process_coordinates[1][1] =  2.1;
    process_coordinates[1][2] =  0.0;

    const Configuration c11(process_coordinates, process_elements1, possible_types);
    const Configuration c12(process_coordinates, process_elements2, possible_types);
    processes[2] = Process(c11,c12,rate,sites_vector);

    // This should have the max range 2.
    const Interactions interactions6(processes, true);
    CPPUNIT_ASSERT_EQUAL( interactions6.maxRange(), 2 );

    // And in x.
    process_coordinates[1][0] =  4.1;
    process_coordinates[1][1] =  0.0;
    process_coordinates[1][2] =  0.0;

    const Configuration c13(process_coordinates, process_elements1, possible_types);
    const Configuration c14(process_coordinates, process_elements2, possible_types);
    processes[2] = Process(c13,c14,rate,sites_vector);

    // This should have the max range 4.
    const Interactions interactions7(processes, true);
    CPPUNIT_ASSERT_EQUAL( interactions7.maxRange(), 4 );

}
// -------------------------------------------------------------------------- //
//
void Test_Interactions::testQuery()
{
    // Setup two valid processes.
    std::vector<Process> processes;

    // Possible types.
    std::map<std::string, int> possible_types;
    possible_types["A"] = 0;
    possible_types["B"] = 1;
    possible_types["V"] = 2;

    // A process that independent of local environment swaps a "B" to "V"
    {
        const std::vector<std::string> process_elements1(1,"B");
        const std::vector<std::string> process_elements2(1,"V");
        const std::vector<std::vector<double> > process_coordinates(1, std::vector<double>(3, 0.0));
        const double rate = 1.234;
        Configuration c1(process_coordinates, process_elements1, possible_types);
        Configuration c2(process_coordinates, process_elements2, possible_types);
        Process p(c1, c2, rate, std::vector<int>(1,0));
        // Store twize.
        processes.push_back(p);
        processes.push_back(p);
    }

    // A process that finds an A between two B's in the 1,1,1 direction
    // and swap the A and the first B.
    {
        std::vector<std::string> process_elements1(3);
        process_elements1[0] = "A";
        process_elements1[1] = "B";
        process_elements1[2] = "B";

        std::vector<std::string> process_elements2(3);
        process_elements2[0] = "B";
        process_elements2[1] = "A";
        process_elements2[2] = "B";

        std::vector<std::vector<double> > process_coordinates(3, std::vector<double>(3, 0.0));

        process_coordinates[1][0] = -0.25;
        process_coordinates[1][1] = -0.25;
        process_coordinates[1][2] = -0.25;
        process_coordinates[2][0] =  0.25;
        process_coordinates[2][1] =  0.25;
        process_coordinates[2][2] =  0.25;

        const double rate = 13.7;
        Configuration c1(process_coordinates, process_elements1, possible_types);
        Configuration c2(process_coordinates, process_elements2, possible_types);
        Process p(c1, c2, rate, std::vector<int>(1,0));
        processes.push_back(p);
    }

    // Setup the interactions object.
    Interactions interactions(processes, false);

    // Query for the processes.
    const std::vector<Process*> & queried_processes = interactions.processes();

    // Check the length of the list of processes.
    CPPUNIT_ASSERT_EQUAL( static_cast<int>(queried_processes.size()), 3 );

    // Get the types in the queried processes and check.
    CPPUNIT_ASSERT_EQUAL( queried_processes[0]->minimalMatchList()[0].match_type, 1 );
    CPPUNIT_ASSERT_EQUAL( queried_processes[0]->minimalMatchList()[0].update_type, 2 );

    CPPUNIT_ASSERT_EQUAL( queried_processes[2]->minimalMatchList()[2].match_type, 1 );
    CPPUNIT_ASSERT_EQUAL( queried_processes[2]->minimalMatchList()[2].update_type, 1 );

    // Query for the total number of available sites. This is zero since no sites are added to
    // the processes.
    CPPUNIT_ASSERT_EQUAL( interactions.totalAvailableSites(), 0 );

    // Add sites to the processes and see that we get the correct number out.
    interactions.processes()[0]->addSite(12);
    interactions.processes()[0]->addSite(143);
    interactions.processes()[0]->addSite(1654);
    interactions.processes()[0]->addSite(177777);

    interactions.processes()[1]->addSite(12);
    interactions.processes()[1]->addSite(143);

    interactions.processes()[2]->addSite(1654);
    interactions.processes()[2]->addSite(177777);
    interactions.processes()[2]->addSite(177777);

    CPPUNIT_ASSERT_EQUAL( interactions.totalAvailableSites(), 9 );

    // Query for the rate calculator.
    const RateCalculator & rc = interactions.rateCalculator();
    CPPUNIT_ASSERT( &rc != NULL );

}
// -------------------------------------------------------------------------- //
//
void Test_Interactions::testUpdateAndPickCustom()
{
    // Setup a list of custom rate processes.
    std::vector<CustomRateProcess> processes;

    // Setup a vector of dummy processes.
    std::vector<std::string> process_elements1(1);
    process_elements1[0] = "A";

    std::vector<std::string> process_elements2(1);
    process_elements2[0] = "B";

    std::vector<std::vector<double> > process_coordinates(1, std::vector<double>(3, 0.0));

    // Possible types.
    std::map<std::string, int> possible_types;
    possible_types["A"] = 0;
    possible_types["B"] = 1;
    possible_types["V"] = 2;

    const double rate = 1.0/13.7;
    Configuration c1(process_coordinates, process_elements1, possible_types);
    Configuration c2(process_coordinates, process_elements2, possible_types);
    std::vector<int> sites_vector(1,0);
    processes.push_back(CustomRateProcess(c1,c2,rate,sites_vector, 1.0));
    processes.push_back(CustomRateProcess(c1,c2,rate,sites_vector, 1.0));
    processes.push_back(CustomRateProcess(c1,c2,rate/2.0,sites_vector, 1.0));
    processes.push_back(CustomRateProcess(c1,c2,rate,sites_vector, 1.0));
    processes.push_back(CustomRateProcess(c1,c2,rate,sites_vector, 1.0));
    processes.push_back(CustomRateProcess(c1,c2,rate,sites_vector, 1.0));

    // Fake a matching by adding sites to the processes.

    // First process, 3 sites, total rate 12
    processes[0].addSite(12,  4.0);
    processes[0].addSite(123, 7.0);
    processes[0].addSite(332, 1.0);

    // Second process, 2 sites, total rate 4
    processes[1].addSite(19, 1.0);
    processes[1].addSite(12, 3.0);

    // Third process, 4 sites, total rate  3
    processes[2].addSite(19,  1.0/4.0);
    processes[2].addSite(12,  5.0/4.0);
    processes[2].addSite(234, 2.0/4.0);
    processes[2].addSite(991, 4.0/4.0);

    // The sixth process, one site, total rate 12.
    processes[5].addSite(992, 12.0);

    // Setup the interactions object.
    RateCalculator rc;
    Interactions interactions(processes, true, rc);

    // Update the probability table.
    interactions.updateProbabilityTable();

    // Check the values of the probability table.
    const std::vector<std::pair<double, int> > & probability_table = \
        interactions.probabilityTable();

    CPPUNIT_ASSERT_EQUAL( static_cast<int>(probability_table.size()),
                          static_cast<int>(processes.size()) );

    CPPUNIT_ASSERT_DOUBLES_EQUAL( probability_table[0].first,  12.0, 1.0e-14 );
    CPPUNIT_ASSERT_DOUBLES_EQUAL( probability_table[1].first,  16.0, 1.0e-14 );
    CPPUNIT_ASSERT_DOUBLES_EQUAL( probability_table[2].first,  19.0, 1.0e-14 );
    CPPUNIT_ASSERT_DOUBLES_EQUAL( probability_table[3].first,  19.0, 1.0e-14 );
    CPPUNIT_ASSERT_DOUBLES_EQUAL( probability_table[4].first,  19.0, 1.0e-14 );
    CPPUNIT_ASSERT_DOUBLES_EQUAL( probability_table[5].first,  31.0, 1.0e-14 );

    CPPUNIT_ASSERT_EQUAL( probability_table[0].second, 3 );
    CPPUNIT_ASSERT_EQUAL( probability_table[1].second, 2 );
    CPPUNIT_ASSERT_EQUAL( probability_table[2].second, 4 );
    CPPUNIT_ASSERT_EQUAL( probability_table[3].second, 0 );
    CPPUNIT_ASSERT_EQUAL( probability_table[4].second, 0 );
    CPPUNIT_ASSERT_EQUAL( probability_table[5].second, 1 );


    // Make sure to seed the random number generator before we test any
    // random dependent stuff.
    seedRandom(false, 131);

    // Pick processes from this table with enough statistics should give
    // the distribution proportional to the number of available sites,
    // but with the double rate for the third process should halve
    // this entry.
    std::vector<int> picked(6,0);
    const int n_loop = 1000000;
    for (int i = 0; i < n_loop; ++i)
    {
        const int p = interactions.pickProcessIndex();

        // Make sure the picked process is not negative or too large.
        CPPUNIT_ASSERT( p >= 0 );
        CPPUNIT_ASSERT( p < static_cast<int>(probability_table.size()) );
        ++picked[p];
    }

    CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0*picked[0]/n_loop,
                                  12.0/31.0,
                                  1.0e-2 );

    CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0*picked[1]/n_loop,
                                  4.0/31.0,
                                  1.0e-2 );

    CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0*picked[2]/n_loop,
                                  3.0/31.0,
                                  1.0e-2 );

    CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0*picked[3]/n_loop,
                                  0.0/31.0,
                                  1.0e-2 );

    CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0*picked[4]/n_loop,
                                  0.0/31.0,
                                  1.0e-2 );

    CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0*picked[5]/n_loop,
                                  12.0/31.0,
                                  1.0e-2 );

    // Check that picking the process twice with two different access methods and
    // a seed reset inbetween gives a reference to the same object.
    seedRandom(false, 87);
    const int p = interactions.pickProcessIndex();
    const Process & proc1 = (*interactions.processes()[p]);

    seedRandom(false, 87);
    const Process & proc2 = (*interactions.pickProcess());
    CPPUNIT_ASSERT_EQUAL( &proc1, &proc2 );

    // Alter the total rate in one of the processes and re-run the picking.
    interactions.processes()[5]->removeSite(992);
    interactions.processes()[5]->addSite(992, 24.0);

    // Update the probability table.
    interactions.updateProbabilityTable();
    std::vector<int> picked2(6,0);
    for (int i = 0; i < n_loop; ++i)
    {
        const int p = interactions.pickProcessIndex();

        // Make sure the picked process is not negative or too large.
        CPPUNIT_ASSERT( p >= 0 );
        CPPUNIT_ASSERT( p < static_cast<int>(probability_table.size()) );
        ++picked2[p];
    }

    CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0*picked2[0]/n_loop,
                                  12.0/43.0,
                                  1.0e-2 );

    CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0*picked2[1]/n_loop,
                                  4.0/43.0,
                                  1.0e-2 );

    CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0*picked2[2]/n_loop,
                                  3.0/43.0,
                                  1.0e-2 );

    CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0*picked2[3]/n_loop,
                                  0.0/43.0,
                                  1.0e-2 );

    CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0*picked2[4]/n_loop,
                                  0.0/43.0,
                                  1.0e-2 );

    CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0*picked2[5]/n_loop,
                                  24.0/43.0,
                                  1.0e-2 );

    // DONE
}