test_partitioners/
test_partitioners.rs

1use mpi::{
2    collective::SystemOperation, environment::Universe, topology::Communicator,
3    traits::CommunicatorCollectives,
4};
5use ndelement::types::ReferenceCellType;
6use ndgrid::{
7    grid::local_grid::SingleElementGridBuilder,
8    traits::{Builder, Entity, Grid, ParallelBuilder, ParallelGrid},
9    types::{GraphPartitioner, Ownership},
10};
11
12/// Test that a graph partitioner works
13fn run_test<C: Communicator>(comm: &C, partitioner: GraphPartitioner) {
14    let n = 10;
15
16    let mut b = SingleElementGridBuilder::<f64>::new(2, (ReferenceCellType::Quadrilateral, 1));
17
18    let rank = comm.rank();
19    let grid = if rank == 0 {
20        let mut i = 0;
21        for y in 0..n {
22            for x in 0..n {
23                b.add_point(i, &[x as f64 / (n - 1) as f64, y as f64 / (n - 1) as f64]);
24                i += 1;
25            }
26        }
27
28        let mut i = 0;
29        for y in 0..n - 1 {
30            for x in 0..n - 1 {
31                let sw = n * y + x;
32                b.add_cell(i, &[sw, sw + 1, sw + n, sw + n + 1]);
33                i += 1;
34            }
35        }
36
37        b.create_parallel_grid_root(comm, partitioner)
38    } else {
39        b.create_parallel_grid(comm, 0)
40    };
41
42    // Check that owned cells are sorted ahead of ghost cells
43
44    let cell_count_owned = grid
45        .local_grid()
46        .entity_iter(ReferenceCellType::Quadrilateral)
47        .filter(|entity| entity.is_owned())
48        .count();
49
50    // Now check that the first `cell_count_owned` entities are actually owned.
51    for cell in grid
52        .local_grid()
53        .entity_iter(ReferenceCellType::Quadrilateral)
54        .take(cell_count_owned)
55    {
56        assert!(cell.is_owned())
57    }
58
59    // Now make sure that the indices of the global cells are in consecutive order
60
61    let mut cell_global_count = grid.cell_layout().local_range().0;
62
63    for cell in grid
64        .local_grid()
65        .entity_iter(ReferenceCellType::Quadrilateral)
66        .take(cell_count_owned)
67    {
68        assert_eq!(cell.global_index(), cell_global_count);
69        cell_global_count += 1;
70    }
71
72    // Get the global indices.
73
74    let global_vertices = grid
75        .local_grid()
76        .entity_iter(ReferenceCellType::Point)
77        .filter(|e| matches!(e.ownership(), Ownership::Owned))
78        .map(|e| e.global_index())
79        .collect::<Vec<_>>();
80
81    let nvertices = global_vertices.len();
82
83    let global_cells = grid
84        .local_grid()
85        .entity_iter(ReferenceCellType::Quadrilateral)
86        .filter(|e| matches!(e.ownership(), Ownership::Owned))
87        .map(|e| e.global_index())
88        .collect::<Vec<_>>();
89
90    let ncells = global_cells.len();
91
92    let mut total_cells: usize = 0;
93    let mut total_vertices: usize = 0;
94
95    comm.all_reduce_into(&ncells, &mut total_cells, SystemOperation::sum());
96    comm.all_reduce_into(&nvertices, &mut total_vertices, SystemOperation::sum());
97
98    assert_eq!(total_cells, (n - 1) * (n - 1));
99    assert_eq!(total_vertices, n * n);
100}
101
102/// Run tests
103fn main() {
104    let universe: Universe = mpi::initialize().unwrap();
105    let comm = universe.world();
106
107    if comm.rank() == 0 {
108        println!("Testing GraphPartitioner::None");
109    }
110    run_test(&comm, GraphPartitioner::None);
111
112    let mut p = vec![];
113    for i in 0..81 {
114        p.push(i % comm.size() as usize);
115    }
116    if comm.rank() == 0 {
117        println!("Testing GraphPartitioner::Manual");
118    }
119    run_test(&comm, GraphPartitioner::Manual(p));
120
121    if comm.rank() == 0 {
122        println!("Testing GraphPartitioner::Coupe");
123    }
124    run_test(&comm, GraphPartitioner::Coupe);
125
126    if comm.rank() == 0 {
127        println!("Testing GraphPartitioner::Scotch");
128    }
129    run_test(&comm, GraphPartitioner::Scotch);
130}