#[cfg(not(feature = "mpi"))]
fn main() {
println!("WARNING: MPI not enabled.");
}
#[cfg(feature = "mpi")]
pub fn main() {
use mpi::traits::Communicator;
use rlst::distributed_tools::{ChunkSizes, GhostCommunicatorBuilder};
let universe = mpi::initialize().unwrap();
let world = universe.world();
let rank = world.rank();
if world.size() != 3 {
println!("Please run this example with 3 MPI ranks.");
return;
}
let ghosts: &[(usize, usize)] = if rank == 0 {
&[(5, 1), (6, 1)]
} else if rank == 1 {
&[(10, 2)]
} else {
&[(5, 1), (0, 0), (1, 0), (2, 0)]
};
let ghost_comm = GhostCommunicatorBuilder::new()
.add_ghosts(ghosts.iter().copied())
.build(&world);
if rank == 2 {
assert_eq!(ghost_comm.receive_indices(), [0, 1, 2, 5]);
}
let data = if rank == 0 {
vec![10, 11, 12]
} else if rank == 1 {
vec![13, 14, 13]
} else {
vec![15]
};
let mut received_data = vec![0; ghost_comm.total_receive_count()];
ghost_comm.forward_send_values(&data, &mut received_data);
if rank == 0 {
assert_eq!(received_data[0], 13);
assert_eq!(received_data[1], 14);
} else if rank == 1 {
assert_eq!(received_data[0], 15);
} else {
assert_eq!(received_data[0], 10);
assert_eq!(received_data[1], 11);
assert_eq!(received_data[2], 12);
assert_eq!(received_data[3], 13);
}
{
use mpi::traits::{Destination, Source};
let row = [
rank.to_string(),
format!("{:?}", ghost_comm.in_ranks()),
format!("{:?}", ghost_comm.out_ranks()),
format!("{:?}", ghost_comm.send_counts()),
format!("{:?}", ghost_comm.receive_counts()),
format!("{:?}", ghost_comm.send_indices()),
format!("{:?}", ghost_comm.receive_indices()),
format!("{:?}", data),
format!("{:?}", received_data),
]
.join("\t");
if rank == 0 {
let mut rows = vec![row];
for other in 1..world.size() {
let (bytes, _) = world.process_at_rank(other).receive_vec::<u8>();
rows.push(String::from_utf8(bytes).unwrap());
}
let header = [
"Rank",
"In ranks",
"Out ranks",
"Send counts",
"Receive counts",
"Send indices",
"Receive indices",
"Sent data",
"Received data",
];
let rows: Vec<Vec<String>> = rows
.iter()
.map(|row| row.split('\t').map(String::from).collect())
.collect();
let widths: Vec<usize> = (0..header.len())
.map(|col| {
rows.iter()
.map(|row| row[col].len())
.chain([header[col].len()])
.max()
.unwrap()
})
.collect();
let format_row = |cells: &[&str]| {
cells
.iter()
.zip(&widths)
.map(|(cell, width)| format!("{cell:<width$}"))
.collect::<Vec<_>>()
.join(" | ")
};
println!("{}", format_row(&header));
println!(
"{}",
widths
.iter()
.map(|width| "-".repeat(*width))
.collect::<Vec<_>>()
.join("-+-")
);
for row in &rows {
let cells: Vec<&str> = row.iter().map(String::as_str).collect();
println!("{}", format_row(&cells));
}
} else {
world.process_at_rank(0).send(row.as_bytes());
}
}
let mut send_data = vec![0; ghost_comm.total_send_count()];
ghost_comm.backward_send_values(&received_data, &mut send_data);
if rank == 0 {
assert_eq!(send_data[0], 10);
assert_eq!(send_data[1], 11);
assert_eq!(send_data[2], 12);
} else if rank == 1 {
assert_eq!(send_data[0], 13);
assert_eq!(send_data[1], 14);
assert_eq!(send_data[2], 13);
} else {
assert_eq!(send_data[0], 15);
}
let chunked_comm = GhostCommunicatorBuilder::new()
.add_ghosts(ghosts.iter().copied())
.chunk_sizes(ChunkSizes::PerIndex(Box::new(|index: usize| index % 3 + 1)))
.build(&world);
let send_buffer = chunked_comm.send_buffer_from_fn(|index, chunk: &mut [usize]| {
for (k, value) in chunk.iter_mut().enumerate() {
*value = 100 * index + k;
}
});
let receive_buffer = send_buffer.forward();
for (index, chunk) in receive_buffer.chunks() {
assert_eq!(chunk.len(), index % 3 + 1);
for (k, &value) in chunk.iter().enumerate() {
assert_eq!(value, 100 * index + k);
}
}
if rank == 2 {
println!(
"Rank 2 received indices {:?} with offsets {:?}: {:?}",
chunked_comm.receive_indices(),
chunked_comm.receive_offsets(),
receive_buffer.as_slice()
);
}
let returned = receive_buffer.backward();
assert_eq!(returned.as_slice(), send_buffer.as_slice());
}